home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / games / volume13 / dominion / part18 / transport.c < prev   
C/C++ Source or Header  |  1992-02-11  |  27KB  |  1,088 lines

  1. /* transport.c -- routines dealing with transportation */
  2.  
  3. /*
  4.  * Copyright (C) 1990 Free Software Foundation, Inc.
  5.  * Written by the dominion project.
  6.  *
  7.  * This file is part of dominion.
  8.  *
  9.  * dominion is free software; you can redistribute it and/or
  10.  * modify it under the terms of the GNU General Public License as published
  11.  * by the Free Software Foundation; either version 1, or (at your option)
  12.  * any later version.
  13.  *
  14.  * This software is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this software; see the file COPYING.  If not, write to
  21.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  */
  23.  
  24. #include "dominion.h"
  25. #include "misc.h"
  26. #include "army.h"
  27. #include "costs.h"
  28. #include "cur_stuff.h"
  29.  
  30. #include <stdio.h>
  31. #include <math.h>
  32.  
  33. extern Suser user;
  34. extern Sworld world;
  35. extern char help_tag[];
  36. extern WINDOW * sectw;
  37. extern struct army_type * army_types;
  38.  
  39.  
  40. /* Main transport functions */
  41. /* int transport ();  /* Coordinates everything (top level) */
  42. /* int transport_load (Sarmy *, WINDOW *); /* Actually loads stuff */
  43. /* int transport_unload (Sarmy *, WINDOW *); /* Unloads stuff */
  44. /* int transport_transfer (Sarmy *, WINDOW *); /* Transfers stuff */
  45.  
  46. /* Cargo weight functions */
  47. /* int army_weight (Sarmy *); /* Figures out an army's manweight */ 
  48. /* int caravan_weight (Sarmy *); /* Figures out a caravan's manweight */
  49. /* int cargo_weight (Scargo *); /* Figures out a cargo's manweight */
  50. /* char * make_cargo_statline (Scargo *); /* Makes a cargo statline */
  51.  
  52.   /* allows you to load/unload cargo from a caravan */
  53. int transport()
  54. {
  55.   WINDOW *tw;
  56.   char type[NAMELEN];
  57.   int ret, size;
  58.   Snation *np = user.np;
  59.   Ssector *sp =  &world.map[user.cursor.x][user.cursor.y];
  60.   Sarmy *ap, *get_army();
  61.   char s[EXECLEN];
  62.   int done = 0;
  63.  
  64.     /* before I make the new window, I should check if the user
  65.        is transporting on a caravan or ship, or if they are transporting
  66.        on something else (like an army or a spirit)
  67.      */
  68.   ap = get_army(np, user.current_army);
  69.   if ( (ap == NULL) || !is_cargo(ap) ) {
  70.     statline2_err ("hit space", "must select a caravan or navy");
  71.     return -1;
  72.   }
  73.   if (user.xmode) {
  74.     tw = NULL;
  75.   } else {
  76.     statline("hit space to exit", "transportation");
  77.     tw = newwin(7, COLS/2+28, LINES-10, COLS/4-14);
  78.   }
  79.  
  80.   while (!done) {
  81.     if (tw != NULL) {
  82.       mvwprintw(tw, 1, 1, "Do you wish to [l]oad, [u]nload or [t]ransfer? ");
  83.       wclrtobot(tw);
  84.       box(tw, '|', '-');
  85.       wrefresh(tw);
  86.     }
  87.     cargo_statline(user.xmode ? NULL : tw, &user);
  88.  
  89.     strcpy(help_tag, "Transportation");
  90.     switch (mygetch()) {
  91.     case 'l':
  92.       if (ap->flags & AF_IN_TRANSPORT) {
  93.     statline2_err ("hit space", "cannot load a caravan in transit");
  94.       }
  95.       else transport_load(ap, user.xmode ? NULL : tw);
  96.       statline2("", "");
  97.       break;
  98.     case 'u':
  99.       if (!cargo_not_empty (&ap->cargo)) {
  100.     statline2_err ("hit space", "cannot unload an empty caravan"); 
  101.       }
  102.       else transport_unload(ap, user.xmode ? NULL : tw);
  103.       statline2("", "");
  104.       break;
  105.     case 't':
  106.       if (!cargo_not_empty (&ap->cargo)) {
  107.     statline2_err ("hit space", "nothing to transfer");
  108.       }
  109.       else transport_transfer(ap, user.xmode ? NULL : tw);
  110.       statline2("", "");
  111.       break;
  112.     case ' ':
  113.       done = 1;
  114.       break;
  115.     default:
  116.       break;
  117.     }
  118.   }
  119.  
  120.   if (tw != NULL) {
  121.     delwin(tw);
  122.     wrefresh (sectw);
  123.     touchwin(stdscr);
  124.   }
  125.   just_moved ();
  126.   return 1;
  127. }
  128.  
  129.   /* load onto a caravan or ship */
  130. transport_load (ap, tw)
  131.      Sarmy *ap;
  132.      WINDOW *tw;
  133. {
  134.   Snation *np = user.np;
  135.   Ssector *sp = &world.map[ap->pos.x][ap->pos.y];
  136.   Sarmy *loaded_army;
  137.   int quantity, done = 0, ret; 
  138.   int doit;
  139.   char c;
  140.   char s[100];
  141.  
  142.   strcpy(help_tag, "Transportation");
  143.  
  144.   while (!done) {
  145.     if (tw != NULL) {
  146.       wmove(tw, 4, 1);
  147.       wclrtobot(tw);
  148.     }
  149.     cargo_statline(tw, &user);
  150.     if (tw != NULL) {
  151.       box(tw, '|', '-');
  152.     }
  153.     if (user.xmode) {
  154.       statline2("  [s,m,j,f,a,p,t]", "load");
  155.     } else {
  156.       wmove (tw, 1, 0);
  157.       wclrtoeol (tw);
  158.       box (tw, '|', '-');
  159.       mvwprintw(tw, 2, 2, "What do you want to load? ");
  160.       mvwprintw(tw, 3, 2,
  161.         " [s]hekels, [m]etal, [j]ewels, [f]ood, [a]rmy, [p]eople, [t]itle ");
  162.       wrefresh(tw);
  163.     }
  164.     do { c = mygetch(); } while (strchr (" smjfapt", c) == NULL);
  165.  
  166.     doit = 1;
  167.     
  168.     /* If anything besides a title or an exit, prompt */
  169.     if (c != ' ' && c != 't') {
  170.       sprintf (s, (c == 'a') ? "(%c) Which army? " : "(%c) Quantity? ", c);
  171.       if (user.xmode) {
  172.     statline2(s, "");
  173.     move(LINES-2, strlen(s));
  174.       } else {
  175.     mvwprintw(tw, 4, 5, s);
  176.       }
  177.       ret = wget_number(user.xmode ? stdscr : tw, &quantity);
  178.       if (ret <= 0) {
  179.     doit = 0;
  180.       }
  181.     }
  182.  
  183.     strcpy (s, "");
  184.  
  185.     if (!good_loading_place (np, sp, c, quantity)) {
  186.       statline2_err ("Can't load that here", "load");
  187.     } else if (load_too_big (np, ap, c, quantity)) {
  188.       statline2_err ("Too much (space)", "load");
  189.     } else if (quantity >= 0 && doit) {
  190.       switch (c) {
  191.       case ' ':
  192.     done = 1;
  193.     break;
  194.       case 's':
  195.     if (quantity <= np->money) {
  196.       ap->cargo.money += quantity;
  197.       np->money -= quantity;
  198.       cmoney (np, -quantity);
  199.     }
  200.     else sprintf (s, "Sorry, not enough in storage (space)");
  201.     break;
  202.       case 'j':
  203.     if (quantity <= np->jewels) {
  204.       ap->cargo.jewels += quantity;
  205.       np->jewels -= quantity;
  206.       cjewels (np, -quantity);
  207.     }
  208.     else sprintf (s, "Sorry, not enough in storage (space)");
  209.     break;
  210.       case 'm':
  211.     if (quantity <= np->metal) {
  212.       ap->cargo.metal += quantity;
  213.       np->metal -= quantity;
  214.       cmetal (np, -quantity);
  215.     }
  216.     else sprintf (s, "Sorry, not enough in storage (space)");
  217.     break;
  218.       case 'f':
  219.     if (quantity <= np->food) {
  220.       ap->cargo.food += quantity;
  221.       np->food -= quantity;
  222.       cfood (np, -quantity);
  223.     }
  224.     else sprintf (s, "Sorry, not enough in storage (space)");
  225.     break;
  226.       case 'a':
  227.     if (ap->cargo.army == -1) {
  228.       if (army_is_in_sector(sp, ap->owner, quantity)) {
  229.         if (ap->id != quantity) {
  230.           ap->cargo.army = quantity;
  231.           loaded_army = get_army (np, quantity);
  232.           loaded_army->flags |= AF_IN_TRANSPORT;
  233.           aflag_set (loaded_army, AF_IN_TRANSPORT);
  234.           show_armies (sp);
  235.         }
  236.         else sprintf(s,"That would be an interesting topological exercise!");      }
  237.       else sprintf (s, "Sorry, can't load across sectors!");
  238.     }
  239.     else sprintf (s, "Sorry, can only transport one army at a time.");
  240.     break;
  241.       case 'p':
  242.     if (quantity <= sp->n_people) {
  243.       ap->cargo.people += quantity;
  244.       sp->n_people -= quantity;
  245.       cpeople_sector (sp, -quantity);
  246.       if (user.xmode) {
  247.         just_moved ();
  248.         show_sector (user.cursor.x, user.cursor.y);
  249.       }
  250.     }
  251.     else sprintf (s, "Sorry, too large a number (space)");
  252.     break;
  253.       case 't':
  254.     if (!has_traded (sp)) {
  255.       if (sp->designation != D_CAPITAL) {
  256.         if (ap->cargo.title.x == -1) {
  257.           sp->flags |= SF_TRADED;
  258.           sprintf (s, "FLAG_SET_SECTOR:%d:%d:%d\n", sp->loc.x, sp->loc.y,
  259.                SF_TRADED);
  260.           gen_exec (s);
  261.           sprintf (s, "");
  262.           ap->cargo.title = sp->loc;
  263.         }
  264.         else sprintf (s, "Sorry, can only load one title per caravan");
  265.       }
  266.       else sprintf (s, "Sorry, but you can't give away your nation...");
  267.     }
  268.     else sprintf (s, "Sector is already traded");
  269.     break;
  270.       }
  271.       if (strlen (s) > 0) {
  272.     statline2_err (s, "load");
  273.       }
  274.       else { adjust_cargo (ap); }
  275.     }
  276.   }
  277. }
  278.  
  279. /* unload from a caravan */
  280. transport_unload(ap, tw)
  281.      Sarmy *ap;
  282.      WINDOW *tw;
  283. {
  284.   Snation *np = user.np;
  285.   Ssector *sp = &world.map[ap->pos.x][ap->pos.y];
  286.   int recip_id;            /* the guy you to whom give the cargo */
  287.   Scargo dropped_cargo;        /* how much you drop */
  288.   char c;
  289.   char s[100];
  290.   int done = 0, ret, quantity, bad_load = 0;
  291.   Sarmy *trans_ap;
  292.  
  293.   /* initialize that nothing is traded */
  294.   dropped_cargo.money = 0;
  295.   dropped_cargo.metal = 0;
  296.   dropped_cargo.jewels = 0;
  297.   dropped_cargo.food = 0;
  298.   dropped_cargo.people = 0;
  299.   dropped_cargo.army = -1;
  300.   dropped_cargo.title.x = -1;
  301.   dropped_cargo.title.y = -1;
  302.  
  303.   trans_ap = get_army(np, ap->cargo.army);
  304.   recip_id = sp->owner;
  305.  
  306.   while (!done) {
  307.     cargo_statline(tw, &user);
  308.     if (tw != NULL) {
  309.       box(tw, '|', '-');
  310.       wrefresh(tw);
  311.     }
  312.     if (tw == NULL) {
  313.       statline2("  [s,m,j,f,p,a,t,*]", "unload");
  314.     } else {
  315.       wmove (tw, 1, 0);
  316.       wclrtoeol (tw);
  317.       box (tw, '|', '-');
  318.       mvwprintw(tw, 2, 2, "What do you want to unload? ");
  319.       mvwprintw(tw, 3, 2,
  320.         "[s]hekels/[m]etal/[j]ewels/[f]ood/[p]eople/[a]rmy/[t]itle/[*]");
  321.       wrefresh (tw);
  322.     }
  323.     do { c = mygetch (); } while (strchr ("*smjaftp ", c) == NULL);
  324.     
  325.     if (!good_unloading_place(np, sp, c, ap->cargo.army)) {
  326.       statline2_err("Cannot unload that here (space)", "");
  327.     }
  328.     else {
  329.       if (c != ' ' && c != 'a' && c != 't' && c != '*') {
  330.     sprintf (s, "(%c) Quantity? ", c);
  331.     if (tw == NULL) {
  332.       statline2 (s, "unload");
  333.       move (LINES-2, strlen(s));
  334.     } else {
  335.       mvwprintw (tw, 4, 7, s);
  336.     }
  337.     ret = wget_number(user.xmode ? stdscr : tw, &quantity);
  338.       }
  339.  
  340.       strcpy (s, "");
  341.  
  342.       /* Actually unload the stuff */
  343.       if (strchr (" at*", c) != NULL || (ret >= 0) ) {
  344.     switch (c) {
  345.     case 's':
  346.       if (quantity <= ap->cargo.money && quantity > 0) {
  347.         ap->cargo.money -= quantity;
  348.         dropped_cargo.money += quantity;
  349.       }
  350.       else sprintf (s, "Invalid number (space)");
  351.       break;
  352.     case 'm':
  353.       if (quantity <= ap->cargo.metal && quantity > 0) {
  354.         ap->cargo.metal -= quantity;
  355.         dropped_cargo.metal += quantity;
  356.       }
  357.       else sprintf (s, "Invalid number (space)");
  358.       break;
  359.     case 'j':
  360.       if (quantity <= ap->cargo.jewels && quantity > 0) {
  361.         ap->cargo.jewels -= quantity;
  362.         dropped_cargo.jewels += quantity;
  363.       }
  364.       else sprintf (s, "Invalid number (space)");
  365.       break;
  366.     case 'f':
  367.       if (quantity <= ap->cargo.food && quantity > 0) {
  368.         ap->cargo.food -= quantity;
  369.         dropped_cargo.food += quantity;
  370.       }
  371.       else sprintf (s, "Invalid number (space)");
  372.       break;
  373.     case 'p':
  374.       if (quantity <= ap->cargo.people && quantity > 0) {
  375.         ap->cargo.people -= quantity;
  376.         dropped_cargo.people += quantity;
  377.       }
  378.       else sprintf (s, "Invalid number (space)");
  379.       break;
  380.     case 't':        /* drop a title to land */
  381.       if (ap->cargo.title.x != -1) {
  382.         dropped_cargo.title = ap->cargo.title;
  383.         ap->cargo.title.x = -1;
  384.         ap->cargo.title.y = -1;
  385.       }
  386.       else sprintf (s, "No sector title loaded (space)");
  387.       break;
  388.     case 'a':
  389.       if (ap->cargo.army >= 0) {
  390.         dropped_cargo.army = ap->cargo.army;
  391.         ap->cargo.army = -1;
  392.       }
  393.       else sprintf (s, "No army loaded (space)");
  394.       break;
  395.     case '*':
  396.       if (ap->cargo.army >= 0) {
  397.         dropped_cargo.army = ap->cargo.army;
  398.         ap->cargo.army = -1;
  399.       }
  400.       dropped_cargo.people = ap->cargo.people;
  401.       ap->cargo.people = 0;
  402.       dropped_cargo.jewels = ap->cargo.jewels;
  403.       ap->cargo.jewels = 0;
  404.       dropped_cargo.metal = ap->cargo.metal;
  405.       ap->cargo.metal = 0;
  406.       dropped_cargo.food = ap->cargo.food;
  407.       ap->cargo.food = 0;
  408.       dropped_cargo.money = ap->cargo.money;
  409.       ap->cargo.money = 0;
  410.       if (ap->cargo.title.x != -1) {
  411.         dropped_cargo.title = ap->cargo.title;
  412.         ap->cargo.title.x = -1;
  413.         ap->cargo.title.y = -1;
  414.       }
  415.       done = 1;
  416.       break;
  417.     case ' ':
  418.       done = 1;
  419.       break;
  420.     default:
  421.       break;
  422.     }
  423.     if (strlen (s) > 0) {
  424.       statline2_err (s, "");
  425.       bad_load = 1;
  426.     }
  427.       }
  428.     }
  429.   }
  430.   if (bad_load == 1) { ; }
  431.   else if (recip_id == user.id) { /* on your land, just put the stuff down */
  432.     np->money += dropped_cargo.money;
  433.     np->metal += dropped_cargo.metal;
  434.     np->jewels += dropped_cargo.jewels;
  435.     np->food += dropped_cargo.food;
  436.     sp->n_people += dropped_cargo.people;
  437.     if (dropped_cargo.title.x != -1) {
  438.       Ssector *traded_sp;
  439.       traded_sp = &world.map[dropped_cargo.title.x][dropped_cargo.title.y];
  440.       traded_sp->flags &= ~SF_TRADED;
  441.         /* now prepare the exec string */
  442.       sprintf(s, "FLAG_CLEAR_SECTOR:%d:%d:%d\n", traded_sp->loc.x,
  443.           traded_sp->loc.y, SF_TRADED);
  444.       gen_exec(s);
  445.     }
  446.     cmoney(np, dropped_cargo.money);
  447.     cmetal(np, dropped_cargo.metal);
  448.     cjewels(np, dropped_cargo.jewels);
  449.     cfood(np, dropped_cargo.food);
  450.     cpeople_sector(sp, dropped_cargo.people);
  451.       /* just drop your army on your own land */
  452.     if (dropped_cargo.army != -1) {
  453.       trans_ap->flags &= ~AF_IN_TRANSPORT;
  454.       aflag_clear(trans_ap, AF_IN_TRANSPORT);
  455.       dropped_cargo.army = -1;
  456.     }
  457.   } 
  458.   else { /* Not in your land */
  459.     if (dropped_cargo.army != -1) { /* Clear army transport flags */
  460.       if (is_front_line (trans_ap) || !(trans_ap->status == A_TRADED)) {
  461.     dropped_cargo.army = -1;    /* don't donate it!! */
  462.       }
  463.       trans_ap->flags &= ~AF_IN_TRANSPORT;
  464.       aflag_clear(trans_ap, AF_IN_TRANSPORT);
  465.     }
  466.     if (cargo_not_empty(&dropped_cargo)) {
  467.       donate_cargo(sp->loc.x, sp->loc.y, user.id, recip_id, &dropped_cargo);
  468.     }
  469.   } 
  470.   adjust_cargo(ap);        /* tell the exec file that cargo is changed */
  471.   if (tw == NULL) { /* Update the sector window */
  472.     just_moved ();
  473.     show_sector (user.cursor.x, user.cursor.y);
  474.   }
  475.   show_armies(sp);
  476. }
  477.  
  478. transport_transfer (ap, tw)
  479. Sarmy * ap;
  480. WINDOW * tw;
  481. {
  482.   Snation *np = user.np;
  483.   Ssector *sp = &world.map [ap->pos.x][ap->pos.y];
  484.   Sarmy * recip;
  485.   int recip_num;
  486.   char c;
  487.   char s [EXECLEN];
  488.   int ret, quantity;
  489.  
  490.   if (tw == NULL) {
  491.     statline2("  [s,m,j,f,p,a,t,*]", "transfer");
  492.   } else {
  493.     wmove (tw, 1, 0);
  494.     wclrtoeol (tw);
  495.     box (tw, '|', '-');
  496.     mvwprintw(tw, 2, 2, "What do you want to transfer? ");
  497.     mvwprintw(tw, 3, 2,
  498.           "[s]hekels/[m]etal/[j]ewels/[f]ood/[p]eople/[a]rmy/[t]itle/[*]");
  499.     wrefresh (tw);
  500.   }
  501.  
  502.   do { c = mygetch (); } while (strchr ("*smjaftp ", c) == NULL);
  503.  
  504.   if (c == ' ') {
  505.     statline2 ("", "");
  506.     return 0; 
  507.   }
  508.  
  509.   if (c != 'a' && c != 't' && c != '*') {
  510.     sprintf (s, "(%c) Quantity? ", c);
  511.     if (tw == NULL) {
  512.       statline2 (s, "transfer");
  513.       move (LINES-2, strlen(s));
  514.     } else {
  515.       mvwprintw (tw, 4, 7, s);
  516.       wrefresh (tw);
  517.     }
  518.     ret = wget_number(user.xmode ? stdscr : tw, &quantity);
  519.     if (ret <= 0 || c == ' ') {
  520.       statline2 ("", "");
  521.       return 0;
  522.     }
  523.   }
  524.  
  525.   sprintf (s, "Transfer to army #? ");
  526.   if (tw == NULL) {
  527.     statline2 (s, "transfer");
  528.     move (LINES-2, strlen (s));
  529.   } else {
  530.     mvwprintw (tw, 4, 7, "Transfer to army #? ");
  531.     wrefresh (tw);
  532.    }
  533.   ret = wget_number(user.xmode ? stdscr : tw, &recip_num);
  534.  
  535.   if (ap->id == recip_num || (recip = get_army (user.np, recip_num)) == NULL) {
  536.     statline2 ("", "");
  537.     return 0;
  538.   }
  539.  
  540.   /* Actually transfer */
  541.   if (strchr ("at*", c) != NULL) {
  542.     if (c == '*') {
  543.       int capacity;
  544.  
  545.       if (ap->cargo.army != -1 && recip->cargo.army != -1) {
  546.     statline2_err ("hit space", "only one army allowed per caravan");
  547.     return 0;
  548.       }
  549.       if (recip->cargo.title.x != -1 && ap->cargo.title.x != -1) {
  550.     statline2_err ("hit space", "only one title allowed per caravan");
  551.     return 0;
  552.       }
  553.       if (is_cargo (recip)) {
  554.     capacity = recip->n_soldiers * CARAVAN_CAPACITY;
  555.       } else capacity = 0;   /* Someone made a booboo */
  556.  
  557.       if ((capacity - cargo_weight (&recip->cargo))
  558.       >= cargo_weight (&ap->cargo)) {
  559.     recip->cargo.money += ap->cargo.money;
  560.     ap->cargo.money = 0;
  561.     recip->cargo.jewels += ap->cargo.jewels;
  562.     ap->cargo.jewels = 0;
  563.     recip->cargo.metal += ap->cargo.metal;
  564.     ap->cargo.metal = 0;
  565.     recip->cargo.food += ap->cargo.food;
  566.     ap->cargo.food = 0;
  567.     recip->cargo.people += ap->cargo.people;
  568.     ap->cargo.people = 0;
  569.     recip->cargo.army = ap->cargo.army;
  570.     ap->cargo.army = -1;
  571.     recip->cargo.title.x = ap->cargo.title.x;
  572.     recip->cargo.title.y = ap->cargo.title.y;
  573.     ap->cargo.title.x = -1;
  574.     ap->cargo.title.y = -1;
  575.       }
  576.       else {
  577.     statline2_err ("hit space", "cargo too big to transfer");
  578.     return 0;
  579.       }
  580.     }
  581.     else {
  582.       if (load_too_big (np, recip, c, quantity)) {
  583.     statline2_err ("hit space", "load too big");
  584.     return (0);
  585.       }
  586.       switch (c) {
  587.       case 'a':
  588.     if (recip->cargo.army != -1) {
  589.       statline2_err ("hit space", "army already loaded");
  590.       return 0;
  591.     }
  592.     recip->cargo.army = ap->cargo.army;
  593.     ap->cargo.army = -1;
  594.     break;
  595.       case 't':
  596.     if (recip->cargo.title.x != -1) {
  597.       statline2_err ("hit space", "title already loaded");
  598.       return 0;
  599.     }
  600.     recip->cargo.title.x = ap->cargo.title.x;
  601.     recip->cargo.title.y = ap->cargo.title.y;
  602.     ap->cargo.title.x = -1;
  603.     ap->cargo.title.y = -1;
  604.     break;
  605.       default:
  606.     break;
  607.       }
  608.     }
  609.   }
  610.   else {
  611.     if (load_too_big (np, recip, c, quantity)) {
  612.       statline2_err("hit space", "load too big");
  613.       return (0);
  614.     }
  615.     switch (c) {
  616.     case 's':
  617.       if (quantity <= ap->cargo.money && quantity > 0) {
  618.     ap->cargo.money -=quantity;
  619.     recip->cargo.money += quantity;
  620.       }
  621.       else statline2_err ("hit space", "Invalid quantity");
  622.       break;
  623.     case 'm':
  624.       if (quantity <= ap->cargo.metal && quantity > 0) {
  625.     ap->cargo.metal -=quantity;
  626.     recip->cargo.metal += quantity;
  627.       }
  628.       else statline2_err ("hit space", "Invalid quantity");
  629.       break;
  630.     case 'j':
  631.       if (quantity <= ap->cargo.jewels && quantity > 0) {
  632.     ap->cargo.jewels -=quantity;
  633.     recip->cargo.jewels += quantity;
  634.       }
  635.       else statline2_err ("hit space", "Invalid quantity");
  636.       break;
  637.     case 'f':
  638.       if (quantity <= ap->cargo.food && quantity > 0) {
  639.     ap->cargo.food -=quantity;
  640.     recip->cargo.food += quantity;
  641.       }
  642.       else statline2_err ("hit space", "Invalid quantity");
  643.       break;
  644.     case 'p':
  645.       if (quantity <= ap->cargo.people && quantity > 0) {
  646.     ap->cargo.people -=quantity;
  647.     recip->cargo.people += quantity;
  648.       }
  649.       else statline2_err ("hit space", "Invalid quantity");
  650.       break;
  651.     default:
  652.       break;
  653.     }
  654.   }
  655.   adjust_cargo (ap);
  656.   adjust_cargo (recip);
  657.   statline2 ("", "");
  658. }
  659.  
  660. #define is_city(sp) (sp->designation == D_CITY || sp->designation == D_CAPITAL)
  661.  
  662. /* you can only load a caravan in certain places */
  663. good_loading_place(np, sp, type, quantity)
  664.      Snation *np;
  665.      Ssector *sp;
  666.      char type;            /* type of cargo */
  667.      int quantity;        /* amount, or army id */
  668. {
  669.   Sarmy *ap, *get_army();
  670.  
  671.   switch (type) {
  672.   case 's':
  673.     if (!(sp->owner == np->id) || !is_city(sp)) {
  674.       return 0;
  675.     }
  676.     break;
  677.   case 'm':
  678.     if (!(sp->owner == np->id) || !(is_city(sp) ||
  679.                  sp->designation == D_METAL_MINE)) {
  680.       return 0;
  681.     }
  682.     break;
  683.   case 'j':
  684.     if (!(sp->owner == np->id) || !(is_city(sp) ||
  685.                     sp->designation == D_JEWEL_MINE)) {
  686.       return 0;
  687.     }
  688.     break;
  689.   case 'f':
  690.     if (!(sp->owner == np->id) || (!(is_city(sp) ||
  691.                     sp->designation == D_FARM))) {
  692.       return 0;
  693.     }
  694.     break;
  695.   case 'p':
  696.      /* you can only load people in your own non-hostile sectors */
  697.     if (!(sp->owner == np->id)|| !(good_altitude(sp, np))||(has_hostile(sp))) {
  698.       return 0;
  699.     }
  700.     break;
  701.   case 't':
  702.       /* you can only load a title in your own land, 
  703.          and if the sector is not traded. */
  704.     if ((sp->owner != np->id) || !(good_altitude(sp, np))) {
  705.       return 0;
  706.     }
  707.     break;
  708.   case 'a':
  709.     if (!(ap = get_army(np, quantity))
  710.     || !(army_is_in_sector(sp, np->id, quantity))
  711.     || ((sp->owner != np->id) && !is_front_line (ap) &&
  712.     sp->designation != D_TRADE_POST)) { 
  713.       return 0;
  714.     }
  715.     break;
  716.   case ' ':            /* this means we don't really load */
  717.     break;
  718.   default:            /* bad type (someone screwed up) */
  719.     return 0;
  720.   }
  721.   return 1;
  722. }
  723.  
  724. /* you can only unload a caravan in certain places */
  725. good_unloading_place(np, sp, type, quantity)
  726.      Snation *np;
  727.      Ssector *sp;
  728.      char type;            /* type of thing being unloaded */
  729.      int quantity;        /* how much, or army id */
  730. {
  731.   Sarmy *ap, *get_army();
  732.  
  733.   switch (type) {
  734.   case 's':
  735.   case 'm':
  736.   case 'j':
  737.   case 'f':
  738.   case 't':
  739.     if ((np->id == sp->owner) || (is_trade_place(sp))) {
  740.       return 1;
  741.     }
  742.     return 0;
  743.   case '*':
  744.     return 1;
  745.   case 'p':
  746.     if ((sp->designation == D_TRADE_POST || sp->owner == np->id)
  747.     && good_altitude(sp, np)) {
  748.       return 1;
  749.     }
  750.     return 0;
  751.   case 'a':
  752.     if (!(ap = get_army(np, quantity))) {
  753.       return 0;
  754.     }
  755.     if (!good_army_altitude(np, sp, ap)) {
  756.       return 0;
  757.     }
  758.     if (sp->owner == np->id) {
  759.       return 1;
  760.     }
  761.     if (is_front_line(ap)) {
  762.       return 1;
  763.     }
  764.     if (sp->designation == D_TRADE_POST) {
  765.       return 1;
  766.     }
  767.     return 0;
  768.   case ' ':
  769.     return 1;
  770.   default:
  771.     return 0;
  772.   }
  773. /*
  774.   if (np->id == 0) {
  775.     return 0;
  776.   }
  777.   if (np->id == sp->owner) {
  778.     return 1;
  779.   }
  780.   if ( (np->id != sp->owner) && (sp->designation == D_TRADE_POST) ) {
  781.     return 1;
  782.   }
  783.   return 0;
  784. */
  785. }
  786.  
  787.  
  788. /* keeps a status line on the transportation window which
  789.    which shows you the cargo on the currently selected army */
  790. cargo_statline(w, up)
  791.      WINDOW *w;
  792.      Suser *up;
  793. {
  794.   char * s;
  795.   Sarmy *ap, *get_army();
  796.   char * make_cargo_statline ();
  797.  
  798.   if ((ap = get_army(up->np, up->current_army)) == NULL) {
  799.     return;
  800.   }
  801.   
  802.   s = make_cargo_statline (&ap->cargo);
  803.  
  804.   if (w) {
  805.     mvwaddstr(w, 5, 2, s);
  806.     wclrtoeol(w);
  807.     box (w, '|', '-');
  808.     wrefresh(w);
  809.   } else {            /* if w is NULL, we are in xmode */
  810.     statline(s, "transp[l,u,t]");
  811.   }
  812. }
  813.  
  814. /* gives cargo from one nation to another */
  815. donate_cargo(x, y, from_id, to_id, cargo)
  816.      int from_id, to_id;
  817.      Scargo *cargo;
  818. {
  819.   Sarmy *ap, *get_army();
  820.   Ssector *sp;
  821.   FILE *fp, *fopen();
  822.   struct argument args[N_EXEC_ARGS];
  823.   char s[NAMELEN];
  824.   int n_people;
  825.  
  826.   while (cargo_is_locked()) {
  827.     sleep(1);
  828.   }
  829.   critical();
  830.   lock_cargo();
  831.   if ((fp = fopen(CARGO_FILE, "a")) == NULL) {
  832.     statline("hit space", "serious error:  cannot append to trade file");
  833.     get_space();
  834.     return;
  835.   }
  836.     /* coordinates of where the trade happened */
  837.   fwrite(&x, sizeof(int), 1, fp);
  838.   fwrite(&y, sizeof(int), 1, fp);
  839.   fwrite(&from_id, sizeof(int), 1, fp);
  840.   fwrite(&to_id, sizeof(int), 1, fp);
  841.   fwrite(cargo, sizeof(Scargo), 1, fp);
  842.     /* handle the donation of an army */
  843.   if ((ap = get_army(user.np, cargo->army)) != NULL) {
  844.     fwrite(ap, sizeof(Sarmy), 1, fp);
  845.     if (!is_spirit (ap)) {
  846.       n_people = ap->n_soldiers;
  847.     }
  848.     else n_people = 0;
  849.     sprintf(s, "ADISBAND:%d\n", ap->id);
  850.     gen_exec(s);
  851.     parse_exec_line(s,args);
  852.     run_exec_line(user.np,args);
  853.     /* Unfortunately, ADISBAND puts the people from the disbanding
  854.        onto the trade sector, thus furnishing some free people ... */
  855.     sp = &world.map[ap->pos.x][ap->pos.y];
  856.     cpeople_sector (sp, -n_people);
  857.     sp->n_people -= n_people;
  858.     delete_army_sector(sp, ap);
  859.     delete_army_nation(user.np, ap);
  860.   }
  861.     /* now handle the donation of a land title */
  862.   sp = &world.map[cargo->title.x][cargo->title.y];
  863.  
  864.   fclose(fp);
  865.   unlock_cargo();
  866.   noncritical();
  867. }
  868.  
  869. /* lock and unlock the cargo data file */
  870. lock_cargo()
  871. {
  872.   FILE *fp, *fopen();
  873.   char fname[NAMELEN];
  874.  
  875.   strcpy(fname, CARGO_FILE);
  876.   strcat(fname, ".LOCK");
  877.  
  878.   if ((fp = fopen(fname, "w")) == NULL)
  879.   {
  880.     fprintf(stderr,"Error: Cannot open lockfile %s\n",CARGO_FILE);
  881.     clean_exit();
  882.     exit(1);
  883.   }
  884. }
  885.  
  886. unlock_cargo()
  887. {
  888.   char fname[NAMELEN];
  889.  
  890.   strcpy(fname, CARGO_FILE);
  891.   strcat(fname, ".LOCK");
  892.  
  893.   unlink(fname);
  894. }
  895.  
  896. /* check if the cargo data file is locked */
  897. cargo_is_locked()
  898. {
  899.   FILE *fp, *fopen();
  900.   char fname[NAMELEN];
  901.  
  902.   strcpy(fname, CARGO_FILE);
  903.   strcat(fname, ".LOCK");
  904.  
  905.   if ((fp = fopen(fname, "r")) == NULL) {
  906.     return 0;
  907.   }
  908.   fclose(fp);
  909.   return 1;
  910. }
  911.  
  912. /* valid trading places are cities, capitals and trade posts */
  913. is_trade_place(sp)
  914.      Ssector *sp;
  915. {
  916.   switch (sp->designation) {
  917.   case D_CAPITAL:
  918.   case D_CITY:
  919.   case D_TRADE_POST:
  920.     return 1;
  921.   default:
  922.     return 0;
  923.   }
  924. }
  925.  
  926. /* returns true if there is a cargo */
  927.  
  928. cargo_not_empty(cargop)
  929.      Scargo *cargop;
  930. {
  931.   if (cargop->money > 0 || cargop->metal > 0 || cargop->jewels > 0
  932.       || cargop->food > 0 || cargop->people > 0 || cargop->army != -1
  933.       || cargop->title.x != -1 || cargop->title.y != -1) {
  934.     return 1;
  935.   }
  936.   return 0;
  937. }
  938.  
  939. /* returns true if we cannot fit this additional load
  940.    onto the ship or caravan. */
  941. load_too_big(np, ap, c, quantity)
  942.      Snation *np;
  943.      Sarmy *ap;            /* the carrier */
  944.      char c;            /* the type of load */
  945.      int quantity;        /* how much */
  946. {
  947.   Sarmy *cargo_ap;
  948.   float capacity, quantity_weight;
  949.  
  950.   if (is_cargo (ap)) {
  951.     capacity = ap->n_soldiers * CARAVAN_CAPACITY;
  952.   } else capacity = 0;   /* Someone made a booboo */
  953.  
  954.   switch (c) {
  955.   case 's':            /* money and other things */
  956.     quantity_weight = quantity * MONEY_WEIGHT;
  957.     break;
  958.   case 'm':
  959.     quantity_weight = quantity * METAL_WEIGHT;
  960.     break;
  961.   case 'j':
  962.     quantity_weight = quantity * JEWEL_WEIGHT;
  963.     break;
  964.   case 'f':
  965.     quantity_weight = quantity * FOOD_WEIGHT;
  966.     break;
  967.   case 'p':
  968.     quantity_weight = quantity;
  969.     break;
  970.   case 'a':
  971.     if (cargo_ap = get_army(np, quantity)) {
  972.       quantity_weight = army_weight (cargo_ap);
  973.     }
  974.     else { quantity_weight = 0; }  /* no army ?!? */
  975.     break;
  976.   case 't':
  977.     quantity_weight = 0;
  978.     break;
  979.   default: /* Someone made a booboo */
  980.     return 0;
  981.   }
  982.   quantity_weight += cargo_weight (&ap->cargo);
  983.  
  984.   if (quantity_weight > capacity) { 
  985.     return 1;
  986.   }
  987.   
  988.   return 0;
  989. }
  990.  
  991. /* Returns the weight of an army, whether normal or a caravan/navy */
  992.  
  993. int army_weight (ap)
  994.  
  995. Sarmy * ap;
  996. {
  997.   int weight, index;
  998.   float weight_per;
  999.  
  1000.   index = army_type_index (ap->type);
  1001.  
  1002.   if (is_cargo(ap)) {
  1003.     weight = caravan_weight (ap);
  1004.   }
  1005.   else if (is_spirit (ap)) {
  1006.     weight = ap->n_soldiers;
  1007.   }
  1008.   else {
  1009.     weight_per = ((float) army_types [index].metal_draft / 100.0) + 
  1010.       ((float) army_types [index].metal_maint / 100) + 1.0;
  1011.     weight = weight_per * ap->n_soldiers;
  1012.   }
  1013.   return weight;
  1014. }
  1015.  
  1016. /* Returns the weight of a caravan, plus any subsidiary cargo */
  1017.  
  1018. int caravan_weight (ap)
  1019.  
  1020. Sarmy * ap;
  1021. {
  1022.   int weight = 0, caravan_index;
  1023.  
  1024.   caravan_index = army_type_index (ap->type);
  1025.  
  1026.   /* Get the weight of the cargo */
  1027.   weight += cargo_weight (&ap->cargo);
  1028.   /* Caravans have 1000 weight (when empty :-) */
  1029.   weight += army_types [caravan_index].metal_draft * ap->n_soldiers;
  1030.  
  1031.   return weight;
  1032. }
  1033.  
  1034. /* Returns the weight of a cargo */
  1035.  
  1036. int cargo_weight (cargo)
  1037.  
  1038. Scargo * cargo;
  1039. {
  1040.   int weight = 0;
  1041.  
  1042.   if (cargo->army >= 0) {
  1043.     weight += army_weight (get_army (user.np, cargo->army));
  1044.   }
  1045.   weight += cargo->people;
  1046.   weight += cargo->jewels * JEWEL_WEIGHT;
  1047.   weight += cargo->metal * METAL_WEIGHT;
  1048.   weight += cargo->food * FOOD_WEIGHT;
  1049.   weight += cargo->money * MONEY_WEIGHT;
  1050.  
  1051.   return weight;
  1052. }
  1053.  
  1054. /* Builds cargo statline out of the cargo struct */
  1055.  
  1056. char * make_cargo_statline (cargo)
  1057.  
  1058. Scargo * cargo;
  1059. {
  1060.   char * rstatline;
  1061.   char tmps [60];
  1062.  
  1063.   if ((rstatline = (char *)malloc (sizeof (char) * 100)) == NULL) {
  1064.     clean_exit();
  1065.     exit (-1);
  1066.   }
  1067.  
  1068.   sprintf (rstatline, "(%d mw)", cargo_weight (cargo));
  1069.  
  1070.   strcat (rstatline, contents (cargo->money, cargo->metal, cargo->jewels,
  1071.                    cargo->food, cargo->people, cargo->army,
  1072.                    &cargo->title, 0));
  1073.  
  1074.   return rstatline;
  1075. }
  1076.  
  1077. /* puts out an exec line describing the new cargo of a caravan */
  1078. adjust_cargo(ap)
  1079.      Sarmy *ap;
  1080. {
  1081.   char s[EXECLEN];
  1082.  
  1083.   sprintf(s, "ACARGO:%d:%d:%d:%d:%d:%d:%d:%d:%d\n", ap->id, ap->cargo.money,
  1084.        ap->cargo.metal, ap->cargo.jewels, ap->cargo.food,
  1085.        ap->cargo.people, ap->cargo.army, ap->cargo.title.x, ap->cargo.title.y);
  1086.   gen_exec(s);
  1087. }
  1088.