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

  1.  /* update.c -- update the dominion world */
  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 <stdio.h>
  28. #include <signal.h>
  29. #include <math.h>
  30.  
  31. #define BAKBEFORE 1
  32. #define BAKAFTER 2
  33.  
  34. extern Sworld world;
  35. extern Suser user;
  36. extern struct race_list *races;    /* list of races */
  37. extern struct army_type *army_types; /* array of available armies */
  38. extern Sh_spell *hanging_spells;
  39. extern char libdir[];
  40. extern int debug;
  41. extern int (*wrapx)(), (*wrapy)();
  42. FILE *mailfile;
  43. extern struct s_desig_map desig_map[];
  44. extern double get_version(), atof();
  45. Suser *temp_users;
  46.  
  47. struct move_data
  48. {
  49.   int moved, adj;
  50.   double des;
  51. } **work_data;
  52.  
  53.  
  54. main(argc, argv)
  55.      int argc;
  56.      char *argv[];
  57. {
  58.   int i, j, k, insector, occuflag, c, bakflag = 0;
  59.   Snation *np;
  60.   Ssector *sp;
  61.   Sarmy *ap, *best;
  62.   extern char *optarg;
  63.   extern int optind;
  64.   char mailname[NAMELEN], passwd[PASSLEN], default_pass[NAMELEN];
  65.   char mail_subject[80],receiver[NAMELEN];
  66.  
  67.   strcpy(libdir, DEF_LIBDIR);    /* default libdir */
  68.   default_pass[0] = '\0';
  69.  
  70.   if (debug) {
  71.     printf("libdir=%s,def_libdir=%s\n", libdir, DEF_LIBDIR);
  72.   }
  73.  
  74.   while ((c = getopt(argc, argv, "baxp:d:--")) != EOF)
  75.     switch (c) {
  76.     case 'b':
  77.       bakflag |= BAKBEFORE;
  78.       break;
  79.     case 'a':
  80.       bakflag |= BAKAFTER;
  81.       break;
  82.     case 'x':
  83.       debug++;
  84.       break;
  85.     case 'd':
  86.       strcpy(libdir, optarg);
  87.       break;
  88.     case 'p':            /* allow user to give passwd on command line */
  89.       strcpy(default_pass, optarg);
  90.       break;
  91.     }
  92.   if (chdir(libdir) == -1) {
  93.     fprintf(stderr,"Error: cannot cd to directory %s\n",libdir);
  94.     clean_exit();
  95.     exit();
  96.   }
  97.  
  98.   if (is_master_lock()) {
  99.     printf("There is a master lock\n");
  100.     exit(1);
  101.   }
  102.   set_master_lock();
  103.   if (is_any_lock()) {
  104.     printf("There is a lock; you should see if the nation is still playing\n");
  105.     clean_exit();
  106.     exit(1);
  107.   }
  108.   set_update_time();
  109.   SRND(time(0L));
  110.   load_army_types();        /* it is important to load these in */
  111.   load_spirit_types();        /* these must also be loaded */
  112.  
  113.   if (bakflag & BAKBEFORE) {
  114.     printf("Backing up data in 'bakbefore' directory\n");
  115.     backuplib("bakbefore"); }
  116.   printf("\n\n dominion : Update Module : COMMENCING\n");
  117.   printf("----------------------------------\n");
  118.  
  119.   read_world(&world, WORLD_FILE);
  120.  
  121.   get_crypt_pass("Gamemaster password: ", passwd, NULL, default_pass);
  122.   if (strcmp(world.nations[0].passwd, passwd)) {
  123.     printf("\r\nTry again\r\n");
  124.     get_crypt_pass("Gamemaster password: ", passwd, NULL, default_pass);
  125.     if (strcmp(world.nations[0].passwd, passwd)) {
  126.       printf("You must be a gamemaster to update the world!\n");
  127.       exit(1);
  128.     }
  129.   }
  130.  
  131.   printf("Updating from thon %d to thon %d.\n", world.turn, world.turn+1);
  132.   world.turn++; /* HAPPY NEW THON */
  133.  
  134.   /* Run through each nation doing calculations for money, etc. */
  135.   /* this is a kludge:  we need the user struct for things like spells */
  136.  
  137. /*  update_npc_diplo(); /* we don't use this any more */
  138.   load_master_execs();
  139.   init_work_data(world.xmax, world.ymax);
  140.     /* you must load each nation before you can load the hanging
  141.        spells, in case a user cast a spell on an army s/he just made
  142.        this turn.
  143.      */
  144.   for (i=1; i<world.n_nations; ++i) {
  145.     np = &world.nations[i];
  146.     if (is_active_ntn(np)) {
  147.       user.spirit_list = NULL;
  148.       user.np = np;
  149.       get_spirits(&user, np->mag_skill);
  150.       load_nation(i, np);
  151.  
  152.       if (gets_mail(np)) {
  153.     sprintf(mailname, "mail%d", i);
  154.     mailfile = fopen(mailname, "a");
  155.     fprintf(mailfile,"\n---------MESSAGE FROM UPDATE PROGRAM---------\n");
  156.     fprintf(mailfile, "During the time between thon %d and thon %d...\n",
  157.          world.turn-1, world.turn);
  158.     fclose(mailfile);
  159.       } else {
  160.     mailfile = NULL;
  161.       }
  162.     }
  163.   }
  164.   load_h_spells(NULL);
  165.   docargos();            /* picks up cargos dropped by caravans */
  166.   for (i = 1; i < world.n_nations; ++i) {
  167.     np = &world.nations[i];
  168.     if (is_active_ntn(np)) {
  169.  
  170.       user.id = i;
  171.       user.np = &world.nations[i];
  172.  
  173.       /* start the user off with all spells s/he deserves.
  174.          note that, because of spirits, this has to be done
  175.          before load_nation(), since the spirit list is used
  176.          in the exec parsing.  THIS MIGHT NOT BE TRUE ANY MORE.
  177.          It still is true. moreso than ever -SHU
  178.         */
  179.       user.spell_list = NULL;
  180.       user.spirit_list = NULL;
  181.         /* prepare for sending them mail */
  182.       if (gets_mail(np)) {
  183.     sprintf (mailname, "mail%d", i);
  184.     mailfile = fopen(mailname, "a");
  185.       } else {
  186.     mailfile = NULL;
  187.       }
  188.       printf(" - - - - - - updating nation %s (%d) %s - - - - - -\n",
  189.           np->name, i, (np->npc_flag)?"[npc]":" ");
  190.       fflush(stdout);
  191.       if (np->npc_flag) {
  192.     npc_moves(np);
  193.       }
  194.       dotechno (np, mailfile);
  195.       dospy(np, mailfile);
  196.       domagic(np, mailfile);
  197.       domoney(np);
  198.       dometal(np);
  199.       dojewels(np);
  200.       dofood(np);
  201.       docivilians(np);
  202.       load_dead_hspells(&user,1);
  203.  
  204.       if (mailfile) { fclose (mailfile); }
  205.     }
  206.   }
  207.   dobattles();
  208.   take_sectors();
  209.   update_diplo();
  210.   reset_armies();
  211.   send_mail();
  212.   post_statistics();
  213.     /* clears the hanging spells before writing the world */
  214.   clear_dead_hspells();
  215.  
  216.   clear_h_spells();
  217.   write_h_spells();
  218.   
  219.   printf("Saving world data...\n");
  220.   fflush(stdout);
  221.   write_world(&world, WORLD_FILE);
  222.  
  223.   system("rm -f exec/exec*");
  224.  
  225.   if (bakflag & BAKAFTER) {
  226.     printf("Backing up data in 'bakafter' directory.\n");
  227.     backuplib("bakafter"); }
  228.   printf("----------------------------------\n");
  229.   printf(" dominion : Update module : COMPLETE\n\n");
  230.     /* at the end, remove the cargo file */
  231.     /* remove the master lock file */
  232.   del_master_lock();
  233. }
  234.  
  235.   /* This will send mail to each nation that has a mail temp file. */
  236. send_mail()
  237. {
  238.   char mailname[200], receiver[200], mail_subject[200];
  239.   int i;
  240.  
  241.   printf("Sending mail... "); fflush(stdout);
  242.  
  243.   sprintf(mail_subject,"Update to thon %d", world.turn);
  244.   for (i = 1; i < world.n_nations; i++) {
  245.     sprintf(mailname, "mail%d", i);
  246.     mailfile = fopen(mailname, "r");
  247.     if (mailfile) {
  248.       fclose (mailfile);
  249.       sprintf(receiver,"%s of %s",
  250.           world.nations[i].leader, world.nations[i].name);
  251.       if (debug) {
  252.     printf("Sending mail to %s using file %s.\n",world.nations[i].name,
  253.            mailname);
  254.     printf("Receiver => %s\n",receiver);
  255.       }
  256.         /* make sure we send no mail to NPCs */
  257.       if (gets_mail(&world.nations[i])) {
  258.     if (mail_send(mailname, 0, i, mail_subject) > 0) {
  259.       fprintf(stderr,"Couldn't send mail to nation %d\n",i);
  260.     }
  261.       }
  262.       unlink(mailname);
  263.     }
  264.   }
  265.   printf("done.\n");
  266.   fflush(stdout);
  267. }
  268.  
  269.  
  270. /* This will backup the lib directory either before an update, after an
  271.    update, or both.  */
  272. backuplib(dirname)
  273.      char dirname[];
  274. {
  275.   char cmdstr[200];
  276.  
  277.   sprintf(cmdstr, "/bin/rm -fr %s\n", dirname);
  278.   if (debug) printf("%s", cmdstr);
  279.   system(cmdstr);
  280.   sprintf(cmdstr, "/bin/mkdir %s\n", dirname);
  281.   if (debug) printf("%s", cmdstr);
  282.   system(cmdstr);
  283.   sprintf(cmdstr,
  284.        "/bin/cp -r doc magic misc exec mail news world dom_diplo %s\n",
  285.        dirname);
  286.   if (debug) { printf("%s", cmdstr); }
  287.   system(cmdstr);
  288. }
  289.  
  290.  
  291. /* This function is called at the end of the update to change all armies
  292.    that are in occupy mode to defend mode.  It also restores full move
  293.    points to all armies.
  294.  */
  295.  
  296. /* HOLD IT:  shouldn't this be done with the nation army lists instead
  297.    of sector army lists?  many sectors will have no armies, so it is
  298.    a waste to traverse the whole map.
  299.  */
  300. reset_armies()
  301. {
  302.   Sarmy *ap, *next_ap;
  303.   Sspirit *spiritp = NULL, *get_spirit_from_type();
  304.   struct army_type this_atype;
  305.   extern struct army_type *army_types;
  306.   struct spirit_type this_spirit_type;
  307.   extern struct spirit_type *spirit_types;
  308.   Snation *np;
  309.   Ssector *sp;
  310.   int i, j;
  311.   FILE *mfile, *fopen();
  312.   char mailfname[PATHLEN];
  313.  
  314.   printf("Resetting armies...\n");
  315.   fflush(stdout);
  316.   for(j = 0; j < world.n_nations; ++j) {
  317.     np = &world.nations[j];
  318.     sprintf(mailfname, "mail%d", j);
  319.     mfile = fopen(mailfname, "a");
  320.     ap = np->armies;
  321.     for(i=0; ap != NULL; ++i) {
  322.       next_ap = ap->next;
  323.       sp = &world.map[ap->pos.x][ap->pos.y];
  324.       if (ap->status == A_OCCUPY) {
  325.     ap->status = A_DEFEND;
  326.       }
  327.       ap->mvpts = army_move_rate(np, ap);
  328.         /* make sure that armies are not too small for patrol/intercept */
  329.       if ((ap->status == A_PATROL || ap->status == A_INTERCEPT)
  330.       && !can_patrol(ap)) {
  331.     ap->status = A_DEFEND;
  332.       }
  333.         /* patrol and garrison move less */
  334.       if (ap->status == A_PATROL || ap->status == A_GARRISON) {
  335.     ap->mvpts /= 2;
  336.       }
  337.       if (ap->status == A_INTERCEPT) {
  338.     ap->mvpts = 0;
  339.       }
  340.         /* if they were in a fort, add some bonus */
  341.       if (is_army(ap)) {
  342.     if (sp->owner == np->id && sp->designation == D_FORT) {
  343.       ap->sp_bonus += FORT_BONUS_INCREASE;
  344.     }
  345.       }
  346.         /* make sure that armies and spirits have their permanent flags */
  347.       if (is_army(ap)) {
  348.     this_atype = army_types[army_type_index(ap->type)];
  349.     ap->flags |= this_atype.flags;
  350.       }
  351.       if (is_spirit(ap)) {
  352.     this_spirit_type = spirit_types[spirit_type_index(ap->type)];
  353.     ap->flags |= this_spirit_type.flags;
  354.       }
  355.       if (is_mage(ap)) {
  356.     ap->flags |= AF_WIZARD;
  357.       }
  358.         /* special handling of the INVERSE_ALT flag:  if they
  359.        are a land race, it becomes a WATER flag;  if they
  360.        are a water race, it becomes a LAND flag.
  361.      */
  362.       if (ap->flags & AF_INVERSE_ALT) {
  363.     if (np->race.pref_alt >= SEA_LEVEL) {
  364.       ap->flags |= AF_WATER;
  365.     } else {
  366.       ap->flags |= AF_LAND;
  367.     }
  368.       }
  369.         /* if they are underwater without the right flag, make them drown */
  370.       if (!good_army_altitude(np, sp, ap)) {
  371.     printf("Army %d (%s) in %s %s.  x%d,y%d\n", ap->id, ap->name, np->name,
  372.            (sp->altitude < SEA_LEVEL) ? "drowned" : "suffocated",
  373.            ap->pos.x, ap->pos.y);
  374.     if (mfile) {        /* elaborate printing statement!! */
  375.       fprintf(mfile, "Your army %d (%s) %s.\n", ap->id, ap->name,
  376.           (sp->altitude < SEA_LEVEL) ? "drowned" : "suffocated");
  377.     }
  378.     delete_army_sector(sp, ap);
  379.     delete_army_nation(np, ap);
  380.       }
  381.  
  382.       ap = next_ap;
  383.     }
  384.     if (mailfile) { fclose(mailfile); }
  385.   }
  386.   if (mfile) { fclose(mfile); }
  387.   printf("done.\n");
  388.   fflush(stdout);
  389. }
  390.  
  391.  
  392.  
  393. /* This will check which sectors have armies in them in occupy mode.  If there
  394.    are two armies in occupy mode, the one with the highest move ratio gets the
  395.    sector... */
  396. take_sectors()
  397. {
  398.   int i, j, k, occuflag, availflag;
  399.   Ssector *sp;
  400.   int old_owner;        /* old owner of the sector that was taken */
  401.   Sarmy *ap, *best, *get_army();
  402.   int n_armies;            /* how many are in sector */
  403.   struct armyid *alist;        /* to run through the sector's army list */
  404.   char mailname[200];
  405.   Sdiplo **dm, **allocate_diplo();
  406.  
  407.   dm = allocate_diplo(world.n_nations);
  408.   read_in_diplo(dm,world.n_nations);
  409.   
  410.   for (i = 0; i < world.ymax; i++) /* check each sector for armies */
  411.     for (j = 0; j < world.xmax; j++) {
  412.       sp = &(world.map[j][i]);
  413.       sp->flags &= ~SF_HOSTILE; /* Turn off the old hostility */
  414.       if (sp->alist != NULL) {     /* we have some armies in this sector */
  415.     occuflag = 0;        /* is anyone trying to occupy this sector?  */
  416.     availflag = 1;        /* is this sector available */
  417.     best = NULL;        /* this keeps track of army with best ratio */
  418.     alist = sp->alist;
  419.  
  420.     /* Now we'll run though each army in the sector and try to find      */
  421.     /* which (if any) are attempting to occupy that sector.  An army can */
  422.     /* only occupy a sector if it's status is OCCUPY, it has enough      */
  423.     /* soldiers (OCCUPYING_SOLDIERS) and either the sector is unowned or */
  424.     /* the nation which owns the sector is the foe of the army and the   */
  425.     /* sector owner has no armies remaining in the sector.               */
  426.  
  427.     n_armies = sect_n_armies(sp);
  428.     for (k = 0; k < n_armies; k++) {
  429.       ap = get_army(&world.nations[alist->owner], alist->id);
  430.  
  431.       if (ap->status == A_OCCUPY && ap->n_soldiers >= OCCUPYING_SOLDIERS &&
  432.           (sp->owner == 0 || 
  433.            (sp->owner != 0 && 
  434.         (get_diplo_status(dm,ap->owner,sp->owner) == WAR || 
  435.          get_diplo_status(dm,ap->owner,sp->owner) == JIHAD)))) {
  436.  
  437.         if (best == NULL) best = ap; /* if first army checked, best yet */
  438.         occuflag = 1;    /* yes, someone's trying to get the sector */
  439.         if (ap->mvratio > best->mvratio) best = ap;
  440.       }
  441.  
  442.       /* If sector owner has an army remaining on it, nobody can take it */
  443.       if (ap->owner == sp->owner) {
  444.         availflag = 0;
  445.       }
  446.       alist = alist->next;    /* now get the next army */
  447.     }
  448.  
  449.     if (occuflag && availflag) {
  450.       old_owner = sp->owner;
  451.       if (debug) printf("Winner is %s's army %d... ",
  452.                  world.nations[best->owner].name, best->id);
  453.       if (best->owner != sp->owner) {
  454.         if (sp->owner != 0) subtsector(&world.nations[sp->owner], j, i);
  455.         addsector(&world.nations[best->owner], j, i);
  456.             if (sp->n_people) {
  457.             /* If there were any civilians in the sector */
  458.               sp->flags |= SF_HOSTILE; /* It's hostile for 1 update */
  459.         }
  460.         if (gets_mail(&world.nations[old_owner]) && old_owner != 0) {
  461.           sprintf(mailname, "mail%d", old_owner);
  462.           mailfile = fopen(mailname, "a");
  463.         } else {mailfile = NULL; }
  464.         if (sp->designation == D_CAPITAL) {
  465.           take_capital(&(world.nations[old_owner]),
  466.                &(world.nations[best->owner]), mailfile);
  467.         } else {
  468.           if (mailfile) {
  469.         fprintf(mailfile,
  470.             "Sector %d, %d has been taken from you by %s!\n",
  471.             xrel(j,i,world.nations[old_owner].capital),
  472.             yrel(j,i,world.nations[old_owner].capital),
  473.             world.nations[best->owner].name);
  474.           }
  475.         }
  476.         if (mailfile) {
  477.           fclose(mailfile);
  478.         }
  479.         if (gets_mail(&world.nations[best->owner])) {
  480.           sprintf(mailname, "mail%d", best->owner);
  481.           if ((mailfile = fopen(mailname, "a")) == NULL)
  482.               {
  483.                 fprintf(stderr,"Error: cannot append to %s\n",mailname);
  484.                 clean_exit();
  485.                 exit(1);
  486.               }
  487.           fprintf(mailfile, "You successfully captured sector %d, %d!\n",
  488.               xrel(j,i,world.nations[best->owner].capital),
  489.               yrel(j,i,world.nations[best->owner].capital));
  490.           fclose(mailfile);
  491.         }
  492.       }
  493.       else if (debug) printf("They already own that sector!\n");
  494.     }
  495.       }
  496.     }
  497.   free_diplo(dm,world.n_nations);
  498. }
  499.  
  500. /* nation np2 takes capital of nation np1.  mfile is mail file of nation
  501.    np1.  If np1 has any cities, make the first one their new capital.
  502.    1/2 of np1's metal, jewels, and money are transferred to np2. */
  503. take_capital(np1, np2, mfile)
  504.      Snation *np1, *np2;
  505.      FILE *mfile;
  506. {
  507.   struct pt_list *ptlist, *bestpt;
  508.   int done = 0, x = np1->capital.x, y = np1->capital.y;
  509.   FILE *news_fp, *fopen();    /* to print this to the news */
  510.   FILE * sacker;
  511.   char tmp_name[100];
  512.   char * contents ();
  513.   char subj[100];
  514.  
  515.     /* A temporary file name for this news posting */
  516. /*  tmp_name = tmpnam(NULL, "dominion"); */
  517.   strcpy(tmp_name, "dominionXXXXXX");
  518.   mktemp(tmp_name);
  519.  
  520.   if (strlen(tmp_name) == 0) {
  521.     fprintf(stderr, "Error getting temp file name\n");
  522.     return;
  523.   }
  524.   if ((news_fp = fopen(tmp_name, "w")) == NULL) {
  525.     fprintf(stderr, "Error opening file %s for writing\n", tmp_name);
  526.     return;
  527.   }
  528.   sprintf (subj, "mail%d", np2->id);
  529.   if ((sacker = fopen (subj, "a")) == NULL) {
  530.     fprintf (stderr, "Error opening file %s for writing\n", subj);
  531.     return;
  532.   }
  533.   sprintf(subj, "Capital of %s sacked", np1->name);
  534.   fprintf(news_fp,"\n\nCapital of %s was sacked by %s\n",np1->name,np2->name);
  535.   fclose(news_fp);
  536.   post_news_file(tmp_name, NEWS_GROUP,subj,0);
  537.  
  538.   if (mfile) {
  539.     fprintf(mfile, "Your capital was captured by %s!\n", np2->name);
  540.   }
  541.   printf("   ** %s has lost their capital to %s! **\n", np1->name, np2->name);
  542.   ptlist = np1->ptlist;
  543.     /* first we see if we can get another city for capital */
  544.   while (ptlist != NULL && !done) {
  545.     if (world.map[ptlist->pt.x][ptlist->pt.y].designation == D_CITY) {
  546.       done = 1;
  547.       world.map[ptlist->pt.x][ptlist->pt.y].designation = D_CAPITAL;
  548.       break;
  549.     }
  550.     ptlist = ptlist->next;
  551.   }
  552.   if (done) {            /* found a replacement city */
  553.     if (mfile) {
  554.       fprintf(mfile, "Your city at %d,%d is your new capital\n",
  555.           xrel(ptlist->pt.x, ptlist->pt.y, np1->capital),
  556.           yrel(ptlist->pt.x, ptlist->pt.y, np1->capital));
  557.     }
  558.     world.map[ptlist->pt.x][ptlist->pt.y].designation = D_CAPITAL;
  559.     np1->capital = ptlist->pt;
  560.   } else {            /* np1 had no more cities!! */
  561.     if (mfile) {
  562.       fprintf(mfile, "You have no cities to put your new capital!\n");
  563.     }
  564.  
  565.     ptlist = np1->ptlist;       /* give them the most populated sector */
  566.     if (ptlist) {               /* if they have any left!! */
  567.       bestpt = ptlist;
  568.       while (ptlist != NULL) {
  569.         if (world.map[ptlist->pt.x][ptlist->pt.y].n_people >
  570.             world.map[bestpt->pt.x][bestpt->pt.y].n_people)
  571.           bestpt = ptlist;
  572.     ptlist = ptlist->next;
  573.       }
  574.       if (mfile) {
  575.     fprintf(mfile, "I am putting your new capital at (%d,%d)\n",
  576.         xrel(bestpt->pt.x, bestpt->pt.y, np1->capital),
  577.         yrel(bestpt->pt.x, bestpt->pt.y, np1->capital));
  578.       }
  579.       np1->capital.x = bestpt->pt.x;
  580.       np1->capital.y = bestpt->pt.y;
  581.       world.map[bestpt->pt.x][bestpt->pt.y].designation = D_CAPITAL;
  582.     } else {            /* if you have no sectors... you die */
  583.       if (mfile) {
  584.     fprintf(mfile,"You have no sectors left. Your nation is destroyed.\n");
  585.       }
  586.       destroy_nation(np1->id);
  587.       printf("*** nation %d is destroyed ***\n", np1->id);
  588.     }
  589.   }
  590.   world.map[x][y].designation = D_CITY; /* old capital -> city (for new guy) */
  591.  
  592.   /* deplete nation */
  593.   fprintf (sacker, "\nSacked capital of %s.  Gained:\n", np1->name);
  594.   fprintf (sacker, "\t%s\n\n", contents(max(np1->money/2, 0),
  595.                       max(np1->metal/2, 0),
  596.                       max(np1->jewels/2, 0),
  597.                       max(np1->food/2, 0), 0, -1, NULL, 0));
  598.   fclose (sacker);
  599.  
  600.   np2->money += max(np1->money/2, 0); /* don't acquire debts */
  601.   np1->money = np1->money/2;
  602.   np2->jewels += max(np1->jewels/2, 0);
  603.   np1->jewels = np1->jewels/2;
  604.   np2->metal += max(np1->metal/2, 0);
  605.   np1->metal = np1->metal/2;
  606.   np2->food += max(np1->food/2, 0);
  607.   np1->food =np1->food/2;                      
  608. }
  609.  
  610.   /* runs throught the list of sectors belonging to a nation
  611.      and does things like reproduction and such.
  612.    */
  613. docivilians(np)
  614.      Snation *np;
  615. {
  616.   int current, born, died, tborn, tdied, rep, mort, i, j;
  617.   Ssector *sp;
  618.   struct pt_list *lp;
  619.  
  620.   rep  = np->race.repro;
  621.   mort = np->race.mortality;
  622.   tborn = tdied = 0;
  623.   lp = np->ptlist;
  624.   while (lp != NULL) {
  625.     sp = &world.map[lp->pt.x][lp->pt.y];
  626.     if (debug) printf ("Doing population in %d,%d\n", lp->pt.x, lp->pt.y);
  627.     current = sp->n_people;
  628.     born = (int) (current * rep  / 100.0);
  629.     died = (int) (current * mort / 100.0);
  630.     tborn += born;
  631.     tdied += died;
  632.     sp->n_people += born - died;
  633.       /* they might suffocate or drown */
  634.     if (sp->n_people > 0 && !good_altitude(sp, np)) {
  635.       printf("%d people %s in sector (%d, %d)\n", sp->n_people,
  636.          (sp->altitude < SEA_LEVEL) ? "drowned" : "suffocated",
  637.          sp->loc.x, sp->loc.y);
  638.       if (mailfile) {
  639.     fprintf(mailfile, "%d people %s in sector (%d, %d)\n", sp->n_people,
  640.         (sp->altitude < SEA_LEVEL) ? "drowned" : "suffocated",
  641.         xrel(sp->loc.x, sp->loc.y, np->capital),
  642.         yrel(sp->loc.x, sp->loc.y, np->capital) );
  643.       }
  644.       sp->n_people = 0;
  645.     }
  646. /* Old civ movement code.  Has been replaced.
  647.     for (i=sp->loc.x-1; i<=sp->loc.x+1; i++)
  648.       for (j=sp->loc.y-1; j<=sp->loc.y+1; j++) { 
  649.     if (world.map[(*wrapx)(i,j)][(*wrapy)(i,j)].owner == np->id)
  650.       movepeople(np, sp->loc.x, sp->loc.y, (*wrapx)(i,j), (*wrapy)(i,j));
  651.       }
  652. */
  653.     lp = lp->next;
  654.   }
  655.   clear_work_data(); /* Setup for moving */
  656.   switch(np->opts->civ_movemode) {
  657.     case 1: { move_people_restrict(np); break; }
  658.     case 2: { move_people_free(np); break; }
  659.     default: { /* the default (0) is to not move at all */; }
  660.   }
  661.   if (mailfile) {
  662.     fprintf(mailfile,
  663.      "There were %d births and %d deaths, for a population change of %d\n",
  664.      tborn, tdied, tborn-tdied);
  665.     fprintf(mailfile, "Your nation now has %d civilians\n", get_n_civil(np));
  666.   }
  667. }
  668.  
  669. movepeople(np, a, b, x, y)
  670. /* This routine is outdated and should be removed */
  671.      Snation *np;
  672.      int a, b, x, y;
  673. {
  674.   int p1, p2, pt2, moved, des1, des2;
  675.  
  676.   if ((a != x || b != y) && world.map[x][y].owner == world.map[a][b].owner) {
  677. /*    des1 = max(0,sect_desire(np, a, b));
  678.     des2 = max(0,sect_desire(np, x, y));
  679. */
  680.       /* desireability = % of people employed */
  681.     des1 = emp_desire(np, a, b);
  682.     des2 = emp_desire(np, x, y);
  683.     p1 = world.map[a][b].n_people;
  684.     p2 = world.map[x][y].n_people;
  685. /*    pt2 = (des2*(p1+p2))/(des1+des2); /* Potential change in p2 */
  686.  
  687. /*    moved = (pt2 - p2)/4; /* Move 1/4 of potential change to p2 */
  688. /*    moved /= 4;            /* make even fewer people move */
  689.     moved = (p1*(100-des1))/400 - (p2*(100-des2))/400;
  690.     moved = min(moved, p1);
  691.       /* hold it!! we cannot move people underwater without bubbles */
  692.     if (!good_altitude(&world.map[a][b], np)
  693.     || !good_altitude(&world.map[x][y], np)) {
  694.       moved = 0;
  695.     }
  696.     p2 += moved;
  697.     p1 -= moved;
  698.     world.map[a][b].n_people = p1;
  699.     world.map[x][y].n_people = p2;
  700.     if (debug) printf ("Moved %d people from %d,%d to %d,%d\n", moved, a, b, x, y);
  701.   }
  702. }
  703.  
  704. domoney(np)
  705.      Snation *np;
  706. {
  707.   int temp;
  708.  
  709.   temp = np->money;
  710.   np->money = next_thon_money(np);
  711.     temp / 100;
  712.  
  713.   if (mailfile) fprintf(mailfile, "Your net MONEY change is %d, bringing your total to %d\n", np->money-temp, np->money);
  714. }
  715.  
  716.  
  717. dometal(np)
  718.      Snation *np;
  719. {
  720.   int temp;
  721.  
  722.   temp = np->metal;
  723.   np->metal = next_thon_metal(np);
  724.  
  725.   if (mailfile) fprintf(mailfile, "Your net METAL change is %d, bringing your total to %d\n", np->metal-temp, np->metal);
  726. }
  727.  
  728.   /* calculates the new amount of jewels a nation has,
  729.      and if it is negative, it kills off some mages
  730.    */
  731. dojewels(np)
  732.      Snation *np;
  733. {
  734.   int temp;
  735.   Sarmy *ap, *get_first_mage();
  736.   Ssector *sp;
  737.  
  738.   temp = np->jewels;
  739.  
  740.   np->jewels = next_thon_jewels(np);
  741.  
  742.   while (np->jewels < 0) {
  743.     if ((ap = get_first_mage (np)) == NULL) {
  744.       break;
  745.     }
  746.     sp = &world.map[ap->pos.x][ap->pos.y];
  747.     printf ("\ndeleting mage %d\n", ap->id);
  748.  
  749.     if (mailfile) {
  750.       fprintf (mailfile,
  751.            "\nYou lost your mage %d because you had no jewels...\n",
  752.            ap->id);
  753.     }
  754.  
  755.     delete_army_sector (sp, ap);
  756.     delete_army_nation (np, ap);
  757.     np->jewels += MAGE_JEWELS_MAINT;
  758.   }
  759.  
  760.   /* now we have the final data on jewels: report it to mail file */
  761.   if (mailfile) {
  762.     fprintf(mailfile,
  763.         "Your net JEWEL change is %d, bringing your total to %d\n",
  764.         np->jewels-temp, np->jewels);
  765.   }
  766. }
  767.  
  768.  
  769.   /* calculate the new amount of food.  also takes care of starving */
  770. dofood(np)
  771.      Snation *np;
  772. {
  773.   int n_should_starve, n_starved, n_sold_starved;
  774.   int oldfood, n_civil, n_sold, x;
  775.   double starved_fraction;
  776.   Ssector *sp;
  777.   struct pt_list *ptlist = np->ptlist;
  778.   Sarmy *ap, *next;        /* for army starvation */
  779.   struct argument args[N_EXEC_ARGS];
  780.   char s[EXECLEN];
  781.  
  782.   n_civil = get_n_civil(np);
  783.   n_sold = get_n_soldiers(np);
  784.  
  785.   oldfood = np->food;
  786.   np->food += calc_food(np) - calc_expend_food(np);
  787.   if (mailfile) {
  788.     if (oldfood == np->food)
  789.       fprintf(mailfile, "Your farmers produced as much food as was needed\n");
  790.     else if (oldfood < np->food) {
  791.       fprintf(mailfile,    "Your farmers produced more food than was consumed\n");
  792.       fprintf(mailfile, "Your food in storage increased %d tons, to %d\n",
  793.           np->food-oldfood, np->food);
  794.     } else if (oldfood > np->food) {
  795.       fprintf(mailfile,
  796.           "Your farmers did not produce enough to feed everyone\n");
  797.       if (np->food >= 0) {
  798.     fprintf(mailfile,
  799.         "%d tons of food were used from storage, leaving %d tons\n",
  800.         oldfood-np->food, np->food);
  801.       } else {
  802.     fprintf(mailfile, "Your remaining storage, %d tons, was used up\n",
  803.            oldfood);
  804.       }
  805.     }
  806.   }
  807.   if (np->food < 0) {
  808.     printf("people starving in nation %s\n", np->name);
  809.       /* all those in cities who cannot eat starve */
  810.     n_should_starve = - (int) (np->food / EAT);
  811.     if (n_civil == 0) {
  812.       starved_fraction = 0;
  813.     } else {
  814.       starved_fraction = (1.0*n_should_starve)/(1.0*get_n_civil(np));
  815.     }
  816.       
  817.     if (starved_fraction > 1.0) {
  818.       starved_fraction = 1.0;
  819.     }
  820.     n_starved = 0;
  821.     while (ptlist != NULL) {
  822.       sp = &world.map[ptlist->pt.x][ptlist->pt.y];
  823.     n_starved += (int) (starved_fraction*sp->n_people);
  824.     sp->n_people -= (int) (starved_fraction*sp->n_people);
  825.     if (sp->n_people < 0) {
  826.       sp->n_people = 0;
  827.     }
  828.       ptlist = ptlist->next;
  829.     }
  830.     if (mailfile) {
  831.       fprintf(mailfile,
  832.       "%d people starve in your %d sectors, leaving %d surviving civilians.\n",
  833.            n_starved, np->n_sects, get_n_civil(np));
  834.     }
  835.       /* if there is still not enough food, starve soldiers */
  836.     if (n_should_starve > n_civil) {
  837.       n_sold_starved = (int) (n_should_starve-n_starved)/SOLD_EAT_FACTOR;
  838.     } else {
  839.       n_sold_starved = 0;
  840.     }
  841.     
  842.     if (get_n_soldiers(np) == 0) {
  843.       starved_fraction = 0;
  844.     } else {
  845.       starved_fraction = (1.0*n_sold_starved)/(1.0*get_n_soldiers(np));
  846.     }
  847.     if (starved_fraction > 1.0) {
  848.       starved_fraction = 1.0;
  849.     }
  850.     if (n_sold_starved > 0) {
  851.       if (mailfile) {
  852.     fprintf(mailfile,
  853.         "%d of your soldiers will starve too\n", n_sold_starved);
  854.       }
  855.       ap = np->armies;
  856.       while (ap && n_sold_starved > 0) {
  857.     x = starved_fraction*ap->n_soldiers;
  858.     ap->n_soldiers -= x;
  859.     n_sold_starved -= x;
  860.     if (x > 0 && mailfile) {
  861.       fprintf(mailfile,"in army %d, %d soldiers starve\n", ap->id, x);
  862.     }
  863.     next = ap->next;
  864.     if (ap->n_soldiers <= 0) {
  865.       sprintf(s, "ADISBAND:%d\n", ap->id);
  866.       parse_exec_line(s,args);
  867.       run_exec_line(np,args);
  868.     }
  869.     ap = next;
  870.       }
  871.     }
  872.     np->food = 0;
  873.   }
  874. }
  875.  
  876. cleanup()
  877. {
  878.   /* not much to do here */
  879. }
  880.  
  881. clean_exit()
  882. {
  883.   del_master_lock();
  884. };
  885.  
  886.   /* reads in the cargo file, then it gives the recipient
  887.      nation all the stuff.  if there is an army, it reads
  888.      in that army and inserts it into the sector and nation
  889.    */
  890. docargos()
  891. {
  892.   Scargo cargo;            /* the cargo that is being traded */
  893.   int from_id, to_id;
  894.   Snation *from_np, *to_np;
  895.   char mailname[NAMELEN];
  896.   FILE *fp, *fopen(), *mailf, *newsf;
  897.   Sarmy army;            /* was an army traded? */
  898.   Ssector *traded_sp;        /* was a sector traded? */
  899.   Ssector *sp;            /* on which sector does it happen? */
  900.   int x, y;            /* location of the trade */
  901.   char * contents ();        /* returns string of cargo_contents */
  902.  
  903.   if ((fp = fopen(CARGO_FILE, "r")) == NULL) {
  904.     printf("No cargo file\n");
  905.     return;
  906.   }
  907.   critical();
  908.   while (fread(&x, sizeof(int), 1, fp) > 0) {
  909.     fread(&y, sizeof(int), 1, fp);
  910.     fread(&from_id, sizeof(int), 1, fp);
  911.     fread(&to_id, sizeof(int), 1, fp);
  912.     from_np = &world.nations[from_id];
  913.     to_np = &world.nations[to_id];
  914.     fread(&cargo, sizeof(Scargo), 1, fp);
  915.       /* send mail to the donor, if it does not go to root */
  916.     if (to_id != 0) {
  917.       if (gets_mail(&world.nations[from_id])) {
  918.     sprintf(mailname, "mail%d", from_id);
  919.     mailf = fopen(mailname, "a");
  920.       } else {mailf = NULL; }
  921.       if (mailf) {
  922.     fprintf(mailf,
  923.         "Cargo given by %s to %s:\n", from_np->name, to_np->name);
  924.     fprintf(mailf,"\tCargo=%s\n",
  925.         contents (cargo.money, cargo.metal, cargo.jewels,
  926.               cargo.food, cargo.people, cargo.army,
  927.               &cargo.title, 0));
  928.     fclose(mailf);
  929.       }
  930.         /* send mail to the recipient */
  931.       if (gets_mail(&world.nations[to_id])) {
  932.     sprintf(mailname, "mail%d", to_id);
  933.     mailf = fopen(mailname, "a");
  934.       } else {mailf = NULL; }
  935.       if (mailf) {
  936.     fprintf(mailf,
  937.         "Cargo given by %s to %s:\n", from_np->name, to_np->name);
  938.     fprintf(mailf,"\tCargo=%s\n",
  939.         contents (cargo.money, cargo.metal, cargo.jewels,
  940.               cargo.food, cargo.people, cargo.army,
  941.               &cargo.title, 0));
  942.     fclose(mailf);
  943.     printf("wrote to mail files about cargo\n");
  944.       }
  945.     }
  946.     if (debug) {
  947.       printf("Got a cargo from nation %d to nation %d\n", from_id, to_id);
  948.       printf("\tCargo=%s\n",
  949.          contents (cargo.money, cargo.metal, cargo.jewels,
  950.                cargo.food, cargo.people, cargo.army,
  951.                &cargo.title, 0));
  952.     }
  953.     fflush(stdout);
  954.     to_np->money += cargo.money;
  955.     to_np->metal += cargo.metal;
  956.     to_np->jewels += cargo.jewels;
  957.     to_np->food += cargo.food;
  958.       /* put people in the sector */
  959.     sp = &world.map[x][y];
  960.     sp->n_people += cargo.people;
  961.       /* if an army is there, read it in from the file */
  962.     if (cargo.army != -1) {
  963.       fread(&army, sizeof(Sarmy), 1, fp);
  964.       army.owner = to_np->id;
  965.       army.flags &= ~AF_IN_TRANSPORT;
  966.       insert_army_nation(to_np, &army, -1);
  967.       ++to_np->n_armies;
  968.       insert_army_sector(sp, &army);
  969.     }
  970.       /* if there is a sector, give it to the new nation */
  971.     if (cargo.title.x != -1 && cargo.title.y != -1) {
  972.       Ssector *sp = &world.map[cargo.title.x][cargo.title.y];
  973.       subtsector(from_np, cargo.title.x, cargo.title.y);
  974.       addsector(to_np, cargo.title.x, cargo.title.y);
  975.       sp->flags &= ~SF_TRADED;
  976.     }
  977.   }
  978.   fclose(fp);
  979.   unlink(CARGO_FILE);
  980.   noncritical();
  981. }
  982.  
  983.   /* update the nation's spy values */
  984. dospy(np, mailfile)
  985.      Snation *np;
  986.      FILE *mailfile;
  987. {
  988.   int stealth = np->race.stealth;
  989.  
  990.   np->spy += stealth * (sqrt(1.0 * np->spy_r_d * calc_revenue(np) / 100 +
  991.                  np->cur_spy_r_d * np->money / 100)) *
  992.                  SPY_MONEY_FACTOR;
  993.   np->secrecy += (stealth*stealth) * 
  994.     (sqrt (1.0*np->spy_r_d * calc_revenue(np) / 100 +
  995.        (np->cur_spy_r_d * np->money / 100)) * SPY_SECRECY_FACTOR);
  996. }
  997.  
  998. /* undo hanging spells, decrease the thons_left param */
  999. clear_h_spells()
  1000. {
  1001.   Sh_spell *h_spells;
  1002.   int i;
  1003.   struct argument exec_args[N_EXEC_ARGS];
  1004.  
  1005.   for (h_spells=hanging_spells; h_spells != NULL; h_spells = h_spells->next) {
  1006.     for (i = 0; i < h_spells->n_lines; ++i) {
  1007.       if (i % 2 == 1) {        /* odd number means undo */
  1008.     parse_exec_line(h_spells->lines[i], exec_args);
  1009.     run_exec_line(&world.nations[h_spells->nat_id], exec_args);
  1010.       }
  1011.     }
  1012.     if (h_spells->thons_left >= 0) {
  1013.       --h_spells->thons_left;
  1014.     }
  1015.   }
  1016. }
  1017.  
  1018.   /* critical() for the update/make/add is different from the game */
  1019. critical()
  1020. {
  1021.   signal(SIGINT, SIG_IGN);
  1022.   signal(SIGQUIT, SIG_IGN);
  1023. }
  1024. noncritical()
  1025. {
  1026.   signal(SIGINT, SIG_DFL);
  1027.   signal(SIGQUIT, SIG_DFL);
  1028. }
  1029.  
  1030.   /* posts some news articles of general interest */
  1031. post_statistics()
  1032. {
  1033.   FILE *tmp_fp, *fopen();
  1034.   char tmp_name[PATHLEN];
  1035.   char subj[100];
  1036.  
  1037.   /* a temporary file name for this news posting */
  1038. /*  tmp_name = tmpnam(NULL, "dominion"); */
  1039.   strcpy(tmp_name, "dominionXXXXXX");
  1040.   mktemp(tmp_name);
  1041.  
  1042.   if (strlen(tmp_name) == 0) {
  1043.     fprintf(stderr, "Error getting temp file name\n");
  1044.     return;
  1045.   }
  1046.   if ((tmp_fp = fopen(tmp_name, "w")) == NULL) {
  1047.     fprintf(stderr, "Error opening file %s for writing\n", tmp_name);
  1048.     return;
  1049.   }
  1050.   sprintf(subj, "statistics at thon %d", world.turn);
  1051.   fprintf(tmp_fp, "\nThere are %d active nations.\n", get_n_act_ntn(&world));
  1052.   fprintf(tmp_fp, "Average population: %d\n", get_avg_civil(&world));
  1053.   fprintf(tmp_fp, "Average soldiers:   %d\n", get_avg_soldiers(&world));
  1054.   fprintf(tmp_fp, "Average treasury:   %d\n", get_avg_money(&world));
  1055.   fprintf(tmp_fp, "Average metal:      %d\n", get_avg_metal(&world));
  1056.   fprintf(tmp_fp, "Average jewels:     %d\n", get_avg_jewels(&world));
  1057.   fprintf(tmp_fp, "Average food:       %d\n", get_avg_food(&world));
  1058.   fprintf(tmp_fp, "Average sectors:    %d\n", get_avg_sectors(&world));
  1059.   fprintf(tmp_fp, "World occupation:   %d%% of land\n",
  1060.       get_per_occu_land(&world));
  1061.   fprintf(tmp_fp, "                    %d%% of water\n",
  1062.       get_per_occu_water(&world));
  1063.   fclose(tmp_fp);
  1064.   post_news_file(tmp_name, NEWS_GROUP,subj,0);
  1065. }
  1066.  
  1067. init_work_data(xmax, ymax)
  1068. /*
  1069.    Allocate the memory for the temporary array the size of the world
  1070.    (with one extra for wrap around) for manipulation before scaling 
  1071. */
  1072. int xmax,ymax;
  1073. {
  1074.   int i;
  1075.   
  1076.   if ((work_data = (struct move_data **) malloc((xmax) * 
  1077.                            (sizeof(struct move_data *)))) == NULL)
  1078.   {
  1079.     mem_error();
  1080.   }
  1081.   for (i=0; i <xmax ; i++)
  1082.   {
  1083.     if ((work_data[i] = (struct move_data *) malloc((ymax) * 
  1084.                                   (sizeof(struct move_data)))) == NULL)
  1085.     {
  1086.       mem_error();
  1087.     }
  1088.   }
  1089. }
  1090.  
  1091. clear_work_data()
  1092. /* Clear the work_peop array */
  1093. {
  1094.   int x,y;
  1095.  
  1096.   for (x = 0 ; x < world.xmax ; x++)
  1097.   {
  1098.     for (y = 0 ; y < world.ymax ; y++)
  1099.     {
  1100.       work_data[x][y].moved = 0;
  1101.       work_data[x][y].adj = 0;
  1102.       work_data[x][y].des = 0.0;
  1103.     }
  1104.   }
  1105. }
  1106.  
  1107. #define MOVE_FREE 1
  1108.  
  1109. move_people_free(np)
  1110. Snation *np;
  1111. {
  1112.   struct pt_list *curr_pt;
  1113.   int tot_peop, tot_emp,x,y,moving,i,j,xx,yy;
  1114.   double race_factor, desire,divisor;
  1115.  
  1116.   race_factor = sqrt(world.nations[np->id].race.repro/10.0);
  1117.   curr_pt = np->ptlist;
  1118. /* Loop over every point the user has. */
  1119.   while (curr_pt != NULL)
  1120.   {
  1121.     if (!good_altitude(&world.map[curr_pt->pt.x][curr_pt->pt.y],np))
  1122.     {
  1123.       curr_pt = curr_pt->next;
  1124.       continue;
  1125.     }
  1126.     x = curr_pt->pt.x;
  1127.     y = curr_pt->pt.y; 
  1128.     work_data[x][y].des = desig_map[world.map[x][y].designation].max_employed;
  1129.     work_data[x][y].des *= race_factor;
  1130.     desire = (double)sect_desire(np,x,y);
  1131.     /* Determine the desireability of the sector */
  1132.     desire = (desire - 650.0)/1000.0;
  1133.     /* And have that modify the % of people wanting to live there */
  1134.     work_data[x][y].des *= (1.0 + desire);
  1135.     for (i = 0 ; i < (MOVE_FREE * 2) + 1  ; i++)
  1136.     {
  1137.       for (j = 0 ; j < (MOVE_FREE * 2) + 1 ; j++)
  1138.       {
  1139.         x = (*wrapx)(i+(curr_pt->pt.x-MOVE_FREE),j+(curr_pt->pt.y-MOVE_FREE));
  1140.         y = (*wrapy)(i+(curr_pt->pt.x-MOVE_FREE),j+(curr_pt->pt.y-MOVE_FREE));
  1141.         if (world.map[x][y].owner == np->id)
  1142.         { 
  1143.           work_data[curr_pt->pt.x][curr_pt->pt.y].adj++;
  1144.     }
  1145.       }
  1146.     }
  1147.     curr_pt = curr_pt->next;
  1148.   }    
  1149.   curr_pt = np->ptlist;
  1150.   while (curr_pt != NULL)
  1151.   {
  1152.     tot_peop = 0;  /* Sum up the total owned people in a 1 sector radius */
  1153.     tot_emp = 0;  /* Sum up the total available employment in a 1 sect rad */ 
  1154. /* If the sector cannot suport civilians, then we don't move to or from it */
  1155.     if (!good_altitude(&world.map[curr_pt->pt.x][curr_pt->pt.y],np))
  1156.     {
  1157.       curr_pt = curr_pt->next;
  1158.       continue;
  1159.     }
  1160. /* First loop over the neighboorhod and find totals */
  1161.     for (i = 0 ; i < (MOVE_FREE * 2) + 1  ; i++)
  1162.     {
  1163.       for (j = 0 ; j < (MOVE_FREE * 2) + 1 ; j++)
  1164.       {
  1165.         x = (*wrapx)(i+(curr_pt->pt.x-MOVE_FREE),j+(curr_pt->pt.y-MOVE_FREE));
  1166.         y = (*wrapy)(i+(curr_pt->pt.x-MOVE_FREE),j+(curr_pt->pt.y-MOVE_FREE));
  1167.         if (world.map[x][y].owner == np->id)
  1168.         { 
  1169.           /* Start with the number of people employable */
  1170.           tot_peop += world.map[x][y].n_people;
  1171.           tot_emp += work_data[x][y].des;
  1172.     }
  1173.       }
  1174.     }
  1175. /* Find the max divisor for this neighboorhood */
  1176.     divisor = 1.0;
  1177.     for (i = 0 ; i < (MOVE_FREE * 2) + 1  ; i++)
  1178.     {
  1179.       for (j = 0 ; j < (MOVE_FREE * 2) + 1 ; j++)
  1180.       {
  1181.         x = (*wrapx)(i+(curr_pt->pt.x-MOVE_FREE),j+(curr_pt->pt.y-MOVE_FREE));
  1182.         y = (*wrapy)(i+(curr_pt->pt.x-MOVE_FREE),j+(curr_pt->pt.y-MOVE_FREE));
  1183.         if (work_data[x][y].adj > divisor)
  1184.         {
  1185.           divisor = work_data[x][y].adj;
  1186.         }
  1187.       }
  1188.     }
  1189. /* Then distribute people over the neighboorhood. */
  1190.     for (i = 0 ; i < (MOVE_FREE * 2) + 1  ; i++)
  1191.     {
  1192.       for (j = 0 ; j < (MOVE_FREE * 2) + 1 ; j++)
  1193.       {
  1194.         x = (*wrapx)(i+(curr_pt->pt.x-MOVE_FREE),j+(curr_pt->pt.y-MOVE_FREE));
  1195.         y = (*wrapy)(i+(curr_pt->pt.x-MOVE_FREE),j+(curr_pt->pt.y-MOVE_FREE));
  1196. /* Again, only work with sectors owned.  No inter-national movement */
  1197.         if ((world.map[x][y].owner == np->id) && 
  1198.              good_altitude(&world.map[x][y],np))
  1199.         {
  1200. /*
  1201.    The percentage of modified available employment times the number of
  1202.    people available is the number of people who want to be in that sector 
  1203. */
  1204.           moving = (int)( (work_data[x][y].des/tot_emp) * tot_peop);
  1205.  
  1206. /* Then adjust for the people already in that sector */
  1207.           moving -= world.map[x][y].n_people;
  1208. /* 
  1209.   If we are working with a sector with N adjacent sectors, then we
  1210.   only move 1/N th of the people we'd like, since the other adjacent
  1211.   sectors may decide to all do the same thing.
  1212. */
  1213.           moving =(int)((double)moving/(double)divisor);
  1214. /*
  1215.    And lastly put the people into the array stating that they will be moving.
  1216.    this is important since all moves are considered before they see where
  1217.    everybody else is moving.
  1218. */
  1219.           work_data[x][y].moved += moving;
  1220.           work_data[curr_pt->pt.x][curr_pt->pt.y].moved -= moving;
  1221.     }
  1222.       }
  1223.     }
  1224.     curr_pt = curr_pt->next;
  1225.   }
  1226. /* Loop over all points again */
  1227.   curr_pt = np->ptlist;
  1228.   while (curr_pt != NULL)
  1229.   {
  1230.     x = curr_pt->pt.x;
  1231.     y = curr_pt->pt.y;
  1232. /* Now add all the movement of people to the state of the world */
  1233.     world.map[x][y].n_people += work_data[x][y].moved;
  1234.     work_data[x][y].moved = 0;
  1235. /* If we less than zero people (roundoff error happens) */
  1236.     if (world.map[x][y].n_people < 0)
  1237.     {
  1238.       if ((debug) || (world.map[x][y].n_people < -9))
  1239.       {
  1240.         fprintf(stderr,"Error: Point %d, %d has %d people\n",x,y,
  1241.                        world.map[x][y].n_people);
  1242.       }
  1243. /* Look around the neighboorhood for a place to get the people from */
  1244.       for (i=0 ; (i < (MOVE_FREE*2)+1) && (world.map[x][y].n_people < 0); i++)
  1245.       {
  1246.         for (j=0 ;(j < (MOVE_FREE*2)+1) && (world.map[x][y].n_people < 0); j++)
  1247.         {
  1248.           xx=(*wrapx)(i+(curr_pt->pt.x-MOVE_FREE),j+(curr_pt->pt.y-MOVE_FREE));
  1249.           yy=(*wrapy)(i+(curr_pt->pt.x-MOVE_FREE),j+(curr_pt->pt.y-MOVE_FREE));
  1250. /* If they have people to spare */
  1251.           if (world.map[xx][yy].n_people + work_data[xx][yy].moved > 0)
  1252.           {
  1253. /* Then we move as many as we can, up to as many as we need */
  1254.             moving = min(world.map[xx][yy].n_people + work_data[xx][yy].moved,
  1255.                          -1 * world.map[x][y].n_people);
  1256.             world.map[xx][yy].n_people -= moving;
  1257.             world.map[x][y].n_people += moving;
  1258.       }
  1259.     }
  1260.       }
  1261.     }
  1262. /* If we still have not enough people, then the algorithm is buggy */
  1263.     if (world.map[x][y].n_people < 0)
  1264.     {
  1265.        fprintf(stderr,"Error: Point %d, %d still has %d people\n",x,y,
  1266.                        world.map[x][y].n_people);
  1267.     }
  1268.     curr_pt = curr_pt->next;
  1269.   }
  1270. }
  1271.  
  1272. fill_work_data(np)
  1273. Snation *np;
  1274. {
  1275.   struct pt_list *curr_pt;
  1276.   double desire,race_factor;
  1277.   int x,y;
  1278.  
  1279.   race_factor = sqrt(world.nations[np->id].race.repro/10.0);
  1280.   curr_pt = np->ptlist;
  1281.   while (curr_pt != NULL)
  1282.   {
  1283.     if (!good_altitude(&world.map[curr_pt->pt.x][curr_pt->pt.y],np)) {
  1284.       curr_pt = curr_pt->next;
  1285.       continue;
  1286.     }
  1287.     x = curr_pt->pt.x;
  1288.     y = curr_pt->pt.y; 
  1289.     work_data[x][y].des = desig_map[world.map[x][y].designation].max_employed;
  1290.     work_data[x][y].des *= race_factor;
  1291. /* the adj holds the number of jobs available in that sector */
  1292.     work_data[x][y].adj = work_data[x][y].des - world.map[x][y].n_people;
  1293.     desire = (double)sect_desire(np,x,y);
  1294.     /* Determine the desireability of the sector */
  1295.     desire = (desire - 650.0)/1000.0;
  1296.     /* And have that modify the % of people wanting to live there */
  1297.     work_data[x][y].des *= (1.0 + desire);
  1298.     curr_pt = curr_pt->next;
  1299.   }    
  1300. }
  1301.  
  1302. #define MOVE_RESTR 2
  1303.  
  1304. move_the_people(np)
  1305. Snation *np;
  1306. {
  1307.   struct pt_list *curr_pt;
  1308.   int x,y, xx,yy,i,j, moving;
  1309.  
  1310.   curr_pt = np->ptlist;
  1311.   while (curr_pt != NULL)
  1312.   {
  1313.     x = curr_pt->pt.x;
  1314.     y = curr_pt->pt.y;
  1315. /* Now add all the movement of people to the state of the world */
  1316.     world.map[x][y].n_people += work_data[x][y].moved;
  1317.     work_data[x][y].moved = 0;
  1318. /* If we less than zero people (roundoff error happens) */
  1319.     if (world.map[x][y].n_people < 0)
  1320.     {
  1321.       if ((debug) || (world.map[x][y].n_people < -9))
  1322.       {
  1323.         fprintf(stderr,"Error: Point %d, %d has %d people\n",x,y,
  1324.                        world.map[x][y].n_people);
  1325.       }
  1326. /* Look around the neighboorhood for a place to get the people from */
  1327.       for (i=0;(i < (MOVE_RESTR*2)+1) && (world.map[x][y].n_people < 0); i++)
  1328.       {
  1329.         for (j=0;(j < (MOVE_RESTR*2)+1) && (world.map[x][y].n_people < 0); j++)
  1330.         {
  1331.           xx=(*wrapx)(i+(curr_pt->pt.x-MOVE_RESTR),
  1332.                                            j+(curr_pt->pt.y-MOVE_RESTR));
  1333.           yy=(*wrapy)(i+(curr_pt->pt.x-MOVE_RESTR),
  1334.                                            j+(curr_pt->pt.y-MOVE_RESTR));
  1335. /* If they have people to spare */
  1336.           if (world.map[xx][yy].n_people + work_data[xx][yy].moved > 0)
  1337.           {
  1338. /* Then we move as many as we can, up to as many as we need */
  1339.             moving = min(world.map[xx][yy].n_people + work_data[xx][yy].moved,
  1340.                          -1 * world.map[x][y].n_people);
  1341.             world.map[xx][yy].n_people -= moving;
  1342.             world.map[x][y].n_people += moving;
  1343.       }
  1344.     }
  1345.       }
  1346.     }
  1347. /* If we still have not enough people, then the algorithm is buggy */
  1348.     if (world.map[x][y].n_people < 0)
  1349.     {
  1350.        fprintf(stderr,"Error: Point %d, %d still has %d people\n",x,y,
  1351.                        world.map[x][y].n_people);
  1352.     }
  1353.     curr_pt = curr_pt->next;
  1354.   }
  1355. }
  1356.  
  1357. move_space_avail(np,curr_pt,peop,tot_emp,tot_peop)
  1358. Snation *np;
  1359. struct pt_list *curr_pt;
  1360. int tot_emp, *peop,tot_peop;
  1361. {
  1362.   struct pt_list *nhbd_list,*curr_plist;
  1363.   int moving,i,j,x,y,peop_left = *peop;
  1364.   double desire;
  1365.  
  1366.   nhbd_list = NULL;
  1367.   for (i = 0 ; i < (MOVE_RESTR * 2) + 1 ; i++) {
  1368.     for (j = 0 ; j < (MOVE_RESTR * 2) + 1 ; j++) {
  1369.       x = (*wrapx) (i+(curr_pt->pt.x-MOVE_RESTR),
  1370.                                       j+(curr_pt->pt.y-MOVE_RESTR));
  1371.       y = (*wrapy) (i+(curr_pt->pt.x-MOVE_RESTR),
  1372.                                       j+(curr_pt->pt.y-MOVE_RESTR));
  1373. /* Again, only work with sectors owned.  No inter-national movement */
  1374.       if ((world.map[x][y].owner == np->id) && good_altitude(
  1375.            &world.map[x][y],np) && ((i != j) || (i != MOVE_RESTR))) {
  1376.          moving = (work_data[x][y].adj * tot_peop / (2 *tot_emp));
  1377.          if (moving < 0) { moving = 0; }
  1378.          peop_left -= moving;
  1379.          work_data[x][y].moved += moving;
  1380.          add_to_plist(&nhbd_list, x, y);
  1381.       }
  1382.     }
  1383.   }
  1384.   sort_ptlist(&nhbd_list);
  1385.   curr_plist = nhbd_list;
  1386.   while ((curr_plist != NULL) && (peop_left != 0))
  1387.   {
  1388.     x = curr_plist->pt.x;
  1389.     y = curr_plist->pt.y;
  1390. /* First figure out how many were moved here already */
  1391.     moving = (work_data[x][y].adj * tot_peop / (2 *tot_emp));
  1392. /* Then figure out how many more can move there. */
  1393.     moving = work_data[x][y].adj - moving;
  1394.     if (moving < 0 ) { moving = 0 ; }
  1395.     if (moving > peop_left) {
  1396.       moving = peop_left;
  1397.       peop_left = 0;
  1398.     } else {
  1399.       peop_left -= moving; 
  1400.     }
  1401.     work_data[x][y].moved += moving;
  1402.     curr_plist = curr_plist->next;
  1403.   }
  1404.   free_ptlist(&nhbd_list);
  1405.   *peop = peop_left;
  1406. }
  1407.  
  1408. move_somespace_avail(np,curr_pt,peop)
  1409. Snation *np;
  1410. struct pt_list *curr_pt;
  1411. int *peop;
  1412. {
  1413.   int i,j,x,y,moving,peop_left = *peop;
  1414.  
  1415.   for (i = 0 ; i < (MOVE_RESTR * 2) + 1 ; i++) {
  1416.     for (j = 0 ; j < (MOVE_RESTR * 2) + 1 ; j++) {
  1417.       x = (*wrapx)(i+(curr_pt->pt.x-MOVE_RESTR),j+(curr_pt->pt.y-MOVE_RESTR));
  1418.       y = (*wrapy)(i+(curr_pt->pt.x-MOVE_RESTR),j+(curr_pt->pt.y-MOVE_RESTR));
  1419.       if ((world.map[x][y].owner == np->id) && good_altitude(
  1420.            &world.map[x][y],np) && ((i != j) || (i != MOVE_RESTR))) {
  1421.          moving = work_data[x][y].adj;
  1422.          if (moving < 0 ) { moving = 0; }
  1423.          if (moving > peop_left ) {
  1424.            moving = peop_left;
  1425.            peop_left = 0; 
  1426.          } else {
  1427.            peop_left -= moving;
  1428.          }
  1429.          work_data[x][y].moved += moving;
  1430.       }
  1431.     }
  1432.   }
  1433.   *peop = peop_left;
  1434. }
  1435.  
  1436. move_people_restrict(np)
  1437. Snation *np;
  1438. {
  1439.   struct pt_list *curr_pt;
  1440.   int tot_peop, peop_left, tot_emp,x,y,moving,i,j,xx,yy;
  1441.   double race_factor, desire,divisor;
  1442.   struct pt_list *nhbd_list, *curr_plist;
  1443.  
  1444.   race_factor = sqrt(world.nations[np->id].race.repro/10.0);
  1445.   fill_work_data(np);
  1446. /* Loop over every point the user has. */
  1447.   curr_pt = np->ptlist;
  1448.   while (curr_pt != NULL)
  1449.   {
  1450.     tot_emp = 0;  /* Sum up the total available employment in a 1 sect rad */ 
  1451. /* If the sector cannot suport civilians, then we don't move to or from it */
  1452.     if (!good_altitude(&world.map[curr_pt->pt.x][curr_pt->pt.y],np)) {
  1453.       curr_pt = curr_pt->next;
  1454.       continue;
  1455.     }
  1456. /* If there are no unemployed people here, then go on. */
  1457.     if ((tot_peop = work_data[curr_pt->pt.x][curr_pt->pt.y].adj) >= 0) {
  1458.       curr_pt = curr_pt->next;
  1459.       continue;
  1460.     }
  1461.     tot_peop *= -1;
  1462.     peop_left = tot_peop;
  1463.     work_data[curr_pt->pt.x][curr_pt->pt.y].moved -= peop_left; 
  1464.  
  1465. /* First loop over the neighboorhod and find totals */
  1466.     for (i = 0 ; i < (MOVE_RESTR * 2) + 1  ; i++)
  1467.     {
  1468.       for (j = 0 ; j < (MOVE_RESTR * 2) + 1 ; j++)
  1469.       {
  1470.         x =(*wrapx)(i+(curr_pt->pt.x-MOVE_RESTR),j+(curr_pt->pt.y-MOVE_RESTR));
  1471.         y =(*wrapy)(i+(curr_pt->pt.x-MOVE_RESTR),j+(curr_pt->pt.y-MOVE_RESTR));
  1472.         if ((world.map[x][y].owner == np->id) && ((i!=j) || (i != MOVE_RESTR)))
  1473.         { 
  1474.           /* Start with the number of available jobs */
  1475.           if (work_data[x][y].adj > 0) {
  1476.             tot_emp += work_data[x][y].adj;
  1477.       }
  1478.     }
  1479.       }
  1480.     }
  1481.     if (tot_emp > 0) {
  1482.       if (tot_emp > tot_peop) {
  1483.         move_space_avail(np,curr_pt,&peop_left,tot_emp,tot_peop);
  1484.       } else {
  1485.         move_somespace_avail(np,curr_pt,&peop_left);
  1486.       }
  1487.     }
  1488.     if (peop_left > 0) {
  1489.       tot_peop = peop_left; 
  1490.       desire = 0.0;
  1491.       for (i = 0 ; i < (MOVE_RESTR * 2) + 1 ; i++) {
  1492.         for (j = 0 ; j < (MOVE_RESTR * 2) + 1 ; j++) {
  1493.           x =(*wrapx)(i+(curr_pt->pt.x-MOVE_RESTR),
  1494.                                           j+(curr_pt->pt.y-MOVE_RESTR));
  1495.           y =(*wrapy)(i+(curr_pt->pt.x-MOVE_RESTR),
  1496.                                           j+(curr_pt->pt.y-MOVE_RESTR));
  1497.           if ((world.map[x][y].owner == np->id) && good_altitude(
  1498.                &world.map[x][y],np) && ((i != j) || (i != MOVE_RESTR))) {
  1499.             desire += work_data[x][y].des;
  1500.           }
  1501.         }
  1502.       }
  1503.       for (i = 0 ; i < (MOVE_RESTR * 2) + 1 ; i++) {
  1504.         for (j = 0 ; j < (MOVE_RESTR * 2) + 1 ; j++) {
  1505.           x =(*wrapx)(i+(curr_pt->pt.x-MOVE_RESTR),
  1506.                                           j+(curr_pt->pt.y-MOVE_RESTR));
  1507.           y =(*wrapy)(i+(curr_pt->pt.x-MOVE_RESTR),
  1508.                                           j+(curr_pt->pt.y-MOVE_RESTR));
  1509.           if ((world.map[x][y].owner == np->id) && good_altitude(
  1510.                &world.map[x][y],np) && ((i != j) || (i != MOVE_RESTR))) {
  1511.             moving = (int)((work_data[x][y].des * tot_peop)/desire);
  1512.             if (moving < 0 ) { moving = 0; } 
  1513.             peop_left -= moving;
  1514.             work_data[x][y].moved += moving;
  1515.           }
  1516.         }
  1517.       }
  1518.       work_data[curr_pt->pt.x][curr_pt->pt.y].moved += peop_left;
  1519.     }
  1520.     curr_pt = curr_pt->next;
  1521.   }
  1522.   move_the_people(np);
  1523. /* Loop over all points again */
  1524. }
  1525.  
  1526. int sort_ptlist(ptlist)
  1527. struct pt_list **ptlist;
  1528. {
  1529.   struct pt_list *pnext, *pprev, *pcurr, *ptemp;
  1530.   int switched;
  1531.  
  1532.   if (*ptlist == NULL) { return; }
  1533.   if ((*ptlist)->next == NULL) {return; }
  1534.   do {
  1535.     switched = 0;
  1536.     pcurr = *ptlist;
  1537.     pnext = pcurr->next;
  1538.     if (work_data[pcurr->pt.x][pcurr->pt.y].des <
  1539.                   work_data[pnext->pt.x][pnext->pt.y].des) {
  1540.       switched++;
  1541.       ptemp = pnext->next;
  1542.       *ptlist = pnext;
  1543.       (*ptlist)->next = pcurr;
  1544.       (*ptlist)->next->next = ptemp;
  1545.     }
  1546.     pprev = *ptlist;
  1547.     pcurr = (*ptlist)->next;
  1548.     while (pcurr->next != NULL) {
  1549.       pnext = pcurr->next;
  1550.       if (work_data[pcurr->pt.x][pcurr->pt.y].des <
  1551.                          work_data[pnext->pt.x][pnext->pt.y].des) {
  1552.         ptemp = pnext->next;
  1553.         pprev->next = pnext;
  1554.         pprev->next->next = pcurr;
  1555.         pprev->next->next->next = ptemp;
  1556.         switched++;
  1557.       }
  1558.       pprev = pprev->next;
  1559.       pcurr = pprev->next;
  1560.     }
  1561.   } while (switched > 0) ;
  1562.   return;
  1563. }
  1564.  
  1565. free_ptlist(ptlist)
  1566. struct pt_list **ptlist;
  1567. {
  1568.   struct pt_list *pt_list = *ptlist, *tmp_pt;
  1569.   
  1570.   while (pt_list != NULL) {
  1571.     tmp_pt = pt_list->next;
  1572.     free(pt_list);
  1573.     pt_list = tmp_pt;
  1574.   }
  1575. }
  1576.  
  1577. add_to_plist(ptlist, x, y)
  1578. struct pt_list **ptlist;
  1579. int x,y;
  1580. {
  1581.   struct pt_list *ptemp = *ptlist; 
  1582.  
  1583.   if (*ptlist == NULL) {
  1584.     if ((*ptlist = (struct pt_list *)malloc(sizeof(struct pt_list)))== NULL) {
  1585.       mem_error();
  1586.     }
  1587.     (*ptlist)->pt.x = x;
  1588.     (*ptlist)->pt.y = y;
  1589.     (*ptlist)->next = NULL;
  1590.     return;
  1591.   }
  1592.   while (ptemp->next != NULL) {
  1593.     ptemp = ptemp->next;
  1594.   }
  1595.   if ((ptemp->next = (struct pt_list *)malloc(sizeof(struct pt_list)))
  1596.             == NULL) { mem_error(); }
  1597.   ptemp = ptemp->next;
  1598.   ptemp->pt.x = x;
  1599.   ptemp->pt.y = y;
  1600.   ptemp->next = NULL;
  1601.   return;
  1602. }
  1603.     
  1604. setup_user_arr(num)
  1605. int num;
  1606. {
  1607.   if ((temp_users = (Suser *)malloc(num * sizeof(Suser))) == NULL) {
  1608.     mem_error();
  1609.   }
  1610. }
  1611.  
  1612. copy_to_user_arr(val)
  1613. int val;
  1614. {
  1615.   temp_users[val] = user;
  1616. }
  1617.  
  1618. copy_from_user_arr(val)
  1619. int val;
  1620. {
  1621.   user = temp_users[val];
  1622. }
  1623.  
  1624.