home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / games / volume13 / dominion / part01 / army.c next >
C/C++ Source or Header  |  1992-02-11  |  40KB  |  1,559 lines

  1.   /* army.c -- visual army stuff;  see also armylib.c */
  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 "cur_stuff.h"
  28.  
  29. #include <stdio.h>
  30. #ifdef AMIGA
  31. # include <stdlib.h>
  32. #endif
  33.  
  34. extern Sworld world;
  35. extern Suser user;
  36. extern char help_tag[];
  37.  
  38. int legal_move();
  39. Sarmy *get_army();
  40. extern struct army_type *army_types;
  41. extern struct army_flags army_flags [];
  42.  
  43.   /* this shows the armies inside the current sector.
  44.      the info is put in the the main window.
  45.    */
  46. show_armies(sp)
  47.      Ssector *sp;
  48. {
  49.   Sarmy *ap;
  50.   Snation *np;
  51.   struct armyid *alist;
  52.     /* we need to know how many are hidden, for display purposes */
  53.   int i, n_hidden = 0, n_armies;
  54.   char s[NAMELEN];
  55.   char apparent_type[NAMELEN];    /* if an army is disguised */
  56.   int visibility = user.visible_sectors[sp->loc.x][sp->loc.y];
  57.   int n_shown, first_shown = 0, current_index; /* to handle scrolling */
  58.   Sarmy **army_array;
  59.  
  60.   if (user.current_army == -1) {
  61.     user.current_army = first_sect_army(sp);
  62.   }
  63.  
  64.   if (!(visibility & SEE_ARMIES)) {
  65.     user.last_n_armies = 0;
  66.     return;
  67.   }
  68.  
  69.     /* we use this array to store all pointers, because it is useful
  70.        to access the armies as an array for the scrolling display
  71.      */
  72.   alist = sp->alist;
  73.   current_index = 0;
  74.   n_armies = sect_n_armies(sp);
  75.   army_array = (Sarmy **) malloc(n_armies * sizeof(Sarmy *));
  76.   for (i = 0; i < n_armies; ++i) {
  77.     np = &world.nations[alist->owner];
  78.     ap = get_army(np, alist->id);
  79.     army_array[i] = ap;
  80.       /* we want to know which the current army is,
  81.      so that we can highlight it.
  82.        */
  83.     if (ap->id == user.current_army && ap->owner == user.id) {
  84.       current_index = i;
  85.     }
  86.     alist = alist->next;
  87.   }
  88.  
  89.     /* cycle through armies and show them */
  90.   alist = sp->alist;
  91.   n_shown = min(7, n_armies);
  92.   if ((n_armies - current_index) <= n_shown/2) { /* are we near end of list */
  93.     first_shown = n_armies - n_shown;
  94.   } else {
  95.     first_shown = max(current_index-n_shown/2, 0);
  96.   }
  97.   for (i = 0; i < n_shown; ++i) {
  98.     ap = army_array[i+first_shown];
  99.     if ((ap->owner == user.id) && (ap->id == user.current_army)) {
  100.       standout();
  101.     }
  102.     if (ap->owner == user.id || user.id == 0) {    /* your armies */
  103.       if (ap->id == user.current_army) {
  104.     mvprintw(2*(i-n_hidden), ARMYW_X,
  105.          ">%.10s:%d %.8s", world.nations[ap->owner].name,
  106.          ap->n_soldiers, ap->type);
  107.       } else {
  108.     mvprintw(2*(i-n_hidden), ARMYW_X,
  109.          " %.10s:%d %.8s", world.nations[ap->owner].name,
  110.          ap->n_soldiers, ap->type);
  111.       }
  112.       clrtoeol();
  113.     } else if (!is_hidden(ap)) { /* other people's armies */
  114.       get_apparent_type(ap, apparent_type);
  115.       mvprintw(2*(i-n_hidden), ARMYW_X,
  116.            " %.10s:%d %.8s", world.nations[ap->owner].name,
  117.            ap->n_soldiers, apparent_type);
  118.     } else {            /* is hidden */
  119.       ++n_hidden;
  120.     }
  121.     clrtoeol();
  122.       /* we have printed the first army description
  123.      line; now print the other one.
  124.        */
  125.     if (ap->owner == user.id || user.id == 0) {
  126.       get_army_status(ap, s);
  127.       mvprintw(2*(i-n_hidden)+1, ARMYW_X,
  128.            " #%d; mv=%d;%s", ap->id, ap->mvpts, s);
  129.     } else {
  130.       move(2*(i-n_hidden)+1, ARMYW_X);
  131.     }
  132.       /* tricky line;  if it is there it causes this bug
  133.      with hidden armies; I try only clearing if the
  134.      army is not hidden.  that might solve the problem,
  135.      but still cause trouble if the army is hidden and
  136.      belongs to me.  I will test it.
  137.        */
  138.     if (!(is_hidden(ap) && ap->owner != user.id)) {
  139.       clrtoeol();        /* do it for non-enemy hidden armies */
  140.     }
  141.     if ((ap->owner == user.id) && (ap->id == user.current_army)) {
  142.       standend();
  143.     }
  144.     alist = alist->next;
  145.   }
  146.   if (n_shown < user.last_n_armies) {
  147.     for (i = n_armies-n_hidden; i < user.last_n_armies; i++) {
  148.       move(2*i, ARMYW_X);
  149.       clrtoeol();
  150.       move(2*i+1, ARMYW_X);
  151.       clrtoeol();
  152.     }
  153.   }
  154.   user.last_n_armies = n_shown;    /* n_armies - n_hidden; */
  155.   free(army_array);
  156. }
  157.  
  158.   /* this is the general army menu, which allows
  159.      you to choose an army action.
  160.    */
  161. army_menu()
  162. {
  163.   WINDOW *aw;
  164.   int x, y;
  165.   char c;
  166.   int done = 0;
  167.   Ssector *sp;            /* current sector */
  168.   Sarmy *ap;
  169.  
  170.   x = user.cursor.x;
  171.   y = user.cursor.y;
  172.   sp = &world.map[x][y];
  173.  
  174.   if (!user.xmode) {
  175.     aw = newwin(8, COLS-2, LINES-10, 1);
  176.   }
  177.   while (!done) {
  178.     if (user.xmode) {
  179.       statline("(d,D,E,n,p,N,P,m,s,t,l,z,Z,-,+)", "army_menu");
  180.     } else {
  181.       statline("Choose the army action you want (space to exit)", "army_menu");
  182.       mvwaddstr(aw, 1, 1,
  183. "  Choose Army: [n]ext, [p]revious, [N]/[P] (absolute), [j]ump to #");
  184.       mvwaddstr(aw, 2, 1,
  185. " Command Army: [m]ove, change [s]tatus, [t]ransport, [D]isband army");
  186.       mvwaddstr(aw, 3, 1,
  187. "    Army Info: [l]ist available army types,[z]oom,[Z] global zoom,[E]xamine");
  188.       mvwaddstr(aw, 4, 1,
  189. "Army Creation: [d]raft troops, [-]split army, [+]merge armies");
  190.       box(aw, '|', '-');
  191.       wrefresh(aw);
  192.     }
  193.     set_cursor();
  194.     strcpy(help_tag, "Diplomacy and war");
  195.     switch (c = mygetch()) {
  196.     case ' ':
  197.       done = 1;
  198.       break;
  199.     case 'j':
  200.       done = jarmy ();
  201.       break;
  202.     case 'm':
  203.       if (!user.xmode) {
  204.     werase(aw);
  205.     touch_all_wins();
  206.       }
  207.       critical();        /* make sure people don't exit while moving */
  208.       move_army(user.current_army, user.xmode ? NULL : aw);
  209.       noncritical();        /* now they can exit:  move is saved */
  210.       break;
  211.     case 't':            /* allow access to the transp. menu */
  212.       transport();
  213.       break;
  214.     case 'p':
  215.       previous_army();        /* pick the previous army */
  216.       if (user.display == ARMY_MOVECOST) {
  217.     draw_map ();
  218.       }
  219.       break;
  220.     case 'n':
  221.       next_army();        /* pick the next army */
  222.       if (user.display == ARMY_MOVECOST) {
  223.     draw_map ();
  224.       }
  225.       break;
  226.     case 'N':            /* pick the next army, no matter where */
  227.       if (ap=get_army(user.np,next_nation_army(user.np, user.current_army))) {
  228.     user.current_army = ap->id;
  229.     user.cursor = ap->pos;
  230.     just_moved();
  231.     re_center(ap->pos.x, ap->pos.y);
  232.     draw_map();
  233.       } else {
  234.     user.current_army = -1;
  235.       }
  236.       break;
  237.     case 'P':
  238.       if (ap=get_army(user.np,prev_nation_army(user.np, user.current_army))) {
  239.     user.current_army = ap->id;
  240.     user.cursor = ap->pos;
  241.     just_moved();
  242.     re_center(ap->pos.x, ap->pos.y);
  243.     draw_map();
  244.       } else {
  245.     user.current_army = -1;
  246.       }
  247.       break;
  248.     case 's':
  249.       change_army_status(user.xmode ? NULL : aw, user.current_army);
  250.       break;
  251.     case 'd':
  252.       list_available_armies(&user, user.xmode ? NULL : aw);
  253.       draft_army(user.np);
  254.       if (user.current_army == -1) {
  255.         user.current_army = first_sect_army(sp);
  256.       }
  257.       break;
  258.     case 'D':
  259.       if ((ap = get_army(user.np, user.current_army)) == NULL) {
  260.     return 0;
  261.       }
  262.       army_disband (sp, ap);
  263.       break;
  264.     case 'E':
  265.       if ((ap = get_army(user.np, user.current_army)) == NULL) {
  266.     return 0;
  267.       }
  268.       army_examine(ap);
  269.       break;
  270.     case 'l':
  271.         /* if we pass NULL, it means we are in xmode */
  272.       list_available_armies(&user, user.xmode ? NULL : aw);
  273.       get_space();
  274.       break;
  275.     case 'z':
  276.       zoom_armies(&user, sp);
  277.       break;
  278.     case 'Z':
  279.       zoom_armies(&user, NULL);
  280.                      /* with a null pointer for sector... */
  281.       break;
  282.     case '+':
  283.       ap = get_army (user.np, user.current_army);
  284.       if (ap == NULL) {
  285.     break;
  286.       }
  287.       army_merge (ap);
  288.       break;
  289.     case '-':
  290.       ap = get_army (user.np, user.current_army);
  291.       if (ap == NULL) {
  292.     break;
  293.       }
  294.       army_split (ap);
  295.       break;
  296.     default:
  297.       break;
  298.     }
  299.     ap = get_army(user.np,user.current_army);
  300.     if (ap != NULL) {
  301.       sp = &world.map[ap->pos.x][ap->pos.y];
  302.     }
  303.     if (!user.xmode) {
  304.       wmove(aw, 3, 1);
  305.       wclrtobot(aw);
  306.       touchwin(aw);
  307.     }
  308.     statline2("", "");
  309.     show_armies(sp);
  310.     refresh();
  311.   }
  312.   if (!user.xmode) {
  313.     delwin(aw);
  314.     touch_all_wins();
  315.   }
  316. }
  317.  
  318. /* Merge selected army with another army */
  319.  
  320. army_merge (ap)
  321.  
  322. Sarmy * ap;
  323. {
  324.   struct argument args[N_EXEC_ARGS];
  325.   Sarmy * ap2;
  326.   Ssector * sp;
  327.   char stmp [EXECLEN];
  328.   int army_num;
  329.  
  330.   sp = &world.map[user.cursor.x][user.cursor.y];
  331.  
  332.   sprintf (stmp, "Merge army %d into army #? ", ap->id);
  333.   statline2_prompt (stmp, "army_merge");
  334.   if (wget_number (stdscr, &army_num) <= 0) {
  335.     statline2 ("", "");
  336.     return 0;
  337.   }
  338.   ap2 = get_army (user.np, army_num);
  339.   if (ap2 == NULL) {
  340.     statline2 ("", "");
  341.     return 0;
  342.   }
  343.   if (is_in_transport(ap) || is_in_transport (ap2)) {
  344.     statline2_err("Hit space to get back", "Army is in transport");
  345.     statline2 ("", "");
  346.     return 0;
  347.   }
  348.   if (cargo_not_empty(&ap->cargo) || cargo_not_empty (&ap2->cargo)) {
  349.     statline2_err("Hit space to get back", "Army has a cargo");
  350.     statline2 ("", "");
  351.     return 0;
  352.   }
  353.   if (is_spelled(ap) || is_spelled(ap2))
  354.   {
  355.     statline2_err("Hit space to get back", "Army is under a Spell");
  356.     statline2 ("", "");
  357.     return 0;
  358.   }     
  359.   if (ap2->pos.x != sp->loc.x || ap2->pos.y != sp->loc.y ||
  360.       strcmp(ap->type,ap2->type) != 0 || ap == ap2) {
  361.     statline2 ("", "");
  362.     return 0;
  363.   }
  364.   sprintf(stmp, "AMERGE:%d:%d\n", ap->id, ap2->id);
  365.   gen_exec(stmp);
  366.     /* have the exec routine do the work!! */
  367.   parse_exec_line(stmp,args);
  368.   run_exec_line(user.np,args);
  369.     /* make sure there is a current army selected */
  370.   user.current_army = ap2->id;
  371.   return 1;
  372. }
  373.  
  374. army_split (ap)
  375.  
  376. Sarmy * ap;
  377. {
  378.   struct argument args[N_EXEC_ARGS];
  379.   Ssector * sp;
  380.   char stmp [EXECLEN];
  381.   int num_troops;
  382.  
  383.   sp = &world.map[user.cursor.x][user.cursor.y];
  384.  
  385.   sprintf (stmp, "Split how many units from army %d? ", ap->id);
  386.  
  387.   statline2_prompt (stmp, "army_split");
  388.   if (wget_number (stdscr, &num_troops) <= 0) {
  389.     statline2 ("", "");
  390.     return 0;
  391.   }
  392.   if (num_troops < 1 || num_troops > ap->n_soldiers - 1) {
  393.     statline2 ("", "");
  394.     return 0;
  395.   }    
  396.   if (is_in_transport(ap)) {
  397.     statline2_err("Hit space to get back", "Army is in transport");
  398.     statline2 ("", "");
  399.     return 0;
  400.   }
  401.   if (cargo_not_empty(&ap->cargo)) {
  402.     statline2_err("Hit space to get back", "Army has a cargo");
  403.     statline2 ("", "");
  404.     return 0;
  405.   }
  406.   if (is_spirit (ap)) {
  407.     statline2_err ("Hit space to get back", "Cannot split spirits");
  408.     statline2 ("", "");
  409.     return 0;
  410.   }
  411.   if (is_spelled(ap))
  412.   {
  413.     statline2_err("Hit space to get back", "Army is under a Spell");
  414.     statline2 ("", "");
  415.     return 0;
  416.   }     
  417.   sprintf(stmp, "ASPLIT:%d:%d\n", ap->id, num_troops);
  418.   gen_exec(stmp);
  419.     /* have the exec routine do the work!! */
  420.   parse_exec_line(stmp,args);
  421.   run_exec_line(user.np,args);
  422.     /* make sure there is a current army selected */
  423.   return 1;
  424. }
  425.  
  426.   /* allow the user to move an army */
  427. move_army(id,aw)
  428.      int id;
  429.      WINDOW *aw;
  430. {
  431.   int army_move_comment();
  432.     /* army being moved (and cargo if there) */
  433.   Sarmy *ap, *cargo_ap, *get_army();
  434.   Ssector *sp_initial, *sp_final;
  435.   Pt pos;
  436.   char s[EXECLEN];
  437.   int /* mv_initial, */ mv_final;
  438.  
  439.   strcpy(help_tag, "Moving your armies");
  440.  
  441.   ap = get_army(user.np, id);
  442.   if ((ap == NULL) || (ap->id != id)) {
  443.     beep();
  444.     statline("Type space to continue", "No Army Selected");
  445.     get_space();
  446.     return;
  447.   }
  448.   if ((ap->owner != user.id)) {
  449.     beep();
  450.     statline2_err("Type space to continue", "Army not yours");
  451.     return;
  452.   }
  453.   if ((ap->mvpts <= 0)) {
  454.     beep();
  455.     statline2_err("Type space to continue", "No movement left");
  456.     return;
  457.   }
  458.   if (is_in_transport(ap)) {
  459.     beep();
  460.     statline2_err("Type space to continue", "This army is loaded");
  461.     return;
  462.   }
  463.  
  464.     /* remove it from old sector */
  465.   pos = user.cursor;        /* old position */
  466.   sp_initial = &world.map[pos.x][pos.y];
  467.     /* see if there is still something in the list */
  468.     delete_army_sector(sp_initial, ap); /* remove from sector list of armies */
  469.  
  470.     /* now for the guts of it: drag the army along,
  471.        and get new position at the end.
  472.      */
  473.   pos = drag_cursor(ap->pos, DRAG_REL, army_move_comment, legal_move);
  474.   ap->pos = pos;        /* army is in a new place!! */
  475.   mv_final = ap->mvpts;
  476.     /* adding army to new sector */
  477.   sp_final = &world.map[pos.x][pos.y];
  478.   insert_army_sector(sp_final, ap);
  479.     /* put the user's cursor at new position */
  480.   user.cursor = pos;
  481.     /* make the exec line for this army movement */
  482.   sprintf(s, "AMOVE:%d:%d:%d:%d\n",
  483.       ap->id, pos.x, pos.y, mv_final);
  484.   gen_exec(s);
  485.     /* not sure if I should call this here or in insert_army_sector() */
  486.   find_visible_sectors(user.visible_sectors);
  487.   user.current_army = ap->id;
  488.  
  489.     /* now see if we should also move the cargo (recursively) */
  490.   if (is_cargo(ap) && ap->cargo.army >= 0) {
  491.     cargo_ap = ap;
  492.     while (cargo_ap = get_army(user.np, cargo_ap->cargo.army)) {
  493.     delete_army_sector(sp_initial, cargo_ap);
  494.       cargo_ap->pos = sp_final->loc;
  495.       insert_army_sector(sp_final, cargo_ap);
  496.       /* make the exec line for this army movement */
  497.       sprintf(s, "AMOVE:%d:%d:%d:%d\n",
  498.           cargo_ap->id, pos.x, pos.y, cargo_ap->mvpts);
  499.       gen_exec(s);
  500.     }
  501.   }
  502.     /* now some code to allow an army in TRADED mode to
  503.        give itself to the recipient.  this only happens
  504.        on other peoples' trade posts.
  505.      */
  506.   if (ap->status == A_TRADED) donate_army(ap, sp_final);
  507. }
  508.  
  509.   /* run through the armies in a sector and pick the next */
  510. next_army()
  511. {
  512.   int old_id;
  513.   Sarmy *ap = get_army(user.np, user.current_army);
  514.   Ssector *sp = &world.map[user.cursor.x][user.cursor.y];
  515.  
  516.   if ((ap == NULL) || (sp->alist == NULL)) {
  517.     return;
  518.   }
  519.   old_id = ap->id;
  520.  
  521.   if ((user.current_army = next_sect_army(sp, ap)) == -1) {
  522.     user.current_army = old_id;
  523.   }
  524. }
  525.   /* run through the armies in a sector and pick the previous */
  526. previous_army()
  527. {
  528.   Sarmy *ap = get_army(user.np, user.current_army);
  529.   Ssector *sp = &world.map[user.cursor.x][user.cursor.y];
  530.  
  531.   if ((ap == NULL) || (sp->alist == NULL)) {
  532.     return;
  533.   }
  534.  
  535.   if ((user.current_army = prev_sect_army(sp, ap)) == -1) {
  536.     user.current_army = first_sect_army(sp);
  537.   }
  538. }
  539.   /* run through the armies in a nation and pick the next */
  540. next_nation_army(np, old_id)
  541.      Snation *np;
  542.      int old_id;
  543. {
  544.   Sarmy *ap = get_army(np, old_id);
  545.  
  546.   if (np->armies == NULL) {
  547.     return -1;
  548.   }
  549.   if (ap == NULL) {
  550.     return np->armies->id;    /* go to the start */
  551.   }
  552.   if (ap->next == NULL) {    /* we are at the end of the line */
  553.     return old_id;
  554.   }
  555.   return ap->next->id;        /* the next army id!! */
  556. }
  557.   /* run through the armies in a nation and pick the previous */
  558. prev_nation_army(np, old_id)
  559.      Snation *np;
  560.      int old_id;
  561. {
  562.   Sarmy *ap = np->armies;
  563.  
  564.   while (ap) {
  565.     if (ap->next && ap->next->id == old_id) {
  566.       return ap->id;
  567.     }
  568.     ap = ap->next;
  569.   }
  570.   return old_id;
  571. }
  572.  
  573.   /* change the status of the army as it appears in both
  574.      the nation's army list and the sector army list.
  575.    */
  576. change_army_status(aw,id)
  577.      WINDOW *aw;
  578.      int id;            /* army id */
  579. {
  580.   char c;
  581.   Sarmy *ap;
  582.   Ssector *sp = &world.map[user.cursor.x][user.cursor.y];
  583.   char execstr[EXECLEN];
  584.  
  585.   if ((ap = get_army(user.np, id)) == NULL) {
  586.     beep();
  587.     statline("type space to continue", "army not yours");
  588.     get_space();
  589.     return;
  590.   }
  591.  
  592.   if (aw) {
  593.     statline2("Enter your new status.", "change_army_status");
  594.     wmove(aw, 5, 2);
  595.     wclrtoeol(aw);
  596.     mvwprintw(aw, 5, 2, " [a]ttack, [d]efend, [o]ccupy,");
  597.     mvwprintw(aw, 6, 2, " [p]atrol, [i]ntercept, [g]arrison or [t]raded");
  598.     box(aw,'|','-');
  599.     wrefresh(aw);
  600.   } else {
  601.     statline2("[a,d,o,n,p,i,g,t]", "change_army_status");
  602.   }
  603.   switch(c = getch()) {
  604.   case 'a':
  605.     ap->status = A_ATTACK;
  606.     sprintf(execstr, "ASTAT:%d:%d\n", ap->id, ap->status);
  607.     gen_exec(execstr);
  608.     break;
  609.   case 'd':
  610.     ap->status = A_DEFEND;
  611.     sprintf(execstr, "ASTAT:%d:%d\n", ap->id, ap->status);
  612.     gen_exec(execstr);
  613.     break;
  614.   case 'o':
  615.     if (can_occupy(ap)) {
  616.       if (sp->owner != ap->owner) {
  617.     ap->status = A_OCCUPY;
  618.     ap->mvpts = 0;
  619.     sprintf(execstr, "ASTAT:%d:%d\n", ap->id, ap->status);
  620.     gen_exec(execstr);
  621.       } else {
  622.     statline2_err("type space to continue", "cannot occupy your sector!");
  623.       }
  624.     } else {
  625.       statline2("type space to continue", "this army cannot occupy");
  626.       get_space();
  627.     }
  628.     break;
  629.   case 'p':
  630.     if (can_patrol(ap)) {
  631.       ap->status = A_PATROL;
  632.       sprintf(execstr, "ASTAT:%d:%d\n", ap->id, ap->status);
  633.       gen_exec(execstr);
  634.     } else {
  635.       statline2_err("type space to continue", "this army cannot patrol");
  636.     }
  637.     break;
  638.   case 'i':
  639.     if (can_intercept(ap)) {
  640.       ap->status = A_INTERCEPT;
  641.       sprintf(execstr, "ASTAT:%d:%d\n", ap->id, ap->status);
  642.       gen_exec(execstr);
  643.     } else {
  644.       statline2_err("type space to continue", "this army cannot intercept");
  645.     }
  646.     break;
  647.   case 'g':
  648.     if (can_garrison(ap)) {
  649.       ap->status = A_GARRISON;
  650.       sprintf(execstr, "ASTAT:%d:%d\n", ap->id, ap->status);
  651.       gen_exec(execstr);
  652.     } else {
  653.       statline2_err("type space to continue", "this army cannot garrison");
  654.     }
  655.     break;
  656.   case 't':
  657.     ap->status = A_TRADED;
  658.       /* see if the army is ready to be traded */
  659.     if (sp->owner != user.id && sp->designation == D_TRADE_POST) {
  660.       sprintf(execstr, "ASTAT:%d:%d\n", ap->id, ap->status);
  661.       gen_exec(execstr);
  662.       donate_army(ap, sp);
  663.     }
  664.     break;
  665.   default:
  666.     break;
  667.   }
  668.   show_armies(&world.map[user.cursor.x][user.cursor.y]);
  669. }
  670.  
  671.   /* this function is used by move_army() with drag_cursor(),
  672.      and returns 0 if the given point cannot be moved to
  673.      by the given army.
  674.    */
  675. legal_move(pt, np, id)
  676.      Pt pt;
  677.      Snation *np;
  678.      int id;            /* army id */
  679. {
  680.   Sarmy *ap;
  681.   Ssector *sp = &world.map[pt.x][pt.y], *old_sp;
  682.   int cost;
  683.  
  684.   wrap(&pt);
  685.     /* find the army we are moving around */
  686.   ap = get_army(np, id);
  687.  
  688.   /* this is if we want to make it that armies cannot go
  689.      more than 1 step from land that they own.  for now, we
  690.      jack up the move cost instead, so this is commented out.
  691.    */
  692.  
  693.   cost = get_army_move_cost(np, sp, ap);
  694.   if (ap->mvpts < cost) {
  695.     return 0;
  696.   }
  697.  
  698.   ap->pos = pt;
  699.   user.cursor = pt;        /* so the map is drawn right */
  700.   army_visibility(user.visible_sectors, ap); /* update the visibility */
  701.   ap->mvpts -= cost;
  702.   return 1;            /* if we are here, must be a legal move */
  703. }
  704.  
  705.   /* this function returns the status of the army, so it
  706.      can be put in the statline while the army is moved.  it
  707.      will also return a 0 if move points are over, or 1 if
  708.      there are still move points.
  709.    */
  710. army_move_comment(s)
  711.      char *s;
  712. {
  713.   Sarmy *ap = get_army(user.np, user.current_army);
  714.   int cost;
  715.  
  716.   cost = get_army_move_cost(user.np, &world.map[ap->pos.x][ap->pos.y], ap);
  717.  
  718.   sprintf(s, "army %d; move points left: %d; cost %d", ap->id, ap->mvpts,cost);
  719.   return (ap->mvpts > 0) ? 0 : 1;
  720. }
  721.  
  722.   /* draft an army for that nation */
  723. draft_army(np)
  724.      Snation *np;
  725. {
  726.   WINDOW *w;
  727.   int size, ret, i;
  728.   Sarmy army, make_army();    /* the new army!! */
  729.   Ssector *sp = &world.map[user.cursor.x][user.cursor.y];
  730.     /* exec string, army's type and army's name */
  731.   char s[EXECLEN], type[NAMELEN], name[NAMELEN], c;
  732.   extern struct s_desig_map desig_map[];
  733.  
  734.   strcpy(help_tag, "Army types");
  735.  
  736.   if (sp->owner != user.np->id) {
  737.     statline2_err("hit space to continue", "Must be your sector");
  738.     return;
  739.   }
  740. /* Make sure the sector is not hostile */
  741.   if (has_hostile(sp)) {
  742.     statline2_err("hit space to continue", "Cannot draft from hostile sector");
  743.     return;
  744.   }
  745.   
  746.   statline("choose your army/navy/caravan type", "draft_army");
  747.   if (!user.xmode) {
  748.     w = newwin(6, 60, LINES-14, COLS/5);
  749.     mvwprintw(w, 1, 1, "You have %d armies;  first free one is #%d",
  750.           np->n_armies, free_army_id(np));
  751.     mvwprintw(w, 2, 1, "What type of army/navy/caravan do you want? ");
  752.     box(w, '|', '-');
  753.     wrefresh(w);
  754.   }
  755.   noecho();
  756.   cbreak();
  757.   c = getch();
  758.   if (c == '?') {
  759.     online_info();
  760.     return -1;
  761.   } else if (c == ' ') {
  762.     if (!user.xmode) {
  763.       wrefresh(w);
  764.       delwin(w);
  765.       touch_all_wins();
  766.     }
  767.     return -1;
  768.   }
  769.   for(i = 0; i < user.n_army_types; i++) {
  770.     if (army_types[i].type_char == c) {
  771.       strcpy(type, army_types[i].type);
  772.       break;
  773.     }
  774.   }
  775.                 /* While it is still the same army_types... */
  776.   if (!strchr (army_types [i].draft_places, desig_map[sp->designation].mark)) {
  777.     statline2_err ("hit space", "bad place to draft");
  778.     if (!user.xmode) {
  779.       wrefresh (w);
  780.       delwin (w);
  781.     }
  782.     return -1;
  783.   }
  784.   if (!is_avail_army_type(&user, type)) {
  785.     statline2_err("Hit space to get back", "Bad army type");
  786.     if (!user.xmode) {
  787.       wrefresh(w);
  788.       delwin(w);
  789.       touch_all_wins();
  790.     }
  791.     return -1;
  792.   }
  793.   if (!user.xmode) {
  794.     wprintw(w, "%s", type);
  795.   }
  796.  
  797.   strcpy (name, type);
  798.  
  799.   if (user.xmode) {
  800.     sprintf(s, "(default: %s): ", name);
  801.     statline2_prompt(s, "Name your army");
  802.     ret = wget_name(stdscr, name);
  803.   } else {
  804.     mvwprintw(w, 3, 1, "Name your army (default: %s):  ", name);
  805.     ret = wget_name(w, name);
  806.   }
  807.     /* if they just type return, use the default name */
  808.   if (ret <= 0) {
  809.     sprintf(name, "%s", type, free_army_id(np));
  810.   }
  811.  
  812.   if (user.xmode) {
  813.     statline("", "How many units?");
  814.     move(LINES-1, 0);
  815.     ret = wget_number(stdscr, &size);
  816.   } else {
  817.     mvwprintw(w, 4, 1, "How many units do you want? ");
  818.     box(w, '|', '-');
  819.     ret = wget_number(w, &size);
  820.   }
  821.   if ((ret <= 0) || (size <= 0)) {
  822.     if (!user.xmode) {
  823.       wrefresh(w);
  824.       delwin(w);
  825.       touch_all_wins();
  826.     }
  827.     return -1;
  828.   }
  829.   army = make_army(type, name, size, A_DEFEND, np->id, sp->loc);
  830.   army.id = free_army_id(np);
  831.   army.next = NULL;
  832.     /* now see if we can afford the army */
  833.   if (army.n_soldiers
  834.       > (sp->n_people - desig_map[sp->designation].min_employed)) {
  835.     beep();
  836.     statline2("space to go on", "not enough people in sector");
  837.     get_space();
  838.     if (!user.xmode) {
  839.       wrefresh(w);
  840.       delwin(w);
  841.       touch_all_wins();
  842.     }
  843.     return -1;
  844.   }
  845.   if (army_cost(&army) > user.np->money) {
  846.     beep();
  847.     statline2("space to go on", "not enough money to draft");
  848.     get_space();
  849.     if (!user.xmode) {
  850.       wrefresh(w);
  851.       delwin(w);
  852.       touch_all_wins();
  853.     }
  854.     return -1;
  855.   }
  856.   if (army_cost_metal(&army) > user.np->metal) {
  857.     beep();
  858.     statline2("space to go on", "not enough metal to draft");
  859.     get_space();
  860.     if (!user.xmode) {
  861.       wrefresh(w);
  862.       delwin(w);
  863.       touch_all_wins();
  864.     }
  865.     return -1;
  866.   }
  867.  
  868.     /* well, if we have reached this point, it means that we
  869.        can afford this army, so let us insert it into the lists
  870.      */
  871.   np->n_armies++;
  872.   if (np->armies == NULL) {    /* special case:  empty list */
  873.     np->armies = (Sarmy *) malloc(sizeof(Sarmy));
  874.     *(np->armies) = army;
  875.     np->armies->next = NULL;
  876.   } else {
  877.     insert_army_nation(np, &army, -1);
  878.   }
  879.   insert_army_sector(sp, &army);
  880.   sp->n_people -= army.n_soldiers;
  881.   np->money -= army_cost(&army);
  882.   np->metal -= army_cost_metal(&army);
  883.     /* now prepare the exec string for making the army and costs */
  884.   sprintf(s, "AMAKE:%d:%d:%d:%d:%s:%s\n", army.id, army.n_soldiers,
  885.       army.pos.x, army.pos.y, army.type, army.name);
  886.   gen_exec(s);
  887.   cpeople_sector(sp, -army.n_soldiers);
  888.   cmoney(np, -army_cost(&army));
  889.   cmetal(np, -army_cost_metal(&army));
  890.  
  891.   show_armies(sp);
  892.  
  893.   if (!user.xmode) {
  894.     wrefresh(w);
  895.     delwin(w);
  896.     touch_all_wins();
  897.   }
  898.   just_moved();
  899.   return 1;
  900. }
  901.  
  902.   /* get the first army in that sector that belongs to you */
  903. first_sect_army(sp)
  904.      Ssector *sp;
  905. {
  906.   int id = -1;            /* default:  no army selected */
  907.   struct armyid *alist = sp->alist;
  908.   char s[100];
  909.  
  910.   while (alist != NULL) {
  911.     if (alist->owner == user.id) {
  912. /* this routine sometimes messes up */
  913.       id = alist->id;
  914.       break;
  915.     }
  916.     alist = alist->next;
  917.   }
  918.  
  919.   return id;
  920. }
  921.  
  922.   /* takes a sector, an army (possibly in that sector), and
  923.      returns the id of the next army you own in that sector,
  924.      or -1 if you don't have any more
  925.    */
  926. next_sect_army(sp, ap)
  927.      Ssector *sp;
  928.      Sarmy *ap;
  929. {
  930.   struct armyid *alist = sp->alist;
  931.   char s[100];
  932.  
  933.   if (ap == NULL) {        /* in case the army given was bogus */
  934.     return first_sect_army(sp);
  935.   }
  936.  
  937.     /* first get up to the given army */
  938.   while ((alist != NULL) &&
  939.      !((alist->id == ap->id) && (alist->owner == ap->owner))) {
  940.     alist = alist->next;
  941.   }
  942. /*  if (alist->next == NULL) {    /* we are at the end of the list */
  943. /*    return -1;
  944.   }
  945. */
  946.  
  947.   if ((alist == NULL) || (alist = alist->next) == NULL) {
  948.     return -1;
  949.   }
  950.     /* now look for the next army owned by the current user */
  951.   while ((alist != NULL) && (alist->owner != ap->owner)) {
  952.     alist = alist->next;
  953.   }
  954.   if (alist == NULL) {
  955.     return -1;
  956.   }
  957.   return alist->id;        /* in this case, we have a valid next army */
  958. }
  959.  
  960.   /* takes a sector, an army (should be in that sector), and
  961.      returns the id of the previous army you own in that sector,
  962.      or -1 if you don't have any more.
  963.    */
  964. prev_sect_army(sp, ap)
  965.      Ssector *sp;
  966.      Sarmy *ap;
  967. {
  968.   struct armyid *alist = sp->alist, *previous = sp->alist;
  969.   previous = NULL;
  970.  
  971.   if ((ap == NULL) || (alist == NULL)) {
  972.     return first_sect_army(sp);
  973.   }
  974.     /* now get up to the given army */
  975.   while ((alist != NULL) &&
  976.      !((alist->owner == ap->owner) && (alist->id == ap->id))) {
  977.     if (alist->owner == ap->owner) {
  978.       previous = alist;
  979.     }
  980.     alist = alist->next;
  981.   }
  982.  
  983.   return (previous == NULL) ? -1 : previous->id;
  984. }
  985.  
  986.   /* gives a list of army types available to this user */
  987. list_available_armies(up, aw)
  988.      Suser *up;
  989.      WINDOW *aw;        /* army window */
  990. {
  991.   int i, count = 0;
  992.   Savail_army *avail_armies = up->avail_armies;
  993.   char s[200];
  994.  
  995.   strcpy(s, " ");
  996.   if (aw) {
  997.     wmove(aw, 1, 1);
  998.     wclrtobot(aw);
  999.     mvwprintw(aw, 1, 20, "AVAILABLE ARMIES");
  1000.     wmove(aw, 2, 1);
  1001.   }
  1002.   while (avail_armies != NULL) {
  1003.     if ((i = army_type_index(avail_armies->type)) >= 0) {
  1004.       if (aw) {
  1005.     wprintw(aw, " %s(%c) ", army_types[i].type, army_types[i].type_char);
  1006.       } else {
  1007.     sprintf(s, "%s%c ", s, army_types[i].type_char);
  1008.       }
  1009.       if (aw && avail_armies->next != NULL) {
  1010.     waddstr(aw, ",");
  1011.       }
  1012.       if (aw) { wclrtoeol(aw); }
  1013.       ++count;
  1014.       if (aw && (count % 5) == 0) { /* new line */
  1015.     wmove(aw, 2+count/5, 1);
  1016.       }
  1017.     }
  1018.     avail_armies = avail_armies->next;
  1019.   }
  1020.   if (aw) {
  1021.     box(aw, '|', '-');
  1022.     wrefresh(aw);
  1023.     statline2("Type space to get back", "list_available_armies");
  1024.   } else {
  1025.     statline2(s, "list_available_armies");
  1026.   }
  1027. }
  1028.  
  1029.  
  1030. army_disband(sp, ap)
  1031.  
  1032. Ssector *sp;
  1033. Sarmy * ap;
  1034. {
  1035.   int army_num, done, index, metal_return;
  1036.   Snation *np = user.np;
  1037.   char s[EXECLEN], c;
  1038.   struct argument args[N_EXEC_ARGS];
  1039.  
  1040.   if (sp->owner != np->id) {
  1041.     statline2_err("Hit space to get back", "You don't own sector");
  1042.     return 0;
  1043.   }
  1044.  
  1045.   if (is_in_transport(ap)) {
  1046.     statline2_err("Hit space to get back", "Army is in transport");
  1047.     return 0;
  1048.   }
  1049.   if (is_cargo(ap) && cargo_not_empty(&ap->cargo)) {
  1050.     statline2_err("Hit space to get back", "Caravan has stuff loaded");
  1051.     return 0;
  1052.   }
  1053.   if (is_spelled(ap)) {
  1054.     statline2_err("Hit space to get back", "Army under a spell");
  1055.     return 0;
  1056.   }
  1057.   sprintf (s, "Disband army %d.  Are you sure? ", ap->id);
  1058.   statline2_prompt (s, "army_disband");
  1059.  
  1060.   switch (c = getch()) {
  1061.   case 'Y':
  1062.   case 'y':
  1063.     sprintf(s, "ADISBAND:%d\n", ap->id);
  1064.     index = army_type_index (ap->type);
  1065.     if (index != -1) {  /* If it's not a spirit */
  1066.       metal_return = (army_types [index].metal_draft * ap->n_soldiers) *
  1067.     DISBAND_RETURN;
  1068.       np->metal +=metal_return;
  1069.       cmetal (np, metal_return);
  1070.     }
  1071.  
  1072.     gen_exec(s);
  1073.     parse_exec_line(s,args);
  1074.     run_exec_line(np,args);
  1075.     break;
  1076.   case 'N': case 'n':
  1077.   default: 
  1078.     break;
  1079.   }
  1080.  
  1081.   if (get_army(user.np, user.current_army) == NULL) {
  1082.     user.current_army = first_sect_army(sp);
  1083.   }
  1084.   just_moved ();
  1085. }
  1086.  
  1087.   /* give a name to an army */
  1088. army_name (ap)
  1089.      Sarmy * ap;
  1090. {
  1091.   char name[NAMELEN], s[EXECLEN];
  1092.   int ret;
  1093.  
  1094.   statline2_prompt ("Give army name: ", "");
  1095.   ret = wget_name(stdscr, name);
  1096.   if (ret > 0) {
  1097.     strcpy(ap->name, name);
  1098.       /* now generate the exec instruction */
  1099.     sprintf(s, "ANAME:%d:%s\n", ap->id, ap->name);
  1100.     gen_exec(s);
  1101.   }
  1102.   noecho();
  1103.   cbreak();
  1104. }
  1105.  
  1106.   /* give a detailed description of all armies in a nation,
  1107.      or just those in the "current_sp".
  1108.    */
  1109. zoom_armies(up, sp)
  1110.      
  1111. Suser *up;
  1112. Ssector *sp;
  1113. {
  1114.   WINDOW *azlw, * azmw;
  1115.   Sarmy * armies;
  1116.   int army_count, maxlen_win;
  1117.   int num_shown;
  1118.   int show_cargo = 0;
  1119.   int done = 0;
  1120.   int page = 1;
  1121.   int maxpage;
  1122.  
  1123.   armies = up->np->armies;
  1124.   army_count = 0;
  1125.  
  1126.   while (armies != NULL) {    /* Count the number of armies to be shown  */
  1127.     if (sp != NULL) {
  1128.       if (armies->pos.x == sp->loc.x
  1129.           && armies->pos.y == sp->loc.y) {
  1130.     army_count ++;
  1131.       }
  1132.     } else {
  1133.       army_count++;
  1134.     }
  1135.     armies = armies->next;
  1136.   }
  1137.  
  1138.   if (army_count == 0) {
  1139.     return 0;
  1140.   }
  1141.  
  1142.   maxlen_win = LINES - 3;
  1143.   if (!user.xmode) {        /* Allow for the non-expert menu */
  1144.     maxlen_win -= 4;
  1145.   }
  1146.  
  1147.   if (army_count <= maxlen_win - 4) { /* Don't use the entire window len? */
  1148.     maxlen_win = army_count + 4;
  1149.     num_shown = army_count;
  1150.     if (user.xmode) {
  1151.       azlw = newwin (maxlen_win, COLS, LINES - (2 + maxlen_win), 0);
  1152.     }
  1153.     else {
  1154.       azlw = newwin (maxlen_win, COLS, LINES - (2 + 4 + maxlen_win), 0);
  1155.     }
  1156.   }
  1157.   else {
  1158.     num_shown = maxlen_win - 4;
  1159.     azlw = newwin (maxlen_win, COLS, 1, 0);
  1160.   }
  1161.   maxpage = army_count / (maxlen_win - 4); 
  1162.   maxpage ++;
  1163.   
  1164.   box (azlw, '|', '-');
  1165.  
  1166.   mvwprintw (azlw, 1, 1, 
  1167. " ID Name       Size Type        Status  Bonus       ");
  1168.   mvwprintw (azlw, 1, 47, "%s", show_cargo ? "Cargo" : "Maint");
  1169.   mvwprintw (azlw, 2, 1, 
  1170. "--- ---------  ---- ----------- ------- ----  ------------------------------");
  1171.  
  1172.  
  1173.   while (!done) {
  1174.     char c;
  1175.     int i;
  1176.     char s [EXECLEN];
  1177.     Sarmy * ap;
  1178.     Ssector * sp2;
  1179.     
  1180.     sp2 = &world.map[user.cursor.x][user.cursor.y];
  1181.  
  1182.     statline2 ("", "");
  1183.     for (i = 3; i < maxlen_win - 1; i++) {
  1184.       wmove (azlw, i, 0);
  1185.       wclrtoeol (azlw);
  1186.     }
  1187.     if (user.xmode) {
  1188.       azmw = NULL;
  1189.       statline ("[>,<,c,D,E,N,+,-]", "zoom_armies");
  1190.     } else {
  1191.       azmw = newwin (4, COLS, LINES - 6, 0);
  1192.       box (azmw, '|', '-');
  1193.       mvwprintw(azmw, 1, 1,
  1194.         " [>]/[.]next pg, [<]/[,]prev pg,[N]ame army, [c] examine %s ",
  1195.         show_cargo ? "costs" : "cargo");
  1196.       mvwprintw(azmw, 2, 1,
  1197.     " [D]isband army, [-]split army, [+]merge army [E]xamine army");
  1198.       statline ("Choose zoom_army command (space to exit)", "zoom_armies");
  1199.       wrefresh (azmw);
  1200.     }
  1201.  
  1202.     box (azlw, '|', '-');
  1203.     zoom_army_page (azlw, up->np->armies, sp, page,maxlen_win-4, show_cargo);
  1204.  
  1205.     do { c = getch (); } while (strchr (" <>.,NcD-+E", c) == NULL);
  1206.  
  1207.     switch (c) {
  1208.     case ' ':
  1209.       done = 1;
  1210.       break;
  1211.     case 'c':
  1212.       show_cargo = !show_cargo;
  1213.       mvwprintw (azlw, 1, 47, "%s", show_cargo ? "Cargo" : "Maint");
  1214.       wrefresh (azlw);
  1215.       if (azmw) {
  1216.     mvwprintw(azmw, 1, 1,
  1217.       " [>]/[.]next pg, [<]/[,]prev pg,[N]ame army, [c] examine %s ",
  1218.           show_cargo ? "costs" : "cargo");
  1219.     wrefresh (azmw);
  1220.       }
  1221.       break;
  1222.     case '>':
  1223.     case '.':
  1224.       if (page != maxpage) {
  1225.     page ++;
  1226.       }
  1227.       break;
  1228.     case '<':
  1229.     case ',':
  1230.       if (page != 1) {
  1231.     page --;
  1232.       }
  1233.       break;
  1234.     case 'N':
  1235.       statline2_prompt ("Name army #", "army_name"); 
  1236.       if (((wget_number (stdscr, &i)) <= 0) || 
  1237.     ((ap  = get_army (user.np, i)) == NULL)) {
  1238.     break;
  1239.       }
  1240.       army_name (ap);
  1241.       break;
  1242.     case 'E':
  1243.       statline2_prompt ("Examine army #", "army_examine"); 
  1244.       if (((wget_number (stdscr, &i)) <= 0) || 
  1245.     ((ap  = get_army (user.np, i)) == NULL)) {
  1246.     break;
  1247.       }
  1248.       army_examine(ap);
  1249.       break;
  1250.     case 'D':
  1251.       statline2_prompt ("Disband army #", "army_disband"); 
  1252.       if (((wget_number (stdscr, &i)) <= 0) || 
  1253.     ((ap  = get_army (user.np, i)) == NULL)) {
  1254.     break;
  1255.       }
  1256.       army_disband (sp2, ap);
  1257.       break;
  1258.     case '-':
  1259.       statline2_prompt ("Split army #", "army_split"); 
  1260.       if (((wget_number (stdscr, &i)) <= 0) || 
  1261.     ((ap  = get_army (user.np, i)) == NULL)) {
  1262.     break;
  1263.       }
  1264.       army_split (ap);
  1265.       break;
  1266.     case '+':
  1267.       statline2_prompt ("Merge army #", "army_merge"); 
  1268.       if (((wget_number (stdscr, &i)) <= 0) || 
  1269.     ((ap  = get_army (user.np, i)) == NULL)) {
  1270.     break;
  1271.       }
  1272.       army_merge (ap);
  1273.       break;
  1274.     }
  1275.   }
  1276.  
  1277.   if (azmw) { delwin(azmw); }
  1278.   delwin(azlw);
  1279.   touch_all_wins();
  1280.   return 0;
  1281. }
  1282.  
  1283. /* This function is used by zoom_armies to select the page of armies you want*/
  1284.  
  1285. zoom_army_page (azlw, armies, sp, page, len_page, show_cargo)
  1286.  
  1287. WINDOW * azlw;
  1288. Sarmy * armies;
  1289. Ssector * sp;
  1290. int page, len_page, show_cargo;
  1291. {
  1292.   int army_count, i;
  1293.   Sarmy * ap = armies;
  1294.  
  1295.   while (ap != NULL) {
  1296.     if (sp != NULL) {
  1297.       if (sp->loc.x == ap->pos.x && sp->loc.y == ap->pos.y) {
  1298.     army_count ++;
  1299.       }
  1300.     }
  1301.     else {
  1302.       army_count ++;
  1303.     }
  1304.     ap = ap->next;
  1305.   }
  1306.  
  1307.   if (army_count <= len_page) {
  1308.     zoom_list_armies (azlw, armies, sp, 0, len_page, show_cargo);
  1309.     return 0;
  1310.   }
  1311.   if ((page - 2) * len_page > army_count) {    /* Too high a page number */
  1312.     return 1;
  1313.   }
  1314.   ap = armies;
  1315.  
  1316.   for (i=0; i < (page-1) * len_page; i++) {
  1317.     ap = ap->next;
  1318.   }
  1319.   if (ap != NULL) {
  1320.     zoom_list_armies (azlw, armies, sp, ap->id, len_page, show_cargo);
  1321.   }
  1322.   return 0;
  1323. }
  1324.  
  1325. /* This function is used by zoom_armies to list armies in the azlw win */
  1326.  
  1327. zoom_list_armies (azlw, armies, sp, start_army, len_win, cargo)
  1328.  
  1329. WINDOW * azlw;
  1330. Sarmy * armies;
  1331. Ssector * sp;
  1332. int start_army;            /* Starting army number */
  1333. int len_win;            /* Number of army lines allowed in window */
  1334. int cargo;            /* Cargo mode? */
  1335. {
  1336.   int army_count;
  1337.   int row;
  1338.   char * slash_pos;
  1339.   Scargo * snails;        /* Sorry for the pun :-) */
  1340.   char * contents ();        /* Returns string of stuff, nicely formatted */
  1341.   char s [EXECLEN];
  1342.   char zooms [EXECLEN];
  1343.  
  1344.   while (armies != NULL) {    /* Get to the starting army number */
  1345.     if (armies->id >= start_army) { /* In case it doesn't actually exist... */
  1346.       break;
  1347.     }
  1348.     armies = armies->next;
  1349.   }
  1350.  
  1351.   if (sp != NULL) {        /* If not zoom ALL armies, */
  1352.     do {            /* Check that the first army is on sector */
  1353.       if (armies->pos.x == sp->loc.x && armies->pos.y == sp->loc.y) {
  1354.     break;
  1355.       }
  1356.       armies = armies->next;
  1357.     } while (armies != NULL);
  1358.   }
  1359.  
  1360.   /* Now display the armies */
  1361.  
  1362.   row = 3;
  1363.   while (armies != NULL && row-3 < len_win) {
  1364.     mvwprintw(azlw, row,  1, "%3d    ", armies->id);
  1365.     mvwprintw(azlw, row,  5, "%s                   ", armies->name);
  1366.     mvwprintw(azlw, row, 16, "%4d  ", armies->n_soldiers);
  1367.     mvwprintw(azlw, row, 21, "%s           ", armies->type);
  1368.     get_army_status(armies, s);
  1369.     slash_pos = (char *) strchr (s, (int) '/');
  1370.     if (slash_pos != NULL) {
  1371.       *slash_pos = '\0';
  1372.     }
  1373.     mvwprintw(azlw, row, 33, "%s     ", s);
  1374.     mvwprintw(azlw, row, 42, "%3d    ", armies->sp_bonus);
  1375.  
  1376.     strcpy (zooms, "");
  1377.     if (cargo) {
  1378.       if (!is_cargo (armies)) {
  1379.     sprintf (zooms, "   not a transport");
  1380.       }
  1381.       else {
  1382.     snails = &armies->cargo;
  1383.     sprintf (zooms, "%s", 
  1384.          contents (snails->money, snails->metal, snails->jewels,
  1385.                snails->food, snails->people, snails->army,
  1386.                &snails->title, 0));
  1387.       }
  1388.     }
  1389.     else {
  1390.       sprintf (zooms, "%s",
  1391.            contents (armies->money_maint * armies->n_soldiers,
  1392.              armies->metal_maint * armies->n_soldiers,
  1393.              armies->jewel_maint * armies->n_soldiers, 0,
  1394.              0, -1, NULL, get_spell_pts_maint (armies))); 
  1395.     }
  1396.  
  1397.     mvwprintw(azlw, row, 47, zooms);
  1398.  
  1399.     armies = armies->next;
  1400.     if (sp != NULL && armies) {    /* Again, check if we want to discriminate...*/
  1401.       do {
  1402.     if (armies->pos.x == sp->loc.x && armies->pos.y == sp->loc.y) {
  1403.       break;
  1404.     }
  1405.     armies = armies->next;
  1406.       } while (armies != NULL);
  1407.     }
  1408.     row ++;
  1409.   }
  1410.   wrefresh (azlw);
  1411. }
  1412.  
  1413.     /* now some code to allow an army in TRADED mode to
  1414.        give itself to the recipient.  this only happens
  1415.        on other peoples' trade posts.
  1416.      */
  1417. donate_army(ap, sp)
  1418.      Sarmy *ap;
  1419.      Ssector *sp;
  1420. {
  1421.   if (is_cargo (ap) && cargo_not_empty (&ap->cargo)) {
  1422.     statline2_err ("Error: transport still has a cargo", "donate_army");
  1423.   } 
  1424.   else if (ap->flags & AF_IN_TRANSPORT) {
  1425.     statline2_err ("Error: army is still in transport", "donate_army");
  1426.   }
  1427.   else if ((ap->status == A_TRADED) && (sp->designation == D_TRADE_POST)
  1428.       && (sp->owner !=  user.np->id)) {
  1429.     statline2("Do you want to trade this army right here [y/n]? ", "");
  1430.     switch (getch()) {
  1431.       Scargo cargo;
  1432.     case 'y':
  1433.     case 'Y':
  1434.       cargo.money = cargo.metal = cargo.jewels = cargo.food = 0;
  1435.       cargo.people = 0;
  1436.       cargo.army = ap->id;
  1437.       cargo.title.x = -1;
  1438.       cargo.title.y = -1;
  1439.       donate_cargo(sp->loc.x, sp->loc.y,
  1440.            user.np->id, sp->owner, &cargo);
  1441.       break;
  1442.     default:
  1443.       break;
  1444.     }
  1445.   }
  1446. }
  1447.  
  1448. extern int (*wrapx)(), (*wrapy)();
  1449.  
  1450. int jarmy ()
  1451. {
  1452.   char s[100];
  1453.   int army_num;
  1454.   Sarmy * ap;
  1455.   int x, y;
  1456.  
  1457.   ap = user.np->armies;
  1458.  
  1459.   statline2 ("Army number to jump to? ", "jump_army");
  1460.   move (LINES-2, 25);
  1461.   refresh ();
  1462.   if (wget_number(stdscr, &army_num) < 1) {
  1463.     statline2("", "");
  1464.     return;
  1465.   }
  1466.  
  1467.   while (ap != NULL) {
  1468.     if (ap->id == army_num) {
  1469.       break;
  1470.     }
  1471.     ap = ap->next;
  1472.   }
  1473.  
  1474.   if (ap == NULL) {
  1475.     statline2_err ("Hit space to continue", "army does not exist");
  1476.     return 0;
  1477.   }
  1478.   if (ap->id == army_num) {
  1479.     x = ap->pos.x;
  1480.     y = ap->pos.y;
  1481.     user.cursor.x = (*wrapx)(x,y);
  1482.     user.cursor.y = (*wrapy)(x,y);
  1483.     user.center = user.cursor;
  1484.     user.current_army = ap->id;
  1485.     just_moved();
  1486.   }
  1487.   statline2("", "");
  1488.   return 1;
  1489. }
  1490.  
  1491. army_examine(ap)
  1492.      Sarmy * ap;
  1493. {
  1494.   WINDOW * flagw, * infow;
  1495.   char s [NAMELEN], * slash_pos;
  1496.   int n_flags = 0;
  1497.   int i, rowpos;
  1498.   char * flags [20];
  1499.   Snation * np = &world.nations [ap->owner];
  1500.  
  1501.   infow = newwin (9, 32, 0, 0);
  1502.   box (infow, '|', '-');
  1503.  
  1504.   get_army_status (ap, s);
  1505.  
  1506.   slash_pos = (char *)strchr (s, (int)'/');
  1507.   n_flags = 0;
  1508.   if (slash_pos != NULL) {
  1509.     n_flags = strlen(slash_pos) - 1;
  1510.     *slash_pos = '\0';
  1511.   }
  1512.  
  1513.   mvwprintw (infow, 1, 2, "Name: %8s (#%d)", ap->name, ap->id);
  1514.   mvwprintw (infow, 2, 2, "%d Movepoints, %d left",
  1515.          army_move_rate (np, ap), ap->mvpts);
  1516.   mvwprintw (infow, 3, 2, "Type: %d %s", ap->n_soldiers, ap->type);
  1517.   mvwprintw (infow, 4, 2, "Status: %s  Bonus: %d",
  1518.          s, ap->sp_bonus);
  1519.   if (is_cargo (ap)) {
  1520.     mvwprintw (infow, 5,2, "Capacity: %d/Weight: %d",
  1521.            ap->n_soldiers * CARAVAN_CAPACITY, army_weight (ap));
  1522.   }
  1523.   else {
  1524.     mvwprintw (infow, 5,2, "Weight: %d", army_weight (ap));
  1525.   }
  1526.   mvwprintw (infow, 6,2, "Maintenance per thon:");
  1527.   mvwprintw (infow, 7,2, "  %s",
  1528.          contents (ap->money_maint * ap->n_soldiers,
  1529.                ap->metal_maint * ap->n_soldiers,
  1530.                ap->jewel_maint * ap->n_soldiers, 0,
  1531.                0, -1, NULL, get_spell_pts_maint (ap))); 
  1532.   wrefresh (infow);
  1533.  
  1534.   if (n_flags > 0) {
  1535.     flagw = newwin (n_flags + 2, COLS - 40, 0, 40);
  1536.  
  1537.     rowpos = 1;
  1538.     for (i = 0; i < 32; i++) {
  1539.       if (strlen (army_flags [i].description) > 0 &&
  1540.           ap->flags & (0x1 << i)) {
  1541.     mvwprintw (flagw, rowpos, 1, "%s", army_flags [i].description);
  1542.     rowpos++;
  1543.       }
  1544.     }
  1545.     box (flagw, '|', '-');
  1546.     wrefresh (flagw);
  1547.   }
  1548.   else {
  1549.     flagw = NULL;
  1550.   }
  1551.  
  1552.   statline2_err ("hit space to continue", "army_examine");
  1553.   werase (infow);
  1554.   if (flagw) {
  1555.     werase (flagw);
  1556.   }
  1557.   touch_all_wins ();
  1558. }
  1559.