home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / x / xconq55.zip / xc5.5 / side.c < prev    next >
C/C++ Source or Header  |  1992-03-11  |  15KB  |  597 lines

  1. /* Copyright (c) 1987, 1988  Stanley T. Shebs. */
  2. /* This program may be used, copied, modified, and redistributed freely */
  3. /* for noncommercial purposes, so long as this notice remains intact. */
  4.  
  5. /* The "side" structure is the repository of information about players. */
  6. /* Surprisingly, there is not much code to manipulate side directly.  */
  7. /* Viewing code is somewhat tricky, since any hex may be viewed by any */
  8. /* number of sides at once. */
  9.  
  10. #include "config.h"
  11. #include "misc.h"
  12. #include "dir.h"
  13. #include "period.h"
  14. #include "side.h"
  15. #include "unit.h"
  16. #include "map.h"
  17. #include "global.h"
  18.  
  19. Side neutral_placeholder; /* just has a pointer to next side and the neutral units. */
  20. Side sides[MAXSIDES];  /* array containing all sides (not very many) */
  21. Side *sidelist;        /* head of list of all sides */
  22. Side *tmpside;         /* temporary used in many places */
  23.  
  24. int numsides;          /* number of sides in the game */
  25.  
  26. char *reasonnames[] = REASONNAMES;  /* names of columns in unit record */
  27.  
  28. extern x_command();
  29.  
  30. /* Reset any side structures that need it. */
  31.  
  32. init_sides()
  33. {
  34.     int i;
  35.  
  36.     for (i = 0; i < MAXSIDES; ++i) {
  37.     sides[i].name = NULL;
  38.     sides[i].laststarttime = 0;
  39.     sides[i].unithead = NULL;
  40.     }
  41.     sidelist = NULL;
  42.     numsides = 0;
  43. }
  44.  
  45. /* Create an object representing a side. Checking to make sure all human */
  46. /* players have displays has been done by now, so problems mean bugs. */
  47.  
  48. Side *
  49. create_side(name, person, host)
  50. char *name, *host;
  51. bool person;
  52. {
  53.     int s, i;
  54.     Side *newside;
  55.  
  56.     /* Can't have humans without displays */
  57.     if (person && host == NULL) abort();
  58.     if (name == NULL) name = "???";
  59.     for (s = 0; s < MAXSIDES; ++s) {
  60.     if (sides[s].name == NULL) {
  61.         newside = &(sides[s]);
  62.         newside->name = copy_string(name);
  63.         newside->humanp = person;
  64.         if (host == NULL || strcmp(host, "*") == 0) {
  65.         newside->host = NULL;
  66.         } else {
  67.         newside->host = copy_string(host);
  68.         }
  69.         newside->lost = FALSE;
  70.         for_all_unit_types(i) {
  71.         newside->counts[i] = 1;
  72.         newside->units[i] = 0;
  73.         newside->building[i] = 0;
  74.         }
  75.         for_all_resource_types(i) {
  76.         newside->resources[i] = 0;
  77.         }
  78.         newside->showmode = BORDERHEX; /* overridden by X11.c
  79.                           get_resources() */
  80.         newside->itertime = 100;
  81.         newside->startbeeptime = DEFAULT_STARTBEEPTIME;
  82.         newside->view =
  83.         (viewdata *) malloc(world.width*world.height*sizeof(viewdata));
  84. #ifdef PREVVIEW
  85.         newside->prevview =
  86.         (viewdata *) malloc(world.width*world.height*sizeof(viewdata));
  87.         newside->viewtimestamp =
  88.         (short *) malloc(world.width*world.height*sizeof(short));
  89. #endif
  90.         newside->coverage =
  91.         (short *) malloc(world.width*world.height*sizeof(short));
  92.         init_view(newside);
  93.         newside->deadunits = NULL;
  94.         newside->graphical = GRAPHICAL;
  95.         newside->display = 0L;
  96.         newside->bottom_note = 0;
  97.         init_requests(newside);
  98.         link_in_side(newside);
  99.         ++numsides;
  100.         return newside;
  101.     }
  102.     }
  103.     fprintf(stderr, "Cannot have more than %d sides total!\n", MAXSIDES);
  104.     abort();
  105. }
  106.  
  107. /* Add the new side to the end of the list of sides - this keeps our */
  108. /* list traversals going from top to bottom (the things we do to keep */
  109. /* users happy...). */
  110.  
  111. link_in_side(side)
  112. Side *side;
  113. {
  114.     Side *head, *last;
  115.  
  116.     if (sidelist == NULL) {
  117.     sidelist = side;
  118.     neutral_placeholder.next = side;
  119.     } else {
  120.     for_all_sides(head) {
  121.         if (head->next == NULL) last = head;
  122.     }
  123.     last->next = side;
  124.     }
  125.     side->next = NULL;
  126.     side->unithead = create_unit(-1, (char *) NULL);
  127. }
  128.  
  129. /* Initialize basic viewing structures for a side, in preparation for the */
  130. /* placement of units. */
  131.  
  132. init_view(side)
  133. Side *side;
  134. {
  135.     int x, y, cov;
  136.     viewdata seen;
  137.  
  138.     cov = (period.allseen ? 100 : 0);
  139.     seen = (FALSE /*(period.allseen || world.known)*/ ? EMPTY : UNSEEN);
  140.     for (x = 0; x < world.width; ++x) {
  141.     for (y = 0; y < world.height; ++y) {
  142.         set_cover(side, x, y, cov);
  143.         side_view(side, x, y) = seen;
  144. #ifdef PREVVIEW
  145.         side_prevview(side, x, y) = UNSEEN;
  146. #endif
  147.     }
  148.     }
  149. }
  150.  
  151. /* Given a side, get its relative position in array of sides (the "number"). */
  152. /* Neutrals are -1, for lack of any better ideas. */
  153.  
  154. side_number(side)
  155. Side *side;
  156. {
  157.     return (side == NULL ? MAXSIDES : (side - sides));
  158. }
  159.  
  160. /* The inverse function - given a number, figure out which side it is. */
  161. /* Return NULL for failure; hopefully callers will check on this! */
  162.  
  163. Side *
  164. side_n(n)
  165. int n;
  166. {
  167.     return ((n >= 0 && n < numsides) ? &sides[n] : NULL);
  168. }
  169.  
  170. /* Put the given unit on the given side, without all the fancy effects. */
  171. /* Important to handle neutrals, because this gets called during init. */
  172.  
  173. extern bool sidecountsread;
  174.  
  175. assign_unit_to_side(unit, side)
  176. Unit *unit;
  177. Side *side;
  178. {
  179.     unit->side = side;
  180.     delete_unit(unit);  /* Make sure it is not in any list now. */
  181.     if (side != NULL)
  182.       insert_unit(side->unithead, unit);
  183.     else insert_unit(neutral_placeholder.unithead, unit);
  184.     if (!sidecountsread)
  185.     unit->number = (side != NULL ? (side->counts)[unit->type]++ : 0);
  186. }
  187.  
  188. /* Being at war requires only ones of the sides to consider itself so. */
  189.  
  190. enemy_side(s1, s2)
  191. Side *s1, *s2;
  192. {
  193.     if (s1 == s2) return FALSE;
  194.     return (s1 != NULL && s2 != NULL &&
  195.         (s1->attitude[side_number(s2)] <= ENEMY ||
  196.          s2->attitude[side_number(s1)] <= ENEMY));
  197. }
  198.  
  199. /* A formal alliance requires the agreement of both sides. */
  200.  
  201. allied_side(s1, s2)
  202. Side *s1, *s2;
  203. {
  204.     if (s1 == s2) return TRUE;
  205.     return (s1 != NULL && s2 != NULL &&
  206.         s1->attitude[side_number(s2)] >= ALLY &&
  207.         s2->attitude[side_number(s1)] >= ALLY);
  208. }
  209.  
  210. /* Neutralness is basically anything else. */
  211.  
  212. neutral_side(s1, s2)
  213. Side *s1, *s2;
  214. {
  215.     return (!enemy_side(s1, s2) && !allied_side(s1, s2));
  216. }
  217.  
  218. /* Formal declarations of war need to do a transitive closure, as part of */
  219. /* dragging allies in. */
  220.  
  221. declare_war(side1, side2)
  222. Side *side1, *side2;
  223. {
  224.     Side *side3;
  225.  
  226.     notify_all("The %s and the %s have declared war!!",
  227.            copy_string(plural_form(side1->name)),
  228.            copy_string(plural_form(side2->name)));
  229.     make_war(side1, side2);
  230.     for_all_sides(side3) {
  231.     if (allied_side(side3, side1)) make_war(side3, side2);
  232.     if (allied_side(side3, side2)) make_war(side3, side1);
  233.     }
  234. }
  235.  
  236. /* Internal non-noisy function. */
  237.  
  238. make_war(side1, side2)
  239. Side *side1, *side2;
  240. {
  241.     side1->attitude[side_number(side2)] = ENEMY;
  242.     side2->attitude[side_number(side1)] = ENEMY;
  243. }
  244.  
  245. /* Establish neutrality for both sides. */
  246.  
  247. declare_neutrality(side1, side2)
  248. Side *side1, *side2;
  249. {
  250.     notify_all("The %s and the %s have agreed to neutrality.",
  251.            copy_string(plural_form(side1->name)),
  252.            copy_string(plural_form(side2->name)));
  253.     make_neutrality(side1, side2);
  254. }
  255.  
  256. /* Internal non-noisy function. */
  257.  
  258. make_neutrality(side1, side2)
  259. Side *side1, *side2;
  260. {
  261.     side1->attitude[side_number(side2)] = NEUTRAL;
  262.     side2->attitude[side_number(side1)] = NEUTRAL;
  263. }
  264.  
  265. /* Establish the alliance for both sides, then extend it to include */
  266. /* every other ally (only need one pass over sides to ensure transitive */
  267. /* closure, because alliances formed one at a time). */
  268.  
  269. declare_alliance(side1, side2)
  270. Side *side1, *side2;
  271. {
  272.     Side *side3;
  273.  
  274.     notify_all("The %s and the %s enter into an alliance.",
  275.            copy_string(plural_form(side1->name)),
  276.            copy_string(plural_form(side2->name)));
  277.     make_alliance(side1, side2);
  278.     for_all_sides(side3) {
  279.     if (allied_side(side3, side1)) make_alliance(side3, side2);
  280.     if (allied_side(side3, side2)) make_alliance(side3, side1);
  281.     }
  282. }
  283.  
  284. /* Internal non-noisy function. */
  285.  
  286. make_alliance(side1, side2)
  287. Side *side1, *side2;
  288. {
  289.     if (side1 != side2) {
  290.     side1->attitude[side_number(side2)] = ALLY;
  291.     side2->attitude[side_number(side1)] = ALLY;
  292.     }
  293. }
  294.  
  295. /* General method for passing along info about one side to another. */
  296. /* If sender is NULL, it means to pass along info about *all* sides. */
  297.  
  298. reveal_side(sender, recipient, chance)
  299. Side *sender, *recipient;
  300. int chance;
  301. {
  302.     Unit *unit;
  303.     int x, y;
  304.     Side *loop_side;
  305.  
  306.     if (chance >= 100) {
  307.       for (x = 0 ; x < world.width; x++)
  308.     for (y = 0; y < world.height; y++) {
  309.       viewdata view = side_view(recipient, x, y);
  310. #ifdef PREVVIEW
  311.        int ts = side_view_timestamp(recipient, x, y);
  312. #endif
  313.       
  314.       if (view != EMPTY && view != UNSEEN
  315.           && side_n(vside(view)) == sender) { 
  316.         see_exact(recipient, x, y);
  317. #ifdef PREVVIEW
  318.         side_view_timestamp(recipient, x, y) = ts;
  319. #endif
  320.       }
  321.     }
  322.     }
  323.     for_all_units(loop_side, unit) {
  324.     if (alive(unit) &&
  325.         (unit->side == sender || sender == NULL) &&
  326.         probability(chance)) {
  327.         see_exact(recipient, unit->x, unit->y);
  328.         draw_hex(recipient, unit->x, unit->y, TRUE);
  329.     }
  330.     }
  331. }
  332.  
  333. /* An always-seen unit has builtin spies to inform of movements. */
  334. /* When such a unit occupies a hex, coverage is turned on and remains */
  335. /* on until the unit leaves that hex. */
  336.  
  337. all_see_occupy(unit, x, y)
  338. Unit *unit;
  339. int x, y;
  340. {
  341.     Side *side;
  342.  
  343.     if (utypes[unit->type].seealways) {
  344.     for_all_sides(side) {
  345.         if (side_view(side, x, y) != UNSEEN) {
  346.         add_cover(side, x, y, 100);
  347.         see_hex(side, x, y);
  348.         }
  349.     }
  350.     }
  351. }
  352.  
  353. /* Departure results in coverage being decremented, AFTER the side sees */
  354. /* that the hex is now empty. */
  355.  
  356. all_see_leave(unit, x, y)
  357. Unit *unit;
  358. int x, y;
  359. {
  360.     Side *side;
  361.  
  362.     if (utypes[unit->type].seealways) {
  363.     for_all_sides(side) {
  364.         if (side_view(side, x, y) != UNSEEN) {
  365.         see_hex(side, x, y);
  366.         add_cover(side, x, y, -100);
  367.         }
  368.     }
  369.     }
  370. }
  371.  
  372. /* Unit's beady eyes are now covering the immediate area.  The iteration */
  373. /* covers a hex area;  since new things may be coming into view, we have */
  374. /* to check and maybe draw lots of hexes (but only need the one flush, */
  375. /* fortunately). */
  376.  
  377. cover_area(unit, x0, y0, onoff)
  378. Unit *unit;
  379. int x0, y0, onoff;
  380. {
  381.     int u = unit->type, range, x, y, x1, y1, x2, y2, best, diff, dist, cov;
  382.     Unit *eunit;
  383.     Side *side = unit->side;
  384.  
  385.     if (neutral(unit) || period.allseen || unit->x < 0 || unit->y < 0) return;
  386.     range = utypes[u].seerange;
  387.     if (range<1)
  388.       return;
  389.     best = utypes[u].seebest;
  390.     diff = best - utypes[u].seeworst;
  391.     y1 = y0 - range;
  392.     y2 = y0 + range;
  393.     for (y = y1; y <= y2; ++y) {
  394.     if (between(0, y, world.height-1)) {
  395.         x1 = x0 - (y < y0 ? (y - y1) : range);
  396.         x2 = x0 + (y > y0 ? (y2 - y) : range);
  397.         for (x = x1; x <= x2; ++x) {
  398.         dist = distance(x0, y0, x, y);
  399.         cov = (onoff * (best - (dist * diff) / range)) +
  400.             cover(side, wrap(x), y);
  401.         set_cover(side, wrap(x), y, max(0, cov));
  402.         if (onoff > 0 && see_hex(side, wrap(x), y)) {
  403.             if ((eunit = unit_at(wrap(x), y)) != NULL) {
  404.             if (unit->orders.flags & ENEMYWAKE && !midturnrestore)
  405.                 if (!allied_side(eunit->side, side))
  406.                 wake_unit(unit, TRUE, WAKEENEMY, eunit);
  407.             }
  408.         }
  409.         }
  410.     }
  411.     }
  412.     if (onoff > 0 && active_display(side)) flush_output(side);
  413. }
  414.  
  415. /* Update the view of this hex for everybody's benefit.  May have to write */
  416. /* to many displays, sigh. */
  417.  
  418. all_see_hex(x, y)
  419. int x, y;
  420. {
  421.     register Side *side;
  422.  
  423.     for_all_sides(side) see_hex(side, x, y);
  424. }
  425.  
  426. /* Look at the given position, possibly not seeing anything.  Return true if */
  427. /* a unit was spotted. */
  428.  
  429. see_hex(side, x, y)
  430. Side *side;
  431. int x, y;
  432. {
  433.     register bool yes = FALSE;
  434.     register int u, chance, terr;
  435.     viewdata newview;
  436.     register Unit *unit;
  437.     viewdata curview;
  438.  
  439.     if (side == NULL) return FALSE;
  440.     curview = side_view(side, x, y);
  441.     if (cover(side, x, y) > 0) {
  442.     if ((unit = unit_at(x, y)) != NULL) {
  443.         u = unit->type;
  444.         if (unit->side == side) {
  445.         yes = TRUE;
  446.         } else {
  447.         chance = (cover(side, x, y) * utypes[u].visibility) / 100;
  448.         terr = terrain_at(x, y);
  449.         chance = (chance * (100 - utypes[u].conceal[terr])) / 100;
  450.         if (probability(chance)) yes = TRUE;
  451.         }
  452.         if (yes) {
  453.         newview = buildview(side_number(unit->side), u);
  454.         if (curview != newview) {
  455.           set_side_view(side, x, y, newview);
  456.           draw_hex(side, x, y, FALSE);
  457.           if (side->followaction && curview != newview
  458.               && side->mode == SURVEY) {
  459.             cancel_request(side);
  460.             side->curx = x; side->cury = y;
  461.             make_current(side, unit_at(x, y));
  462.           }
  463.         }
  464.         return TRUE;
  465.           } else {
  466.             if (side_view(side, x, y) == UNSEEN) {
  467.           set_side_view(side, x, y, EMPTY);
  468.           draw_hex(side, x, y, FALSE);
  469.         }
  470.         return FALSE;
  471.         }
  472.     } else {
  473.       if (curview != EMPTY) {
  474.             set_side_view(side, x, y, EMPTY);
  475.         draw_hex(side, x, y, FALSE);
  476.         if (side->followaction && side != curside
  477.             && curview != newview)
  478.           put_on_screen(side, x, y);
  479.       }
  480.       return FALSE;
  481.     }
  482.     } else {
  483.     /* preserve old image */
  484.     return FALSE;
  485.     }
  486. }
  487.  
  488. /* "Bare-bones" viewing, for whenever you know exactly what's there. */
  489. /* This is the lowest level of all viewing routines, and executed a *lot*. */
  490.  
  491. see_exact(side, x, y)
  492. Side *side;
  493. int x, y;
  494. {
  495.     register viewdata newview;
  496.     register Unit *unit = unit_at(x, y);
  497.  
  498.     if (side == NULL) return;
  499.     newview =
  500.       ((unit != NULL)
  501.        ? buildview(side_number(unit->side), unit->type) : EMPTY);
  502.     set_side_view(side, x, y, newview);
  503.     draw_hex(side, x, y, FALSE);
  504. }
  505.  
  506. /* Utility to clean up images of units from a lost side. */
  507.  
  508. remove_images(side, n)
  509. Side *side;
  510. int n;
  511. {
  512.     int x, y;
  513.     viewdata view;
  514.  
  515.     for (x = 0; x < world.width; ++x) {
  516.     for (y = 0; y < world.height; ++y) {
  517.         view = side_view(side, x, y);
  518.         if (view != EMPTY && view != UNSEEN && vside(view) == n) {
  519.         set_side_view(side, x, y, EMPTY);
  520.         draw_hex(side, x, y, TRUE);
  521.         }
  522.     }
  523.     }
  524. }
  525.  
  526. /* Show some overall numbers on performance of a side. */
  527.  
  528. print_side_results(fp, side)
  529. FILE *fp;
  530. Side *side;
  531. {
  532.     fprintf(fp, "The %s (%s):\n",
  533.         plural_form(side->name), (side->host ? side->host : "machine"));
  534.     fprintf(fp, "\n");
  535. }
  536.  
  537. /* Display what is essentially a double-column bookkeeping of unit gains */
  538. /* and losses.  Tricks here include the use of "dummy reason" flags to */
  539. /* display sums of several columns. */
  540.  
  541. print_unit_record(fp, side)
  542. FILE *fp;
  543. Side *side;
  544. {
  545.     int atype, reason, sum;
  546.  
  547.     fprintf(fp, "Unit Record (gains and losses by cause and unit type)\n");
  548.     fprintf(fp, "   ");
  549.     for (reason = 0; reason < NUMREASONS; ++reason) {
  550.     fprintf(fp, " %3s", reasonnames[reason]);
  551.     }
  552.     fprintf(fp, "  Total\n");
  553.     for_all_unit_types(atype) {
  554.     sum = 0;
  555.     fprintf(fp, " %c ", utypes[atype].uchar);
  556.     for (reason = 0; reason < NUMREASONS; ++reason) {
  557.         if (side->balance[atype][reason] > 0) {
  558.         fprintf(fp, " %3d", side->balance[atype][reason]);
  559.         sum += side->balance[atype][reason];
  560.         } else if (reason == DUMMYREAS) {
  561.         fprintf(fp, " %3d", sum);
  562.         sum = 0;
  563.         } else {
  564.         fprintf(fp, "    ");
  565.         }
  566.     }
  567.     fprintf(fp, "   %3d\n", sum);
  568.     }
  569.     fprintf(fp, "\n");
  570. }
  571.  
  572. void set_side_view(s,x,y,v)
  573. Side *s;
  574. int x,y;
  575. viewdata v;
  576. {
  577.  
  578. #ifdef PREVVIEW
  579.   s->viewtimestamp[world.width*y+x] = global.time;
  580. /*   if (v != side_view(s,x,y)) */
  581.     s->prevview[world.width*y+x] = side_view(s,x,y);
  582. #endif
  583.   s->view[world.width*y+x] = v;
  584. }
  585.  
  586. /*
  587. viewdata buildview(side, utype)
  588. int side,utype;
  589. {
  590.   viewdata newview;
  591.   
  592.   vside(newview) = side;
  593.   vtype(newview) = utype;
  594.   return newview;
  595. }
  596. */
  597.