home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / games / volume13 / dominion / part19 / battle.c next >
C/C++ Source or Header  |  1992-02-11  |  27KB  |  882 lines

  1. /* battle.c -- functions relating to resolving battles between nations    */
  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. /* against(dm,list,nation) - checks a list of armies (in a sector) for    */
  25. /*         any army which the nation specified is against (at WAR/JIHAD)  */
  26. /* count_force(np,sp,ap) - calculates the EFFECTIVE force of an army      */
  27. /*         which a unit represents including nation, sector, army bonuses */
  28. /* free_list(list) - frees up memory which was used in the list           */
  29. /* status_check(list,status) - checks a 'sector list' of armies for a     */
  30. /*         particular status and returns one if it occurs, else zero      */
  31. /* supports(dm,list,nation) - checks a list of armies for any army which  */
  32. /*         the nation specified supports (TREATY)                         */
  33. /**************************************************************************/
  34. /* These remaining functions are probably useless for other purposes      */
  35. /**************************************************************************/
  36. /* dobattles() - resolves all battles in the world during an update       */
  37. /* move_intercepts(dm) - moves each army with INTERCEPT status to         */
  38. /*         bordering hostile armies and sets to ATTACK status.  If there  */
  39. /*         is no hostile army locally, keep army in INTERCEPT mode.       */
  40. /* add_to_list(list,army,mail_list) - adds the army to the list specified */
  41. /*         and also to the mail list IF it does not already occur there.  */
  42. /* extract_losses(list,pct_loss,mail_list,type) - Extracts losses from    */
  43. /*         armies in a sector.  If type is 3, the army list is of neutrals*/
  44. /* total_bonus(np,sp,ap) - gets TOTAL bonus for that army                 */
  45. /* battle_mail(mail_list,s) - adds string s to mail for nations in list   */
  46. /* intro_battle_mail(mail_list,x,y) - sends intro message with rel coord. */
  47. /* intro_battle_news(...) - posts news about the battle                   */
  48. /* single_mail(nation,s) - adds string s to mail for nation #nation       */
  49. /* is_war(dm,x,y) - sees if any war should happen in this sector          */
  50. /* battle(dm,x,y,fp) - main routine which deals with all battles in a sector */
  51.  
  52. #include "dominion.h"
  53. #include "misc.h"
  54. #include "army.h"
  55.  
  56. #include <stdio.h>
  57.  
  58. /* used as type parameter values passed to extract_losses */
  59.  
  60. #define ALLIES 1
  61. #define ENEMIES 2
  62. #define NEUTRALS 3
  63.  
  64.  
  65. extern Sworld world;
  66. int (*wrapx)(), (*wrapy)();
  67. FILE *mailfile;
  68.  
  69. dobattles()
  70. {
  71.   int x,y;
  72.   Sdiplo **dm, **allocate_diplo();
  73.   FILE *tmp_fp, *fopen();    /* for the news posting */
  74.   char tmp_name[100];
  75.   char subj[100];
  76.   dm = allocate_diplo(world.n_nations);
  77.   read_in_diplo(dm,world.n_nations);
  78.  
  79.   printf("Doing battles...\n");
  80.   fflush(stdout);
  81.  
  82.     /* a temporary file name for this news posting */
  83. /*  tmp_name = tmpnam(NULL, "dominion"); */
  84.   strcpy(tmp_name, "dominionXXXXXX");
  85.   mktemp(tmp_name);
  86.  
  87.   if (strlen(tmp_name) == 0) {
  88.     fprintf(stderr, "Error getting temp file name\n");
  89.     return;
  90.   }
  91.   if ((tmp_fp = fopen(tmp_name, "w")) == NULL) {
  92.     fprintf(stderr, "Error opening file %s for writing\n", tmp_name);
  93.     return;
  94.   }
  95. /*  fprintf(tmp_fp, "Date: Thon %d\n", world.turn);
  96.   fprintf(tmp_fp, "From: Update\n");
  97.   fprintf(tmp_fp, "Subj: battles from thon %d to thon %d\n", world.turn-1,
  98.       world.turn);*/
  99.   sprintf(subj, "battles from thon %d to thon %d",world.turn-1,world.turn);
  100.  
  101.   move_intercepts(dm);
  102.  
  103.   for (x = 0; x < world.xmax; x++) {
  104.     for (y = 0; y < world.ymax; y++) {
  105.       if (world.map[x][y].alist && world.map[x][y].alist->next
  106.       && is_war(dm, x, y, tmp_fp)) {
  107. /*    battle(dm, x, y, tmp_fp); */
  108.       }
  109.     }
  110.   }
  111.   fclose(tmp_fp);
  112.   post_news_file(tmp_name, NEWS_GROUP,subj,0);
  113.   printf("just posted file to newsgroup <%s>\n", NEWS_GROUP);
  114. }
  115.  
  116.   /* takes all armies in intercept mode and sees if
  117.      it can move them to attack an enemy army.
  118.    */
  119. move_intercepts(dm)
  120.      Sdiplo **dm;
  121. {
  122.   int nation,x,y;
  123.   Snation *np;
  124.   Ssector *sp;
  125.   Sarmy *ap;
  126.  
  127.   for (nation = 1; nation < world.n_nations; nation++) {
  128.     np = &world.nations[nation];
  129.     ap = np->armies;
  130.     while (ap != NULL) {
  131.       if (ap->status == A_INTERCEPT) {
  132.     for (x = ap->pos.x - 1; x <= ap->pos.x + 1; x++) {
  133.       for (y = ap->pos.y - 1; y <= ap->pos.y + 1; y++) {
  134.         sp = &world.map[(*wrapx)(x,y)][(*wrapy)(x,y)];
  135.           /* army might not be in intercept mode any more,
  136.          in which case we don't make it move.  that way
  137.          an intercept army will only move once.
  138.            */
  139.         if (ap->status == A_INTERCEPT && against(dm, sp->alist, nation)
  140.           /* be careful about moving into bad altitude */
  141.         && (good_army_altitude(np, sp, ap) || is_kamikaze(ap))) {
  142.           printf("%s army %d is intercepting from (%d,%d) to (%d,%d)\n",
  143.              np->name, ap->id, ap->pos.x, ap->pos.y, x, y);
  144.           ap->status = A_ATTACK;
  145. /*          if (sect_n_armies(&world.map[ap->pos.x][ap->pos.y]) > 1) { */
  146.           delete_army_sector(&world.map[ap->pos.x][ap->pos.y],ap);
  147. /*          } else {
  148.         free(sp->alist);
  149.         sp->alist = NULL;
  150.           }
  151. */
  152.           ap->pos.x = (*wrapx)(x,y);
  153.           ap->pos.y = (*wrapy)(x,y);
  154.           insert_army_sector(sp, ap);
  155.         }
  156.       }
  157.     }
  158.       }
  159.       ap = ap->next;
  160.     }
  161.   }
  162. }
  163.  
  164. /*
  165.      against(): searches throught the list of armies
  166.                 and checks for their diplomatic status
  167.         with 'nation' and vice versa.  When
  168.         the nation status is either WAR or JIHAD
  169.         then it returns 1 else 0
  170.                 This routine is called from battle()
  171. */
  172.  
  173. against(dm,list,nation)
  174.      Sdiplo **dm;
  175.      struct armyid *list;
  176.      int nation;
  177. {
  178.   struct armyid *tmp;
  179.   int ds1,ds2;
  180.   
  181.   tmp = list;
  182.   while (tmp != NULL) {
  183.     ds1 = get_diplo_status(dm,nation,tmp->owner);
  184.     ds2 = get_diplo_status(dm,tmp->owner,nation);
  185.     if (ds1 == WAR || ds1 == JIHAD || ds2 == WAR || ds2 == JIHAD) {
  186.       return 1;
  187.     }
  188.     tmp = tmp->next;
  189.   }
  190.   return 0;
  191. }
  192.  
  193. /*  this routine is being called from battle() */
  194.  
  195. supports(dm,list,nation)
  196.      Sdiplo **dm;
  197.      struct armyid *list;
  198.      int nation;
  199. {
  200.   struct armyid *tmp;
  201.   int ds1,ds2;
  202.   
  203.   tmp = list;
  204.   while (tmp != NULL) {
  205.     if (tmp->owner == nation) {    /* a nation is allied with itself */
  206.       return 1;
  207.     }
  208.     ds1 = get_diplo_status(dm,nation,tmp->owner);
  209.     ds2 = get_diplo_status(dm,tmp->owner,nation);
  210.     if (ds1 == TREATY && ds2 == TREATY) {
  211.       return 1;
  212.     }
  213.     tmp = tmp->next;
  214.   }
  215.   return 0;
  216. }
  217.  
  218. /* this routine is being called from battle() as well */
  219. /* also being called from battle() */
  220.  
  221. add_to_list(list,army,mail_list)
  222.      struct armyid **list, *army, **mail_list;
  223. {
  224.   struct armyid *tmp;
  225.  
  226.   tmp = (struct armyid *) malloc(sizeof(struct armyid));
  227.   *tmp = *army;
  228.   tmp->next = (*list);
  229.   (*list) = tmp;
  230.  
  231.   tmp = (*mail_list);
  232.   while (tmp != NULL) {
  233.     if (tmp->owner == army->owner) {
  234.       return;
  235.     }
  236.     tmp = tmp->next;
  237.   }
  238.   tmp = (struct armyid *) malloc(sizeof(struct armyid));
  239.   *tmp = *army;
  240.   tmp->next = (*mail_list);
  241.   (*mail_list) = tmp;
  242. }
  243.  
  244. /***************************************************
  245.      total_bonus() returns all bonuses of an army
  246.      if an army is in TREATY with the owner of the 
  247.      sector then they can enjoy sector defense bonuses
  248.      and have a choice of being in DEFEND, GARRISON,
  249.      AMBUSH etc.
  250.      if an army is in garrison mode they get extra 10
  251.      this function has the flexibility in case we want
  252.      other modes.  For starters I will add some experimental
  253.      stuff with ALLIED status with sector's owner
  254.      ALLIED will give 1/2 of sector bonuses and +5 for
  255.      garrison mode.   A nation with very strong 
  256.      sector bonuses will invite more nations to be in
  257.      treaty with him because any time they fight in a sector
  258.      owned by this strong nation will enjoy the sector
  259.      bonuses as well.
  260.      This routine is called from battle() and from extract_losses
  261. *************************************************************/
  262.  
  263. total_bonus(np,sp,ap,dm)
  264. Snation *np;
  265. Ssector *sp;
  266. Sarmy *ap;
  267. Sdiplo **dm;
  268.  
  269. {
  270.   int bonus = 0;
  271.   int ds1,ds2;  /* test to see if army is in trearty with sector owner */
  272.      /* if they are in treaty with each other then the army can share the*/
  273.      /* sector's defense bonuses. */
  274.  
  275.   if (sp->owner == np->id) {
  276.      bonus += np->defense;
  277.      bonus += sp->defense;
  278.      if (ap->status == A_GARRISON)
  279.        bonus += 10;
  280.    } else {
  281.   ds1 = get_diplo_status(dm,sp->owner,np->id);
  282.   ds2 = get_diplo_status(dm,np->id,sp->owner);  
  283.  
  284.     /* count the nation's bonus */
  285.    if ((ds1 == TREATY || ds1 == ALLIED) && (ds2 == TREATY || ds2 == ALLIED)) {
  286.       switch(ap->status) {
  287.         case A_DEFEND: bonus += np->defense;
  288.                      if (ds1 == TREATY)
  289.                        bonus += sp->defense;
  290.                      else /* ALLIED */
  291.                        bonus += (sp->defense)/2;
  292.                     break;
  293.         case A_ATTACK:
  294.                     { bonus += np->attack;
  295.                        if (ds1 == TREATY)
  296.                          bonus += sp->defense;
  297.                        else /* ALLIED */
  298.                          bonus += (sp->defense)/2;
  299.             }
  300.                      break;
  301.         case A_GARRISON:
  302.                    { bonus += np->defense;
  303.                      if (ds1 == TREATY) {
  304.                        bonus += sp->defense;
  305.                        bonus += 10; }
  306.                      else {/* ALLIED */
  307.                        bonus += (sp->defense)/2;
  308.                        bonus += 5; }
  309.             }
  310.                      break;
  311.         default: break;
  312.       } /* end switch */
  313.     } else 
  314.         bonus += np->attack;  /* not allied with owner */
  315.                                 /* just attack bonuses */
  316.   }
  317.  
  318.   bonus += ap->sp_bonus;    /* army's special bonus */
  319.  
  320.   return bonus;
  321. }
  322.  
  323.   /* returns the force of that army (minimum 1) */
  324.   /* this is being called by battle() and extract_losses()
  325.      and makes a call to total bonus.  It is important to
  326.      know that **dm is being passed along and not used
  327.      until it reaches total_bonus() */
  328.  
  329. count_force(np,sp,ap,dm)
  330.      Snation *np;
  331.      Ssector *sp;
  332.      Sarmy *ap;
  333.      Sdiplo **dm;  /* passed along to total bonus */
  334. {
  335.   int      force;  
  336.  
  337.   force = (ap->n_soldiers*(100+total_bonus(np,sp,ap,dm)))/100;
  338.   if (force < 1) {
  339.     return 1;            /* return at least 1 */
  340.   }
  341.   return force;
  342. }
  343.  
  344. count_men(force_list,flags)
  345. /*
  346.    This counts the nubmer of units in a given force counting only those
  347.    units without the flags in flags set.
  348. */
  349. struct armyid *force_list;
  350. int flags;
  351. {
  352.   struct armyid *tmp_alist;
  353.   Sarmy *ap = NULL, *get_army();
  354.   Snation *np;
  355.   int total = 0;
  356.  
  357.   for (tmp_alist= force_list; tmp_alist != NULL; tmp_alist = tmp_alist->next) {
  358.     np = &world.nations[tmp_alist->owner];
  359.     ap = get_army(np, tmp_alist->id);
  360.     if ((!(ap->flags & flags)) && !(is_spirit(ap))) {
  361.       total += ap->n_soldiers;
  362.     }
  363.   }
  364.   return total;
  365. }
  366.  
  367. count_machine(force_list)
  368. /*
  369.    This counts the nubmer of units in a given force counting only those
  370.    units without the flags in flags set.
  371. */
  372. struct armyid *force_list;
  373. {
  374.   struct armyid *tmp_alist;
  375.   Sarmy *ap = NULL, *get_army();
  376.   Snation *np;
  377.   int total = 0;
  378.  
  379.   for (tmp_alist= force_list; tmp_alist != NULL; tmp_alist = tmp_alist->next) {
  380.     np = &world.nations[tmp_alist->owner];
  381.     ap = get_army(np, tmp_alist->id);
  382.     if (is_machine(ap)) {
  383.       total += ap->n_soldiers;
  384.     }
  385.   }
  386.   return total;
  387. }
  388.  
  389. mach_bonus_avg(force_list)
  390. /*
  391.    This computes the average bonus gained from machines.
  392. */
  393. struct armyid *force_list;
  394. {
  395.   struct armyid *tmp_alist;
  396.   Sarmy *ap = NULL, *get_army();
  397.   Snation *np;
  398.   int tot_mach_bonus = 0, total_units = 0;
  399.  
  400.   for (tmp_alist= force_list; tmp_alist != NULL; tmp_alist = tmp_alist->next) {
  401.     np = &world.nations[tmp_alist->owner];
  402.     ap = get_army(np, tmp_alist->id);
  403.     if (is_machine(ap))
  404.     {
  405.       tot_mach_bonus += ap->sp_bonus * ap->n_soldiers;
  406.       total_units += ap->n_soldiers;
  407.     }
  408.   }
  409.   return (tot_mach_bonus / total_units);
  410. }
  411.  
  412. /* This function is being called from battle() */
  413.  
  414. extract_losses(list, pct_loss, mail_list, type, dm)
  415.      struct armyid *list;
  416.      float pct_loss;
  417.      struct armyid *mail_list;
  418.      int type;
  419.      Sdiplo **dm;
  420. {
  421.   struct armyid *tmp_aid;
  422.   Snation *np;
  423.   Ssector *sp;
  424.   Sarmy *ap, *get_army();
  425.   int killed, dead = 0;
  426.   char s[EXECLEN], name[NAMELEN];
  427.  
  428.   tmp_aid = list;
  429.   if (tmp_aid != NULL) {
  430.     if (type == NEUTRALS) {
  431.       sprintf(s, "---<<< NEUTRAL FORCES IN THE REGION >>>---\n");
  432.     } else {
  433.         if (type == ALLIES)
  434.           sprintf(s, "---<<<  First force >>>---\n");
  435.         else
  436.           sprintf(s, "---<<< Second force >>>---\n");
  437.     }
  438.     battle_mail(mail_list,s);
  439.   }
  440.   while (tmp_aid != NULL) {
  441.     np = &world.nations[tmp_aid->owner];
  442.     ap = get_army(np,tmp_aid->id);
  443.     sp = &world.map[ap->pos.x][ap->pos.y];
  444.       /* special case for mages and ships:  they
  445.      only die if more than 80% of supporting armies
  446.      are killed.
  447.        */
  448.     if ((strcmp(ap->type, "Mage") == 0) || is_cargo(ap)) {
  449.       if (pct_loss > 0.8) {
  450.     killed = ap->n_soldiers;
  451.       } else {
  452.     killed = 0;
  453.       }
  454.     } else {
  455.       killed = (int) (ap->n_soldiers * pct_loss + .5);
  456.         /* if less than 5 soldiers, or if kamikaze unit, kill them */
  457.       if ((ap->n_soldiers - killed) < 5 || is_kamikaze(ap)) {
  458.     killed = ap->n_soldiers;
  459.       }
  460.     }
  461.  
  462.     if (strlen(ap->name) == 0) {
  463.       strcpy(ap->name, "(no name)");
  464.     } else {
  465.       sprintf(name, " \"%s\" ", ap->name);
  466.     }
  467.     sprintf(s,
  468.     "\t%s: Army %s (%d):\n\t\t%d %s\n",
  469.         np->name, name, ap->id, ap->n_soldiers, ap->type);
  470.     battle_mail(mail_list,s);
  471.  
  472. /* AH YOU LITTLE BUGGER, the cause of the segmentation fault mystery
  473.    I didn't look at this sprintf() funtion and it does in fact call
  474.    total_bonus() and count_force.  So I just added an extra parameter
  475.    **dm
  476.  */
  477.     sprintf(s, "\t\tbonus %d, force %d;\n\t\tloses %d men.\n",
  478.         total_bonus(np, sp, ap, dm), count_force(np, sp, ap, dm), killed);
  479.     battle_mail(mail_list,s);
  480.  
  481.     ap->n_soldiers -= killed;
  482.     dead += killed;
  483.     if (ap->n_soldiers == 0) {    /* Army destroyed */
  484.       delete_army_sector(sp, ap);
  485.       delete_army_nation(np, ap);
  486.     }
  487.     tmp_aid = tmp_aid->next;
  488.   }
  489.     /* now that we have the dead count, we can raise some of them
  490.        to join with the vampire units.  this code is primitive:
  491.        just for example, it does not take into account that more
  492.        people may rise than actually died (if there are lots of
  493.        vampire units).
  494.      */
  495.   for (tmp_aid = list; tmp_aid != NULL; tmp_aid = tmp_aid->next) {
  496.     np = &world.nations[tmp_aid->owner];
  497.      /* only if we *do* get the army can we go on. it might have been killed */
  498.     if (ap = get_army(np, tmp_aid->id)) {
  499. /*      sp = &world.map[ap->pos.x][ap->pos.y]; why??? */
  500.       if (is_vampire(ap)) {
  501.           /* notice that an army canot grow by more than a certain amount */
  502.     ap->n_soldiers += min((int) (dead*VAMPIRE_FRACT), 10*ap->n_soldiers);
  503.       }
  504.     }
  505.   }
  506.   return dead;
  507. }
  508.  
  509. free_list(list)
  510.      struct armyid *list;
  511. {
  512.   struct armyid *tmp;
  513.  
  514.   while (list != NULL) {
  515.     tmp = list;
  516.     list = list->next;
  517.     free(tmp);
  518.   }
  519. }
  520.  
  521. status_check(list,status)
  522.      struct armyid *list;
  523.      int status;
  524. {
  525.   struct armyid *tmp;
  526.   Sarmy *ap, *get_army();
  527.   
  528.   tmp = list;
  529.   while (tmp != NULL) {
  530.     ap = get_army(&world.nations[tmp->owner],tmp->id);
  531.     if (ap->status == status) {
  532.       return 1;
  533.     }
  534.     tmp = tmp->next;
  535.   }
  536.   return 0;
  537. }
  538.  
  539. battle_mail(mail_list,s)
  540.      struct armyid *mail_list;
  541.      char s[];
  542. {
  543.   struct armyid *alist;
  544.  
  545.   alist = mail_list;
  546.   while (alist != NULL) {
  547.     single_mail(alist->owner,s);
  548.     alist = alist->next;
  549.   }
  550. }
  551.  
  552.   /* prints the introductory message, with relative
  553.      coordinates for each nation.
  554.    */
  555. intro_battle_mail(mail_list, x, y)
  556.      struct armyid *mail_list;
  557.      int x, y;
  558. {
  559.   Snation *np;
  560.   struct armyid *alist = mail_list;
  561.   char s[EXECLEN];
  562.  
  563.   while (alist) {
  564.     Snation *sect_owner = &world.nations[world.map[x][y].owner];
  565.  
  566.     np = &world.nations[alist->owner];
  567.     sprintf(s, "\nBattle Reported in Sector (%d, %d) [owner: %s]:\n",
  568.         xrel(x, y, np->capital), yrel(x, y, np->capital),
  569.         sect_owner->id == 0 ? "unowned" : sect_owner->name);
  570.     single_mail(alist->owner, s);
  571.     alist = alist->next;
  572.   }
  573. }
  574.  
  575.   /* prints some stuff to the News about the battle */
  576. intro_battle_news(news_fp, x, y, ally_list, enemy_list, neutral_list)
  577.      FILE *news_fp;
  578.      int x, y;
  579.      struct armyid *ally_list, *enemy_list, *neutral_list;
  580. {
  581.   Snation *np;
  582.   struct armyid *alist;        /* to run through the lists */
  583.   Sarmy *ap, *get_army();
  584.   Ssector *sp = &world.map[x][y];
  585.   char s[EXECLEN];
  586.  
  587.   np = &world.nations[world.map[x][y].owner]; /* nation in which it happens */
  588.   fprintf(news_fp, "\nBattle Reported in %s", np->id ? np->name
  589.       : "unowned land");
  590.   if (strlen(sp->name) > 0) {
  591.     fprintf(news_fp, " (\"%s\")", sp->name);
  592.   }
  593.  
  594.   fprintf(news_fp, ".\nInvolved armies:\n");
  595. /*  fprintf(news_fp,   "**************\n"); */
  596.   alist = ally_list;
  597.   while (alist) {        /* run through the participants */
  598.     np = &world.nations[alist->owner];
  599.     ap = get_army(np, alist->id);
  600.     if (is_spirit(ap)) {
  601.       fprintf(news_fp, "\t%s (spirit %s)\n", np->name, ap->name);
  602.     } else {
  603.       fprintf(news_fp, "\t%s (army %s)\n", np->name, ap->name);
  604.     }
  605.     alist = alist->next;
  606.   }
  607.   fprintf(news_fp, "versus\n");
  608.   alist = enemy_list;
  609.   while (alist) {        /* run through the participants */
  610.     np = &world.nations[alist->owner];
  611.     ap = get_army(np, alist->id);
  612.     if (is_spirit(ap)) {
  613.       fprintf(news_fp, "\t%s (spirit %s)\n", np->name, ap->name);
  614.     } else {
  615.       fprintf(news_fp, "\t%s (army %s)\n", np->name, ap->name);
  616.     }
  617.     alist = alist->next;
  618.   }
  619.   if (neutral_list) {
  620.     fprintf(news_fp, "Neutral Armies:\n");
  621.     fprintf(news_fp, "--------------:\n");
  622.   }
  623.   alist = neutral_list;
  624.   while (alist) {        /* run through the participants */
  625.     np = &world.nations[alist->owner];
  626.     fprintf(news_fp, "\t%s\n", np->name);
  627.     alist = alist->next;
  628.   }
  629. }
  630.  
  631. single_mail(nation,s)
  632.      int nation;
  633.      char s[];
  634. {
  635.   char mailname[NAMELEN];
  636.  
  637.   if (world.nations[nation].npc_flag != 0) return;
  638.  
  639.   sprintf(mailname, "mail%d", nation);
  640.   if ( (mailfile = fopen(mailname, "a") ) == NULL)
  641.   {
  642.     fprintf(stderr,"Error: Cannot reopen mail file %s\n",mailname);
  643.     clean_exit();
  644.     exit(1);
  645.   }
  646.   fprintf(mailfile, s);
  647.   fclose(mailfile);
  648. }
  649.  
  650. battle(dm, x, y, news_fp, ally_list, enemy_list, neutral_list, mail_list)
  651.      Sdiplo **dm;
  652.      int x,y;
  653.      FILE *news_fp;            /* for reporting to the news */
  654.      struct armyid *ally_list, *enemy_list, *neutral_list, *mail_list;
  655. {
  656.   Snation *np = NULL;
  657.   Ssector *sp = &world.map[x][y];
  658.   Sarmy *ap = NULL, *get_army();
  659. /*  struct armyid *ally_list, *enemy_list, *neutral_list, *mail_list, *tmp; */
  660.   struct armyid *tmp_alist;
  661.   int ally_force, enemy_force, neutral_force;
  662.   int ally_dead, enemy_dead, neutral_dead;
  663.   int enemy_act_mach, ally_act_mach, neutral_act_mach, mach_force_fact;
  664.   double defense_loss = 0.0;
  665.  
  666.   float ally_losses, enemy_losses, neutral_losses;
  667.   int nation;
  668.  
  669.   char mailname[NAMELEN], s[EXECLEN];
  670.  
  671.   /* Initialize the three lists for armies in the sector's battle */
  672.  
  673. /*  ally_list = enemy_list = neutral_list = mail_list = NULL; */
  674.   ally_force = enemy_force = neutral_force = 0;
  675.   ally_dead = enemy_dead = neutral_dead = 0;
  676.   ally_losses = enemy_losses = neutral_losses = 0.0;
  677.  
  678.   /* Now begin breaking the armies up by affiliations and sum forces */
  679.   for (tmp_alist = ally_list; tmp_alist != NULL; tmp_alist = tmp_alist->next) {
  680.     np = &world.nations[tmp_alist->owner];
  681.     ap = get_army(np, tmp_alist->id);
  682.     ally_force += count_force(np,sp,ap,dm);
  683.   }
  684.   for(tmp_alist = enemy_list; tmp_alist != NULL; tmp_alist = tmp_alist->next) {
  685.     np = &world.nations[tmp_alist->owner];
  686.     ap = get_army(np, tmp_alist->id);
  687.     enemy_force += count_force(np,sp,ap,dm);
  688.   }
  689.   for(tmp_alist=neutral_list; tmp_alist != NULL; tmp_alist = tmp_alist->next){
  690.     np = &world.nations[tmp_alist->owner];
  691.     ap = get_army(np, tmp_alist->id);
  692.     neutral_force += count_force(np,sp,ap,dm);
  693.   }
  694.  
  695. /*  tmp = sp->alist;
  696.   while (tmp != NULL) {
  697.     np = &world.nations[tmp->owner];
  698.     ap = get_army(np,tmp->id);
  699.     nation = tmp->owner;
  700.     if (ally_list == NULL
  701.     || supports(dm,ally_list,nation)
  702.         || against(dm,enemy_list,nation)) {
  703.       add_to_list(&ally_list,tmp,&mail_list);
  704.       ally_force += count_force(np,sp,ap,dm);
  705.     } else {
  706.       if (supports(dm,enemy_list,nation) 
  707.          || against(dm,ally_list,nation)) {
  708.     add_to_list(&enemy_list,tmp,&mail_list);
  709.     enemy_force += count_force(np,sp,ap,dm);
  710.       } else {
  711.     add_to_list(&neutral_list,tmp,&mail_list);
  712.     neutral_force += count_force(np,sp,ap,dm);
  713.       }
  714.     }
  715.     tmp = tmp->next;
  716.   }
  717. */
  718. /* Now adjust the forces for the presence of macines */
  719.   if ((ally_act_mach = min(count_machine(ally_list) * MEN_PER_MACHINE,
  720.                         count_men(ally_list,(AF_MACHINE)))) != 0)
  721.   {
  722.     ally_force += ally_act_mach * mach_bonus_avg(ally_list) / 100;
  723.   }
  724.   if ((enemy_act_mach = min(count_machine(enemy_list) * MEN_PER_MACHINE,
  725.                      count_men(enemy_list,(AF_MACHINE)))) != 0)
  726.   {
  727.     enemy_force += enemy_act_mach * mach_bonus_avg(enemy_list) / 100;
  728.   }
  729.   if ((neutral_act_mach = min(count_machine(neutral_list) * MEN_PER_MACHINE,
  730.                             count_men(neutral_list,(AF_MACHINE)))) != 0)
  731.   {
  732.     neutral_force += neutral_act_mach * mach_bonus_avg(neutral_list) / 100;
  733.   }
  734.   /* Now calculate loss percentages for each side */
  735.   if (ally_force != 0 && enemy_force != 0 && 
  736.      (status_check(ally_list,A_ATTACK) || status_check(enemy_list,A_ATTACK) ||
  737.       status_check(ally_list,A_OCCUPY) || status_check(enemy_list,A_OCCUPY))) {
  738.  
  739.       /* send an introductory message to all users,
  740.      giving the relative coords of sector in which
  741.      battle happens.  also send out some news.
  742.        */
  743.     intro_battle_mail(mail_list, x, y);
  744.     intro_battle_news(news_fp, x, y, ally_list, enemy_list, neutral_list);
  745.  
  746.     ally_losses = (1.0*enemy_force*enemy_force)
  747.       /(1.0*(ally_force*ally_force + enemy_force*enemy_force));
  748.     enemy_losses = (1.0*ally_force*ally_force)
  749.       /(1.0*(ally_force*ally_force + enemy_force*enemy_force));
  750.     if (ally_losses < enemy_losses) {
  751.       neutral_losses = ally_losses/10.0;
  752.     } else {
  753.       neutral_losses = enemy_losses/10.0;
  754.     }
  755. /* Now we mess with the fortifications. */
  756.   np = &world.nations[enemy_list->owner];
  757.   defense_loss = 0.0;
  758.   if (sp->owner == np->id)
  759.   {
  760.     if (ally_act_mach != 0)
  761.     { 
  762.       defense_loss = count_men(ally_list,AF_MACHINE);
  763.       defense_loss = defense_loss/ally_act_mach;
  764.       defense_loss *= enemy_losses;
  765.       defense_loss = (int)(sp->defense * defense_loss);
  766.       sp->defense -= (int)defense_loss;
  767.     }
  768.   }
  769.   np = &world.nations[ally_list->owner];
  770.   if (sp->owner == np->id)
  771.   {
  772.     if (enemy_act_mach != 0)
  773.     { 
  774.       defense_loss = count_men(enemy_list,AF_MACHINE);
  775.       defense_loss = defense_loss/enemy_act_mach;
  776.       defense_loss *= ally_losses;
  777.       defense_loss = (int)(sp->defense * defense_loss);
  778.       sp->defense -= (int)defense_loss;
  779.     }
  780.   }
  781.  
  782.     /* Now extract losses from each group */
  783.     /* calls to extract_losses() */
  784.  
  785.     ally_dead = extract_losses(ally_list,ally_losses,mail_list,ALLIES,dm);
  786.     enemy_dead = extract_losses(enemy_list,enemy_losses,mail_list,ENEMIES,dm);
  787.     neutral_dead =
  788.       extract_losses(neutral_list,neutral_losses,mail_list,NEUTRALS,dm);
  789.   } 
  790.   if (defense_loss != 0.0)
  791.   {
  792.     sprintf(s, "\nSector Defenses reduced by %d to %d\n",
  793.                                (int)defense_loss,sp->defense);
  794.     battle_mail(mail_list,s);
  795.   }
  796.  
  797.   /* Now free up all the memory we ate with our army lists! */
  798.   free_list(ally_list);
  799.   free_list(enemy_list);
  800.   free_list(neutral_list);
  801.   free_list(mail_list);
  802. }
  803.  
  804.   /* this is an ugly routine which goes into great detail
  805.      to see if a war is actually taking place in a given
  806.      sector.  it is totally inefficient, but until we
  807.      redo the battle code, it will have to do.  the previous
  808.      code used to not yield battles in some cases.
  809.    */
  810. is_war(dm, x, y, news_fp)
  811.      Sdiplo **dm;
  812.      int x, y;
  813.      FILE *news_fp;
  814. {
  815.   Ssector *sp = &world.map[x][y];
  816.   Snation *np, *tmp_np;
  817.   struct armyid *alist, *tmp_alist;
  818.   int id1, id2, stat1, stat2;
  819.  
  820. /*  printf("**********sector (%d,%d)***************\n", x, y); */
  821.   alist = sp->alist;
  822.   while (alist != NULL) {
  823. /*    printf("alist = (%d,%d)\n", alist->owner, alist->id); */
  824.     np = &world.nations[alist->owner];
  825.     id1 = np->id;
  826.     tmp_alist = sp->alist;
  827.     while (tmp_alist != NULL) {
  828. /*      printf("\ttmp_alist = (%d,%d)\n", tmp_alist->owner, tmp_alist->id); */
  829.       tmp_np = &world.nations[tmp_alist->owner];
  830.       id2 = tmp_np->id;
  831.       stat1 = get_diplo_status(dm, id1, id2);
  832. /*      printf("stat1 = %d\n", stat1); */
  833.       stat2 = get_diplo_status(dm, id2, id1);
  834. /*      printf("stat2 = %d\n", stat2); */
  835.       if (stat1 == WAR || stat1 == JIHAD || stat2 == WAR || stat2 == JIHAD) {
  836.     struct armyid *other_tmp_alist;
  837.     struct armyid *ally_list, *enemy_list, *neutral_list, *mail_list;
  838.     int nation;
  839.  
  840.     ally_list = enemy_list = neutral_list = mail_list = NULL;
  841.  
  842.     printf("Found battle between %s and %s\n", np->name, tmp_np->name);
  843.     add_to_list(&ally_list, tmp_alist, &mail_list);
  844.     other_tmp_alist = sp->alist;
  845.       /* now we add everything else in this sector to some list */
  846.     while (other_tmp_alist != NULL) {
  847.         /* bad kludge */
  848.       nation = other_tmp_alist->owner;
  849.       /* remember:  we have already added an ally.  don't
  850.          duplicate him.
  851.        */
  852.       if (other_tmp_alist->owner != tmp_alist->owner
  853.           || other_tmp_alist->id != tmp_alist->id) {
  854.         if (ally_list == NULL
  855.         || supports(dm,ally_list,nation)
  856.         || against(dm,enemy_list,nation)) {
  857.           add_to_list(&ally_list,other_tmp_alist,&mail_list);
  858. /*          ally_force += count_force(np,sp,ap,dm); */
  859.         } else {
  860.           if (supports(dm,enemy_list,nation) 
  861.           || against(dm,ally_list,nation)) {
  862.         add_to_list(&enemy_list,other_tmp_alist,&mail_list);
  863. /*        enemy_force += count_force(np,sp,ap,dm); */
  864.           } else {
  865.         add_to_list(&neutral_list,other_tmp_alist,&mail_list);
  866. /*        neutral_force += count_force(np,sp,ap,dm); */
  867.           }
  868.         }
  869.       }
  870.       other_tmp_alist = other_tmp_alist->next;
  871.     }
  872.     battle(dm, x, y, news_fp,
  873.            ally_list, enemy_list, neutral_list, mail_list);
  874.     return 1;
  875.       }
  876.       tmp_alist = tmp_alist->next;
  877.     }
  878.     alist = alist->next;
  879.   }
  880.   return 0;
  881. }
  882.