1 /* Sides in Xconq.
2    Copyright (C) 1987-1989, 1991-2000 Stanley T. Shebs.
3    Copyright (C) 2004-2005 Eric A. McDonald.
4 
5 Xconq is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.  See the file COPYING.  */
9 
10 /* This file implements sides and functionality relating to sides in
11    general. */
12 
13 #include "conq.h"
14 #include "kernel.h"
15 
16 #define checked_elev_at(x, y) (elevations_defined() ? elev_at(x, y) : 0)
17 
18 namespace Xconq {
19     int people_always_see;
20     int any_people_see_chances = -1;
21     int any_see_chances = -1;
22     int max_see_chance_range;
23     int any_see_mistake_chances = -1;
24     int max_see_mistake_range;
25     int any_overwatch_cache = -1;
26     PackedBoolTable *any_overwatch_chances = NULL;
27     int *overwatch_against_range_max = NULL;
28     int *overwatch_against_range_min = NULL;
29 }
30 
31 /* From 'ui.h'. */
32 extern void set_unit_image(Unit *unit);
33 extern void set_unit_view_image(UnitView *uview);
34 
35 void return_default_colorname(Side *side);
36 
37 static char *pick_default_colorname(Side *side);
38 static void allocate_unit_view_block(void);
39 static UnitView *create_bare_unit_view(void);
40 static void init_visible_elevation(int x, int y);
41 static void init_visible_elevation_2(int x, int y);
42 static void calc_visible_elevation(int x, int y);
43 static void calc_visible_elevation_2(int x, int y);
44 static void cover_area_1(Side *side, struct a_unit *unit, int x0, int y0,
45 			 int x1, int y1);
46 static int see_materials(Side *side, int x, int y);
47 static int see_weather(Side *side, int x, int y);
48 static int mistaken_type(int u2);
49 static void update_master_uview(Unit *unit, int lookabove);
50 static int remove_unit_view(Side *side, UnitView *olduview);
51 static void flush_one_view(UnitView *uview);
52 
53 static int see_unit(Unit *seer, Unit *tosee, SeerNode *seers, int *numseers);
54 static int side_occs_see_unit(int x, int y, int *numseers, ParamBox *parambox);
55 static int side_ustack_see_unit(int x, int y, int *numseers,
56 				ParamBox *parambox);
57 static void compute_overwatch_cache(void);
58 
59 #ifndef INITMAXVIEWS
60 #define INITMAXVIEWS 200
61 #endif
62 
63 #define VIEW_HASH_SIZE 257
64 
65 /* Head of the list of all sides. */
66 
67 Side *sidelist;
68 
69 /* Pointer to the side representing independent units. */
70 
71 Side *indepside;
72 
73 /* Pointer to the last side of the list. */
74 
75 Side *lastside;
76 
77 /* Temporary used in many places. */
78 
79 Side *tmpside;
80 
81 /* The actual number of sides in a game.  This number never decreases;
82    sides no longer playing need to be around for recordskeeping purposes. */
83 
84 int numsides;
85 
86 /* This is the number of sides including indepside. We need it for the
87    AI assignment in init.c. We want to keep numsides referring to
88    normal sides only, since it is used a lot in the interface code,
89    where we typically don't want to include indepside. */
90 
91 int numtotsides;
92 
93 /* Used to generate the id number of the side. */
94 
95 int nextsideid;
96 
97 /* Test if a given side's sideclass matches a given sideclass. */
98 
99 int
fn_test_side_in_sideclass(Obj * osclass,ParamBox * pbox)100 fn_test_side_in_sideclass(Obj *osclass, ParamBox *pbox)
101 {
102     char *sclass = NULL;
103     int sid = -1;
104     ParamBoxSide *paramboxs = NULL;
105     Obj *rest = lispnil;
106 
107     assert_error(osclass, "Attempted to access a NULL GDL object");
108     assert_error(pbox, "Attempted to access a NULL parameter box");
109     assert_error(pbox->get_type() == PBOX_TYPE_SIDE,
110 		 "Wrong type of paramter box passed to test function");
111     paramboxs = (ParamBoxSide *)pbox;
112     /* If object is NIL, then return immediately. */
113     if (osclass == lispnil)
114       return FALSE;
115     /* If the object is a string, then assume it is a sideclass. */
116     if (stringp(osclass)) {
117         sclass = c_string(osclass);
118         if (paramboxs->side && (paramboxs->side != indepside)) {
119             if (empty_string(paramboxs->side->sideclass))
120               return FALSE;
121             return (!strcmp(sclass, paramboxs->side->sideclass));
122         }
123 	else
124           return (!strcmp(sclass, "independent"));
125     }
126     /* If the object is a number, then assume it is a side ID. */
127     else if (numberp(osclass)) {
128 	sid = c_number(osclass);
129 	if (paramboxs->side)
130 	  return (sid == paramboxs->side->id);
131 	else
132 	  return (!sid);
133     }
134     /* If the object is a cons, then assume it is a list of side ID's
135        inclusive-or side classes, and iterate through list until a
136        match is found or end of list is encountered. */
137     else if (consp(osclass)) {
138 	for_all_list(osclass, rest) {
139 	    if (fn_test_side_in_sideclass(car(rest), pbox))
140 	      return TRUE;
141 	}
142 	return FALSE;
143     }
144     /* Else, we can't use the object. */
145     else {
146         init_warning("Testing side against garbled sideclass expression");
147         /* Be permissive if continued. */
148         return TRUE;
149     }
150     return FALSE;
151 }
152 
153 /* Used for solid color emblems. These colors have been carefully
154    tested so that they stand out against most backgrounds and also can be
155    easily distinguished from each other. The indepside default emblem is
156    set to "none" since it usually goes without emblem. */
157 
158 char *default_colornames[MAXSIDES + 1] = {
159 	"lemon-chiffon",
160 	"blue",
161 	"red",
162 	"yellow",
163 	"green",
164 	"dark-orange",
165 	"deep-pink",
166 	"cyan",
167 	"purple",
168 	"tomato",
169 	"violet",
170 	"dodger-blue",
171 	"light-sea-green",
172 	"rosy-brown",
173 	"slate-blue",
174 	"firebrick"
175 };
176 
177 /* Default colors used so far by any non-removed side. Stores the
178    number of the side using the color, or else zero. */
179 
180 static short default_colornames_used[MAXSIDES + 1];
181 
182 static char
pick_default_colorname(Side * side)183 *pick_default_colorname(Side *side)
184 {
185 	int i;
186 
187 	if (side == indepside) {
188 		return default_colornames[0];
189 	}
190 	/* We start at 1 since default_colors[0] is reserved for
191 	indepside, whether or not it is present in the game. */
192 	for (i = 1; i <= MAXSIDES +1; i++) {
193 		if (default_colornames_used[i] == FALSE) {
194 			default_colornames_used[i] = TRUE;
195 			return default_colornames[i];
196 		}
197 	}
198 	/* Should never happen, but humor the compiler. */
199 	return "black";
200 }
201 
202 void
return_default_colorname(Side * side)203 return_default_colorname(Side *side)
204 {
205 	int i;
206 
207 	/* We start at 1 since default_colors[0] is reserved for
208 	indepside, whether or not it is present in the game. */
209 	for (i = 1; i <= MAXSIDES + 1; i++) {
210 	    if (default_colornames_used[i] == TRUE
211 		&& strcmp(side->default_color, default_colornames[i]) == 0) {
212 		default_colornames_used[i] = FALSE;
213 		return;
214 	    }
215 	}
216 }
217 
218 /* Cached values of global vision vars. */
219 
220 short any_los = -1;
221 
222 int any_material_views = -1;
223 
224 char *any_material_views_by_m = NULL;
225 
226 /* Pointer to buffer used for readable side description (for debugging). */
227 
228 char *sidedesigbuf = NULL;
229 
230 /* Pointer to the head of the list of players. */
231 
232 Player *playerlist;
233 
234 /* Pointer to the last player of the list, used to add players at end. */
235 
236 Player *last_player;
237 
238 /* The total number of players. */
239 
240 int numplayers;
241 
242 /* Use to generate the id number of each player. */
243 
244 int nextplayerid;
245 
246 char *playerdesigbuf = NULL;
247 
248 /* The list of doctrine objects. */
249 
250 Doctrine *doctrine_list;
251 
252 Doctrine *last_doctrine;
253 
254 int next_doctrine_id;
255 
256 /* The list of available unit views. */
257 
258 UnitView *freeviews;
259 
260 /* The global linked list of all unit views. */
261 
262 UnitView *viewlist = NULL;
263 
264 /* The number of views in viewlist. */
265 
266 static int numunitviews = 0;
267 
268 /* Grab a block of unit view objects to work with. */
269 
270 static void
allocate_unit_view_block(void)271 allocate_unit_view_block(void)
272 {
273     int i;
274     UnitView *viewblock = (UnitView *) xmalloc(INITMAXVIEWS * sizeof(UnitView));
275 
276     for (i = 0; i < INITMAXVIEWS; ++i) {
277         viewblock[i].id = -1;
278         viewblock[i].nexthere = &viewblock[i+1];
279     }
280     viewblock[INITMAXVIEWS-1].nexthere = NULL;
281     freeviews = viewblock;
282     Dprintf("Allocated space for %d unit views.\n", INITMAXVIEWS);
283 }
284 
285 /* The primitive unit view creator. */
286 
287 UnitView *
create_bare_unit_view(void)288 create_bare_unit_view(void)
289 {
290     UnitView *newview;
291 
292     /* If our free list is empty, go and get some more units. */
293     if (freeviews == NULL) {
294 	allocate_unit_view_block();
295     }
296     /* Take the first unit off the free list. */
297     newview = freeviews;
298     freeviews = freeviews->nexthere;
299     /* ...but an invalid id. */
300     newview->id = -1;
301     return newview;
302 }
303 
304 /* Count how many units total are on a side. */
305 
306 int
n_units_on_side(Side * side)307 n_units_on_side(Side *side)
308 {
309     int n = 0;
310     Unit *unit = NULL;
311     /* (NOTE: Probably faster to sum up the side totals for each type.
312 	The question is whether those tallies are accurate.) */
313     for_all_side_units(side, unit)
314       ++n;
315     return n;
316 }
317 
318 /* Init side machinery. Don't fill in indepside yet since numutypes
319    etc. may not be defined.  */
320 
321 void
init_sides(void)322 init_sides(void)
323 {
324     /* Set up the list of sides. */
325     sidelist = lastside = (Side *) xmalloc(sizeof(Side));
326     /* The independent units' side will be the first one in the list,
327        is always created.  It cannot be filled in yet, because the
328        numbers of the various types is not yet known. */
329     indepside = sidelist;
330     /* Note: indepside is included in numtotsides, but not numsides. */
331     numtotsides = 0;
332     numsides = 0;
333     nextsideid = 0;
334     /* Set up the list of players. */
335     playerlist = last_player = NULL;
336     numplayers = 0;
337     /* Indepside also needs a player, so we now start with id 0. */
338     nextplayerid = 0;
339     /* Set up the player/side assignment array. */
340     assignments = (Assign *) xmalloc((MAXSIDES + 1) * sizeof(Assign));
341     /* Set up the list of doctrines. */
342     doctrine_list = last_doctrine = NULL;
343     /* Doctrine ids must start at 1. */
344     next_doctrine_id = 1;
345 }
346 
347 /* Create an object representing a side. */
348 
349 Side *
create_side(void)350 create_side(void)
351 {
352     int u, m;
353     Side *newside;
354 
355     /* Too many sides. */
356     if (numsides >=  g_sides_max()) {
357 	run_error("Cannot have more than %d sides total!", g_sides_max());
358     }
359     /* Prevent many crashes and much hair-pulling. */
360     if (numutypes <= 0) {
361 	/* (Should probably be regarded as an init_error; however, this
362 	    segment of code may be executed "late".) */
363 	run_error("Unit types must be defined before defining sides!");
364     }
365     /* Just fill in the names if dealing with indepside. */
366     if (nextsideid == 0) {
367     	newside = indepside;
368 	newside->name = "Independents";
369 	newside->noun = "Independent";
370 	newside->pluralnoun = "Independents";
371 	newside->adjective = "independent";
372 	newside->colorscheme = "black,black,white";
373 	newside->emblemname = "none";
374     } else {
375 	/* Else allocate a new side object and increase numsides. */
376 	newside = (Side *) xmalloc(sizeof(Side));
377 	/* numsides does not include indepside, thus increment it here. */
378     	++numsides;
379     }
380     /* Fill in various side slots.  Only those with non-zero/non-NULL
381        defaults need have anything done to them. */
382     newside->id = nextsideid++;
383     /* Always start sides IN the game. */
384     newside->ingame = TRUE;
385     /* Note that "everingame" is only set at the beginning of a turn. */
386     /* Set up the relationships with other sides. */
387     newside->knows_about = ALLSIDES; /* for now */
388     newside->trusts = (short *) xmalloc((g_sides_max() + 1) * sizeof(short));
389     newside->trades = (short *) xmalloc((g_sides_max() + 1) * sizeof(short));
390     /* Set up per-unit-type slots. */
391     newside->counts = (short *) xmalloc(numutypes * sizeof(short));
392     newside->tech = (short *) xmalloc(numutypes * sizeof(short));
393     newside->inittech = (short *) xmalloc(numutypes * sizeof(short));
394     newside->numunits = (short *) xmalloc(numutypes * sizeof(short));
395     newside->default_color = pick_default_colorname(newside);
396     if (newside != indepside) {
397 	newside->emblemname = newside->default_color;
398     }
399     for_all_unit_types(u) {
400 	/* Start unit numbering at 1, not 0. */
401 	newside->counts[u] = 1;
402     }
403     newside->priority = -1;
404     /* All sides should auto-finish by default. */
405     newside->autofinish = TRUE;
406     /* True by default, players should disable manually. */
407     newside->willingtosave = TRUE;
408     /* Put valid Lisp data into slots that need it. */
409     newside->symbol = lispnil;
410     newside->instructions = lispnil;
411     newside->rawscores = lispnil;
412     newside->aidata = lispnil;
413     newside->uidata = lispnil;
414     newside->possible_units = lispnil;
415     newside->startx = newside->starty = -1;
416     newside->init_center_x = newside->init_center_y = -1;
417     newside->gaincounts = (short *) xmalloc(numutypes * num_gain_reasons * sizeof(short));
418     newside->losscounts = (short *) xmalloc(numutypes * num_loss_reasons * sizeof(short));
419     newside->atkstats = (long **) xmalloc(numutypes * sizeof(long *));
420     newside->hitstats = (long **) xmalloc(numutypes * sizeof(long *));
421     /* Necessary to enable AI control toggling of selected units! */
422     newside->prefixarg = -1;
423     if (numatypes > 0) {
424 	newside->advance = (short *) xmalloc(numatypes * sizeof(short));
425 	newside->canresearch = (short *) xmalloc(numatypes * sizeof(short));
426 	newside->research_precluded =
427 	    (short *)xmalloc(numatypes * sizeof(short));
428 	newside->research_topic = NOADVANCE;
429 	newside->autoresearch = FALSE;
430 	newside->research_goal = NONATYPE;
431     }
432     newside->canbuild = (short *) xmalloc(numutypes * sizeof(short));
433     newside->cancarry = (short *) xmalloc(numutypes * sizeof(short));
434     newside->candevelop = (short *) xmalloc(numutypes * sizeof(short));
435     /* We can't update the canbuild vector yet, because its contents
436        may depend on side class, which isn't set yet. */
437     if (nummtypes > 0) {
438 	/* Set up the side's supply of materials. */
439 	newside->treasury = (long *) xmalloc(nummtypes * sizeof(long));
440 	for_all_material_types(m) {
441 	     	if (side_has_treasury(newside, m)) {
442 	  		newside->treasury[m] = m_initial_treasury(m);
443 		}
444 	}
445 	/* Make space for default conversions and copy them over. */
446 	newside->c_rates = (short *) xmalloc(nummtypes * sizeof(short));
447 	{
448 	    int m1, m2;
449 
450 	    /* First initilaize m. */
451 	    m = NONMTYPE;
452 	    /* For now, assume only one m. */
453 	    for_all_material_types(m1) {
454 		for_all_material_types(m2) {
455 		    if (mm_conversion(m1, m2) > 0) {
456 			m = m1;
457 			break;
458 		    }
459 		}
460 	    }
461 	    if (m != NONMTYPE) {
462 		for_all_material_types(m2) {
463 		    newside->c_rates[m2] = mm_conversion_default(m, m2);
464 		}
465 	    }
466 	}
467     }
468     newside->controlled_by_id = -1;
469     newside->playerid = -1;
470     /* Link in at the end of the list of sides. */
471     newside->next = NULL;
472     /* Important to avoid the indepside->next = indepside loop! */
473     if (newside != indepside) {
474 	lastside->next = newside;
475 	lastside = newside;
476     }
477     init_side_unithead(newside);
478     /* numtotsides also includes indepside. */
479     ++numtotsides;
480     return newside;
481 }
482 
483 /* To make the double links work, we have to have one pseudo-unit to
484    serve as a head.  This unit should not be seen by any outside
485    code. */
486 
487 void
init_side_unithead(Side * side)488 init_side_unithead(Side *side)
489 {
490     if (side->unithead == NULL) {
491 	side->unithead = create_bare_unit(0);
492 	side->unithead->next = side->unithead;
493 	side->unithead->prev = side->unithead;
494     }
495 }
496 
497 /* Quick check to see if we have units. */
498 
499 /* This should be improved to not be fooled by dead units? */
500 
501 int
side_has_units(Side * side)502 side_has_units(Side *side)
503 {
504     return (side->unithead != NULL
505 	    && (side->unithead->next != side->unithead));
506 }
507 
508 /* Set up doctrine structures. */
509 
510 void
init_doctrine(Side * side)511 init_doctrine(Side *side)
512 {
513     int u;
514 
515     /* Every side must have a default doctrine to fall back on. */
516     if (side->default_doctrine == NULL) {
517 	side->default_doctrine = new_doctrine(0);
518     }
519     /* Make each individual unit doctrine point to the generic
520        doctrine by default. */
521     if (side->udoctrine == NULL) {
522 	side->udoctrine =
523 	  (Doctrine **) xmalloc(numutypes * sizeof(Doctrine *));
524     }
525     for_all_unit_types(u) {
526 	if (side->udoctrine[u] == NULL)
527 	  side->udoctrine[u] = side->default_doctrine;
528     }
529 }
530 
531 void
init_self_unit(Side * side)532 init_self_unit(Side *side)
533 {
534     Unit *unit;
535 
536     if ((g_self_required() /* || side prop? */)
537     	&& side != indepside
538 	&& side->self_unit == NULL) {
539 	for_all_side_units(side, unit) {
540 	    if (u_can_be_self(unit->type)
541 		&& in_play(unit)
542 		&& completed(unit)) {
543 		side->self_unit = unit;
544 		break;
545 	    }
546 	}
547     }
548 }
549 
550 /* Initialize basic viewing structures for a side.  This happens when
551    the side is created (during/after reading but before synthesis).
552    At this time we're mostly allocating space; filling in the views
553    happens once all the units are in position.  We don't know the
554    final values of parameters like side->see_all, so we have to
555    allocate some data that might never be used. */
556 
557 int
init_view(Side * side)558 init_view(Side *side)
559 {
560     int terrainset = FALSE, t, u, m;
561 
562     /* Be sure that we're not trying to set this up too soon. */
563     check_area_shape();
564     /* Allocate terrain view layers. */
565     if ((!g_terrain_seen() || !g_see_terrain_always())
566 	&& side->terrview == NULL) {
567 	side->terrview = malloc_area_layer(char);
568 	if (!g_see_terrain_always()) {
569 	    side->terrviewdate = malloc_area_layer(short);
570 	    /* The terrview also holds the "have we seen it" flag, so
571 	       it must always be allocated, but the aux terrain view
572 	       need not be. */
573 	    if (numcelltypes < numttypes) {
574 		side->auxterrview =
575 		  (char **) xmalloc(numttypes * sizeof(short *));
576 		for_all_terrain_types(t) {
577 		    if (!t_is_cell(t)) {
578 			side->auxterrview[t] = malloc_area_layer(char);
579 		    }
580 		}
581 		if (0 /* aux terrain seen separately from main terrain */) {
582 		    side->auxterrviewdate =
583 		      (short **) xmalloc(numttypes * sizeof(short *));
584 		    for_all_terrain_types(t) {
585 			if (!t_is_cell(t)) {
586 			    side->auxterrviewdate[t] =
587 			      malloc_area_layer(short);
588 			}
589 		    }
590 		}
591 	    }
592 	}
593     } else {
594 	terrainset = TRUE;
595     }
596     /* Allocate material view layers. */
597     if (any_material_views < 0) {
598 	any_material_views = FALSE;
599 	for_all_material_types(m) {
600 	    for_all_terrain_types(t) {
601 		if (tm_storage_x(t, m) > 0 && tm_see_always(t, m) == 0) {
602 		    any_material_views = TRUE;
603 		    if (any_material_views_by_m == NULL)
604 		      any_material_views_by_m = (char *)xmalloc(nummtypes);
605 		    any_material_views_by_m[m] = TRUE;
606 		    break;
607 		}
608 	    }
609 	}
610     }
611     if (any_material_views) {
612 	if (side->materialview == NULL)
613 	  side->materialview = (short **) xmalloc(nummtypes * sizeof(short *));
614 	if (side->materialviewdate == NULL)
615 	  side->materialviewdate =
616 	    (short **) xmalloc(nummtypes * sizeof(short *));
617 	for_all_material_types(m) {
618 	    if (any_material_views_by_m[m]) {
619 		if (side->materialview[m] == NULL) {
620 		    side->materialview[m] = malloc_area_layer(short);
621 		}
622 		if (side->materialviewdate[m] == NULL) {
623 		    side->materialviewdate[m] = malloc_area_layer(short);
624 		}
625 	    }
626 	}
627     }
628     /* Allocate weather view layers. */
629     if (any_temp_variation && !g_see_weather_always()) {
630 	if (side->tempview == NULL) {
631 	    side->tempview = malloc_area_layer(short);
632 	}
633 	if (side->tempviewdate == NULL) {
634 	    side->tempviewdate = malloc_area_layer(short);
635 	}
636     }
637     if (any_clouds && !g_see_weather_always()) {
638 	if (side->cloudview == NULL) {
639 	    side->cloudview = malloc_area_layer(short);
640 	}
641 	if (side->cloudbottomview == NULL) {
642 	    side->cloudbottomview = malloc_area_layer(short);
643 	}
644 	if (side->cloudheightview == NULL) {
645 	    side->cloudheightview = malloc_area_layer(short);
646 	}
647 	if (side->cloudviewdate == NULL) {
648 	    side->cloudviewdate = malloc_area_layer(short);
649 	}
650     }
651     if (any_wind_variation && !g_see_weather_always()) {
652 	if (side->windview == NULL) {
653 	    side->windview = malloc_area_layer(short);
654 	}
655 	if (side->windviewdate == NULL) {
656 	    side->windviewdate = malloc_area_layer(short);
657 	}
658     }
659     /* Allocate the vision coverage cache. */
660     if (side->coverage == NULL) {
661 	side->coverage = malloc_area_layer(short);
662     }
663     /* Allocate vision altitude coverage if needed */
664     if (any_los < 0) {
665 	any_los = FALSE;
666 	for_all_unit_types(u) {
667 	    if (!u_can_see_behind(u)) {
668 		any_los = TRUE;
669 		break;
670 	    }
671 	}
672     }
673     if (side->alt_coverage == NULL && any_los) {
674 	side->alt_coverage = malloc_area_layer(short);
675     }
676     return terrainset;
677 }
678 
679 /* Calculate the centroid of all the starting units. */
680 
681 void
calc_start_xy(Side * side)682 calc_start_xy(Side *side)
683 {
684     int num = 0, sumx = 0, sumy = 0;
685     Unit *unit;
686 
687     for_all_side_units(side, unit) {
688 	if (in_play(unit)) {
689 	    sumx += unit->x;  sumy += unit->y;
690 	    ++num;
691 	}
692     }
693     if (num > 0) {
694 	side->startx = wrapx(sumx / num);  side->starty = sumy / num;
695     }
696 }
697 
698 /* Given a side, get its "number", which is same as its "id". */
699 
700 int
side_number(Side * side)701 side_number(Side *side)
702 {
703     return side->id;
704 }
705 
706 /* The inverse function - given a number, figure out which side it is.
707    Returns NULL for any failure. */
708 /* (should cache values in a table, do direct lookup) */
709 
710 Side *
side_n(int n)711 side_n(int n)
712 {
713     Side *side;
714 
715     for_all_sides(side)
716       if (side->id == n)
717         return side;
718     return NULL;
719 }
720 
721 Side *
find_side_by_name(char * str)722 find_side_by_name(char *str)
723 {
724     Side *side;
725 
726     if (empty_string(str))
727       return NULL;
728     for_all_sides(side) {
729 	if (!empty_string(side->name) && strcmp(side->name, str) == 0)
730 	  return side;
731 	if (!empty_string(side->noun) && strcmp(side->noun, str) == 0)
732 	  return side;
733 	if (!empty_string(side->pluralnoun) && strcmp(side->pluralnoun, str) == 0)
734 	  return side;
735 	if (!empty_string(side->adjective) && strcmp(side->adjective, str) == 0)
736 	  return side;
737     }
738     return NULL;
739 }
740 
741 Side *
parse_side_spec(char * str)742 parse_side_spec(char *str)
743 {
744     int s;
745     char *reststr;
746 
747     if (isdigit(str[0])) {
748 	s = strtol(str, &reststr, 10);
749 	if (between(1, s, numsides)) {
750 	    return side_n(s);
751 	}
752     } else {
753 	return find_side_by_name(str);
754     }
755     return NULL;
756 }
757 
758 /* This is true when one side controls another. */
759 
760 int
side_controls_side(Side * side,Side * side2)761 side_controls_side(Side *side, Side *side2)
762 {
763     return (side == side2 || side2->controlled_by == side);
764 }
765 
766 short *max_control_ranges;
767 
768 static int controller_here(int x, int y);
769 
770 static int
controller_here(int x,int y)771 controller_here(int x, int y)
772 {
773     Unit *unit2;
774 
775     if (distance(x, y, tmpunit->x, tmpunit->y) < 2)
776       return FALSE;
777     for_all_stack(x, y, unit2) {
778 	if (side_controls_unit(tmpside, unit2)
779 	    && probability(uu_control(unit2->type, tmpunit->type)))
780 	  return TRUE;
781     }
782     return FALSE;
783 }
784 
785 /* This is true if the given side may operate on the given unit. */
786 
787 int
side_controls_unit(Side * side,Unit * unit)788 side_controls_unit(Side *side, Unit *unit)
789 {
790     int dir, x1, y1;
791     Unit *unit2;
792 
793     if (unit == NULL)
794       return FALSE;
795     if (is_designer(side))
796       return TRUE;
797     /* Also give debuggers full control. */
798     if (Debug || DebugG || DebugM)
799       return TRUE;
800     if (side_controls_side(side, unit->side)) {
801 	/* The *unit* side must have the tech to use the unit, the controlling
802 	   side would have to actually take over the unit if it wants to use
803 	   its tech level to control the unit. */
804 	if (unit->side != NULL
805 	    && unit->side->tech[unit->type] < u_tech_to_use(unit->type))
806 	  return FALSE;
807 	if (u_direct_control(unit->type) || unit == side->self_unit)
808 	  return TRUE;
809 	/* Unit is not under direct control of the side; look for a
810 	   controlled unit that can control this unit. */
811 	if (max_control_ranges == NULL) {
812 	    int u1, u2;
813 
814 	    max_control_ranges = (short *) xmalloc(numutypes * sizeof(short));
815 	    for_all_unit_types(u2) {
816 		max_control_ranges[u2] = -1;
817 		for_all_unit_types(u1) {
818 		    max_control_ranges[u2] =
819 		      max(max_control_ranges[u2], uu_control_range(u1, u2));
820 		}
821 	    }
822 	}
823 	if (max_control_ranges[unit->type] >= 0) {
824 	    for_all_stack(unit->x, unit->y, unit2) {
825 		if (unit != unit2
826 		    && side_controls_unit(side, unit2)
827 		    && probability(uu_control_at(unit2->type, unit->type)))
828 		  return TRUE;
829 	    }
830 	    /* (what about occupants that could be controllers?) */
831 	}
832 	if (max_control_ranges[unit->type] >= 1) {
833 	    for_all_directions(dir) {
834 		if (interior_point_in_dir(unit->x, unit->y, dir, &x1, &y1)) {
835 		    for_all_stack(x1, y1, unit2) {
836 			if (side_controls_unit(side, unit2)
837 			    && probability(uu_control_adj(unit2->type, unit->type)))
838 			  return TRUE;
839 		    }
840 		}
841 	    }
842 	}
843 	if (max_control_ranges[unit->type] >= 2) {
844 	    tmpside = side;
845 	    tmpunit = unit;
846 	    return search_around(unit->x, unit->y,
847 				 max_control_ranges[unit->type],
848 	    			 controller_here, &x1, &y1, 1);
849 	}
850     }
851     return FALSE;
852 }
853 
854 /* This is true if the given side may examine the given unit. */
855 
856 int
side_sees_unit(Side * side,Unit * unit)857 side_sees_unit(Side *side, Unit *unit)
858 {
859     int x = -1, y = -1;
860 
861     if (unit == NULL)
862       return FALSE;
863     /* If the side is omniscient. */
864     if (side->see_all || side->show_all)
865       return TRUE;
866     /* If the unit is 'see-always' and on known terrain in the arena. */
867     x = unit->x;  y = unit->y;
868     if (u_see_always(unit->type) && inside_area(x, y)
869 	&& (UNSEEN != terrain_view(side, x, y)))
870       return TRUE;
871     /* If the side controls the unit's side. */
872     if (side_controls_side(side, unit->side))
873       return TRUE;
874     /* If the unit's side trusts the side. */
875     if (trusted_side(unit->side, side))
876       return TRUE;
877     /* If the game is over. */
878     if (endofgame)
879       return TRUE;
880     /* If the side's people can see the unit. */
881     if (Xconq::people_always_see && people_sides_defined()
882 	&& (people_side_at(unit->x, unit->y) == side->id))
883       return TRUE;
884     /* Else, side cannot see. */
885     return FALSE;
886 }
887 
888 /* This is true if the side can see the image of a unit. */
889 
890 int
side_sees_image(Side * side,Unit * unit)891 side_sees_image(Side *side, Unit *unit)
892 {
893     UnitView *uview;
894     int x = -1, y = -1;
895 
896     if (side == NULL)
897       run_error("NULL side to side_sees_image");
898     if (unit == NULL)
899       return FALSE;
900     if (side->see_all || side->show_all)
901       return TRUE;
902     /* If the unit is 'see-always' and on known terrain in the arena. */
903     x = unit->x;  y = unit->y;
904     if (u_see_always(unit->type) && inside_area(x, y)
905 	&& (UNSEEN != terrain_view(side, x, y)))
906       return TRUE;
907     if (side_controls_side(side, unit->side))
908       return TRUE;
909 #if (0)
910     if (u_see_always(unit->type))
911       return TRUE;
912 #endif
913     for_all_view_stack_with_occs(side, unit->x, unit->y, uview) {
914 	if (unit->type == uview->type
915 	    && unit->side == side_n(uview->siden)
916 	    && unit->id == uview->id) {
917 		return TRUE;
918     	}
919     }
920     return FALSE;
921 }
922 
923 /* Test whether the occupants of the given unit are visible to the
924    given side. */
925 
926 int
occupants_visible(Side * side,Unit * unit)927 occupants_visible(Side *side, Unit *unit)
928 {
929     if (unit->occupant == NULL)
930       return FALSE;
931     /* If the side is omniscient. */
932     if (side->see_all)
933       return TRUE;
934     /* If the side sees the transport and the occupants are to be revealed. */
935     if (side_sees_unit(side, unit) && u_see_occupants(unit->type))
936       return TRUE;
937     /* If the side owns a seeing unit in the transport. */
938     /* (TODO: Handle the case of a trusted unit providing info.) */
939     if (side_owns_viewer_in_unit(side, unit))
940       return TRUE;
941     return FALSE;
942 }
943 
944 int
num_units_in_play(Side * side,int u)945 num_units_in_play(Side *side, int u)
946 {
947     int num = 0;
948     Unit *unit;
949 
950     if (side != NULL && side->ingame) {
951       for_all_side_units(side, unit) {
952 	if (unit->type == u
953 	    && in_play(unit)
954 	    && completed(unit))
955 	  ++num;
956       }
957     }
958     return num;
959 }
960 
961 int
num_units_incomplete(Side * side,int u)962 num_units_incomplete(Side *side, int u)
963 {
964     int num = 0;
965     Unit *unit;
966 
967     if (side != NULL && side->ingame) {
968       for_all_side_units(side, unit) {
969 	if (unit->type == u
970 	    && in_play(unit)
971 	    && !completed(unit)) {
972 	    ++num;
973       	}
974       }
975     }
976     return num;
977 }
978 
979 Unit *
find_next_unit(Side * side,Unit * prevunit)980 find_next_unit(Side *side, Unit *prevunit)
981 {
982     Unit *unit = NULL;
983 
984     if (side != NULL) {
985 	if (prevunit == NULL)
986 	  prevunit = side->unithead;
987 	for (unit = prevunit->next; unit != prevunit; unit = unit->next) {
988 	    if (is_unit(unit) && unit->id > 0
989 		&& alive(unit)
990 		&& inside_area(unit->x, unit->y)) {
991 		return unit;
992 	    }
993 	}
994     }
995     return NULL;
996 }
997 
998 Unit *
find_prev_unit(Side * side,Unit * nextunit)999 find_prev_unit(Side *side, Unit *nextunit)
1000 {
1001     Unit *unit = NULL;
1002 
1003     if (side != NULL) {
1004 	if (nextunit == NULL) nextunit = side->unithead;
1005 	for (unit = nextunit->prev; unit != nextunit; unit = unit->prev) {
1006 	    if (is_unit(unit) && unit->id > 0
1007 		&& alive(unit)
1008 		&& inside_area(unit->x, unit->y)) {
1009 		return unit;
1010 	    }
1011 	}
1012     }
1013     return NULL;
1014 }
1015 
1016 Unit *
find_next_actor(Side * side,Unit * prevunit)1017 find_next_actor(Side *side, Unit *prevunit)
1018 {
1019     Unit *unit = NULL;
1020 
1021     if (side != NULL) {
1022 	if (prevunit == NULL) prevunit = side->unithead;
1023 	for (unit = prevunit->next; unit != prevunit; unit = unit->next) {
1024 	    if (is_unit(unit) && unit->id > 0
1025 		&& alive(unit)
1026 		&& inside_area(unit->x, unit->y)
1027 		&& (unit->act && unit->act->initacp)) {
1028 		return unit;
1029 	    }
1030 	}
1031     }
1032     return NULL;
1033 }
1034 
1035 Unit *
find_prev_actor(Side * side,Unit * nextunit)1036 find_prev_actor(Side *side, Unit *nextunit)
1037 {
1038     Unit *unit = NULL;
1039 
1040     if (side != NULL) {
1041 	if (nextunit == NULL)
1042 	  nextunit = side->unithead;
1043 	for (unit = nextunit->prev; unit != nextunit; unit = unit->prev) {
1044 	    if (is_unit(unit) && unit->id > 0
1045 		&& alive(unit)
1046 		&& inside_area(unit->x, unit->y)
1047 		&& (unit->act && unit->act->initacp)) {
1048 		return unit;
1049 	    }
1050 	}
1051     }
1052     return NULL;
1053 }
1054 
1055 Unit *
find_next_mover(Side * side,Unit * prevunit)1056 find_next_mover(Side *side, Unit *prevunit)
1057 {
1058     Unit *unit = NULL;
1059 
1060     if (side != NULL) {
1061 	if (prevunit == NULL)
1062 	  prevunit = side->unithead;
1063 	for (unit = prevunit->next; unit != prevunit; unit = unit->next) {
1064 	    if (is_unit(unit) && unit->id > 0
1065 		&& alive(unit)
1066 		&& inside_area(unit->x, unit->y)
1067 		&& has_acp_left(unit)) {
1068 		return unit;
1069 	    }
1070 	}
1071     }
1072     return NULL;
1073 }
1074 
1075 Unit *
find_prev_mover(Side * side,Unit * nextunit)1076 find_prev_mover(Side *side, Unit *nextunit)
1077 {
1078     Unit *unit = NULL;
1079 
1080     if (side != NULL) {
1081 	if (nextunit == NULL)
1082 	  nextunit = side->unithead;
1083 	for (unit = nextunit->prev; unit != nextunit; unit = unit->prev) {
1084 	    if (is_unit(unit) && unit->id > 0
1085 		&& alive(unit)
1086 		&& inside_area(unit->x, unit->y)
1087 		&& has_acp_left(unit)) {
1088 		return unit;
1089 	    }
1090 	}
1091     }
1092     return NULL;
1093 }
1094 
1095 Unit *
find_next_awake_mover(Side * side,Unit * prevunit)1096 find_next_awake_mover(Side *side, Unit *prevunit)
1097 {
1098     Unit *unit = NULL;
1099 
1100     if (side != NULL) {
1101 	if (prevunit == NULL)
1102 	  prevunit = side->unithead;
1103 	for (unit = prevunit->next; unit != prevunit; unit = unit->next) {
1104 	    if (is_unit(unit)
1105 		&& unit->id > 0
1106 		&& alive(unit)
1107 		&& inside_area(unit->x, unit->y)
1108 		&& has_acp_left(unit)
1109 		&& (unit->plan
1110 		    && !unit->plan->asleep
1111 		    && !unit->plan->reserve
1112 		    && !unit->plan->delayed)) {
1113 		return unit;
1114 	    }
1115 	}
1116     }
1117     return NULL;
1118 }
1119 
1120 Unit *
find_prev_awake_mover(Side * side,Unit * nextunit)1121 find_prev_awake_mover(Side *side, Unit *nextunit)
1122 {
1123     Unit *unit = NULL;
1124 
1125     if (side != NULL) {
1126 	if (nextunit == NULL) nextunit = side->unithead;
1127 	for (unit = nextunit->prev; unit != nextunit; unit = unit->prev) {
1128 	    if (is_unit(unit) && unit->id > 0
1129 		&& alive(unit)
1130 		&& inside_area(unit->x, unit->y)
1131 		&& has_acp_left(unit)
1132 		&& (unit->plan
1133 		    && !unit->plan->asleep
1134 		    && !unit->plan->reserve
1135 		    && !unit->plan->delayed)) {
1136 		return unit;
1137 	    }
1138 	}
1139     }
1140     return NULL;
1141 }
1142 
1143 /* Compute the total number of action points available to the side at the
1144    beginning of the turn. */
1145 
1146 int
side_initacp(Side * side)1147 side_initacp(Side *side)
1148 {
1149     int totacp = 0;
1150     Unit *unit;
1151 
1152     for_all_side_units(side, unit) {
1153 	if (alive(unit) && unit->act) {
1154 	    totacp += unit->act->initacp;
1155 	}
1156     }
1157     return totacp;
1158 }
1159 
1160 /* Return the total of acp still unused by the side. */
1161 
1162 int
side_acp(Side * side)1163 side_acp(Side *side)
1164 {
1165     int acpleft = 0;
1166     Unit *unit;
1167 
1168     for_all_side_units(side, unit) {
1169 	if (alive(unit) && unit->act) {
1170 	    acpleft += unit->act->acp;
1171 	}
1172     }
1173     return acpleft;
1174 }
1175 
1176 int
side_acp_reserved(Side * side)1177 side_acp_reserved(Side *side)
1178 {
1179     int acpleft = 0;
1180     Unit *unit;
1181 
1182     for_all_side_units(side, unit) {
1183 	if (alive(unit) && unit->act) {
1184 		if (unit->plan
1185 		    && (unit->plan->reserve || unit->plan->asleep)) {
1186 	    	acpleft += unit->act->acp;
1187 	    }
1188 	}
1189     }
1190     return acpleft;
1191 }
1192 
1193 #if 0  /* not presently needed, but possibly useful */
1194 /* Return the total of acp still expected to be used by a human player. */
1195 
1196 int
1197 side_acp_human(Side *side)
1198 {
1199     int acpleft = 0;
1200     Unit *unit;
1201 
1202     if (!side_has_display(side))
1203       return acpleft;
1204 
1205     for_all_side_units(side, unit) {
1206 	if (unit != NULL
1207 	    && alive(unit)
1208 	    && inside_area(unit->x, unit->y)
1209 	    && has_acp_left(unit)
1210 	    && (unit->plan
1211 		&& !unit->plan->asleep
1212 		&& !unit->plan->reserve
1213 		&& unit->plan->tasks == NULL)) {
1214 		acpleft += unit->act->acp;
1215 	}
1216     }
1217     return acpleft;
1218 }
1219 #endif
1220 
1221 /* (note that technology could be "factored out" of a game if all sides
1222    reach max tech at some point) */
1223 /* (otherwise should compute once and cache) */
1224 /* (note that once tech factors out, can never factor in again) */
1225 
1226 int
using_tech_levels(void)1227 using_tech_levels(void)
1228 {
1229     int u;
1230     Side *side;
1231 
1232     for_all_sides(side) {
1233 	for_all_unit_types(u) {
1234 	    if (side->tech[u] < u_tech_max(u))
1235 	      return TRUE;
1236 	}
1237     }
1238     return FALSE;
1239 }
1240 
1241 /* Take the given side out of the game entirely.  This does not imply
1242    winning or losing, nor does it take down the side's display or AI. */
1243 
1244 void
remove_side_from_game(Side * side)1245 remove_side_from_game(Side *side)
1246 {
1247     Side *side2;
1248 
1249     /* Officially flag this side as being no longer in the game. */
1250     side->ingame = FALSE;
1251     /* Update everybody on this. */
1252     for_all_sides(side2) {
1253 	update_side_display(side2, side, TRUE);
1254     }
1255     /* Note that we no longer try to remove any images from other sides'
1256        views, because even with the side gone, the images may be useful
1257        information about where its units had gotten to.  For instance,
1258        if a unit had been captured shortly before the side lost, then its
1259        image might still correspond to an actual unit, with only its side
1260        changed, and other sides may want to investigate for themselves. */
1261 }
1262 
1263 int
num_displayed_sides(void)1264 num_displayed_sides(void)
1265 {
1266     int n = 0;
1267     Side *side;
1268 
1269     for_all_sides(side) {
1270 	if (side_has_display(side))
1271 	  ++n;
1272     }
1273     return n;
1274 }
1275 
1276 void
update_side_display_all_sides(Side * side,int rightnow)1277 update_side_display_all_sides(Side *side, int rightnow)
1278 {
1279     Side *side2;
1280 
1281     for_all_sides(side2) {
1282 	if (side_has_display(side2)) {
1283 	    update_side_display(side2, side, rightnow);
1284 	}
1285     }
1286 }
1287 
1288 void
set_side_name(Side * side,Side * side2,char * newname)1289 set_side_name(Side *side, Side *side2, char *newname)
1290 {
1291     side2->name = newname;
1292     update_side_display_all_sides(side2, TRUE);
1293 }
1294 
1295 void
set_side_longname(Side * side,Side * side2,char * newname)1296 set_side_longname(Side *side, Side *side2, char *newname)
1297 {
1298     side2->longname = newname;
1299     update_side_display_all_sides(side2, TRUE);
1300 }
1301 
1302 void
set_side_shortname(Side * side,Side * side2,char * newname)1303 set_side_shortname(Side *side, Side *side2, char *newname)
1304 {
1305     side2->shortname = newname;
1306     update_side_display_all_sides(side2, TRUE);
1307 }
1308 
1309 void
set_side_noun(Side * side,Side * side2,char * newname)1310 set_side_noun(Side *side, Side *side2, char *newname)
1311 {
1312     side2->noun = newname;
1313     update_side_display_all_sides(side2, TRUE);
1314 }
1315 
1316 void
set_side_pluralnoun(Side * side,Side * side2,char * newname)1317 set_side_pluralnoun(Side *side, Side *side2, char *newname)
1318 {
1319     side2->pluralnoun = newname;
1320     update_side_display_all_sides(side2, TRUE);
1321 }
1322 
1323 void
set_side_adjective(Side * side,Side * side2,char * newname)1324 set_side_adjective(Side *side, Side *side2, char *newname)
1325 {
1326     side2->adjective = newname;
1327     update_side_display_all_sides(side2, TRUE);
1328 }
1329 
1330 void
set_side_emblemname(Side * side,Side * side2,char * newname)1331 set_side_emblemname(Side *side, Side *side2, char *newname)
1332 {
1333     side2->emblemname = newname;
1334     update_side_display_all_sides(side2, TRUE);
1335 }
1336 
1337 void
set_side_colorscheme(Side * side,Side * side2,char * newname)1338 set_side_colorscheme(Side *side, Side *side2, char *newname)
1339 {
1340     side2->colorscheme = newname;
1341     update_side_display_all_sides(side2, TRUE);
1342 }
1343 
1344 #ifdef DESIGNERS
1345 
1346 /* Implement the transition from regular side to a side that can
1347    alter the game's state directly (aka "designer"). */
1348 
1349 void
become_designer(Side * side)1350 become_designer(Side *side)
1351 {
1352     Side *side2;
1353 
1354     if (side->designer)
1355       return;
1356     side->designer = TRUE;
1357     ++numdesigners;
1358     /* Designers have godlike power in the game, so mark it (permanently)
1359        as no longer a normal game. */
1360     compromised = TRUE;
1361     /* Designers get to see everything if they want, but it's useful
1362        to see a player view sometimes, so give designers the ability
1363        to toggle the accurate display.  Note that we must leave the
1364        side's see_all at its original value, so that unit views
1365        continue to be constructed and manipulated properly. */
1366     if (!side->see_all)
1367       side->may_set_show_all = TRUE;
1368     side->show_all = TRUE;
1369     place_legends(side);
1370     update_everything();
1371     /* Let everybody know of the change in status. */
1372     notify_all("%s IS NOW A DESIGNER.", short_side_title(side));
1373     for_all_sides(side2) {
1374 	update_side_display(side2, side, TRUE);
1375     }
1376 }
1377 
1378 /* Give up the godlike powers. */
1379 
1380 void
become_nondesigner(Side * side)1381 become_nondesigner(Side *side)
1382 {
1383     Side *side2;
1384 
1385     if (!side->designer)
1386       return;
1387     side->designer = FALSE;
1388     --numdesigners;
1389     /* Go back to the original viewing capabilities. */
1390     side->may_set_show_all = FALSE;
1391     side->show_all = side->see_all;
1392     place_legends(side);
1393     update_everything();
1394     notify_all("%s is no longer a designer.", short_side_title(side));
1395     for_all_sides(side2) {
1396 	update_side_display(side2, side, TRUE);
1397     }
1398 }
1399 
1400 #endif /* DESIGNERS */
1401 
1402 /* Return TRUE if side1 trusts side2.  Note that the nature of trust
1403    is such that we don't want to check that the trust is mutual
1404    (although in practice it would be a foolish player who would trust
1405    a side that doesn't reciprocate!) */
1406 
1407 int
trusted_side(Side * side1,Side * side2)1408 trusted_side(Side *side1, Side *side2)
1409 {
1410     if (side1 == side2)
1411       return TRUE;
1412     if (side1 == NULL || side2 == NULL || side1->trusts == NULL)
1413       return FALSE;
1414     return (side1->trusts[side2->id]);
1415 }
1416 
1417 void
set_trust(Side * side,Side * side2,int val)1418 set_trust(Side *side, Side *side2, int val)
1419 {
1420     int oldval;
1421     Side *side3;
1422 
1423     if (side == side2)
1424       return;
1425     if (side->trusts == NULL)
1426       return;
1427     oldval = side->trusts[side2->id];
1428     if (val == oldval)
1429       return;
1430     side->trusts[side2->id] = val;
1431     /* This is a major change that all other sides will know about. */
1432     for_all_sides(side3) {
1433 	if (active_display(side3)) {
1434 	    /* (should be handled by nlang.c) */
1435 	    notify(side3, "%s %s %s",
1436 		   side_name(side),
1437 		   (val ? "now trusts" : "no longer trusts"),
1438 		   side_name(side2));
1439 	    update_side_display(side3, side, FALSE);
1440 	    update_side_display(side3, side2, TRUE);
1441 	}
1442     }
1443     /* (should update views, list of units known about, etc) */
1444     /* (if cell goes from exact to only recorded, update display anyhow) */
1445 }
1446 
1447 void
set_controlled_by(Side * side,Side * side2,int val)1448 set_controlled_by(Side *side, Side *side2, int val)
1449 {
1450     char tmpbuf[BUFSIZE];
1451     int changed = FALSE;
1452 
1453     if (side == NULL || side2 == NULL || side == side2)
1454       return;
1455     if (val) {
1456 	/* Make side be controlled. */
1457 	if (side->controlled_by == NULL) {
1458 	    side->controlled_by = side2;
1459 	    /* (should rework unit movement vectors now?) */
1460 	    changed = TRUE;
1461 	} else {
1462 	    /* Can't happen. */
1463 	}
1464     } else {
1465 	/* Make side be uncontrolled. */
1466 	if (side->controlled_by == side2) {
1467 	    side->controlled_by = NULL;
1468 	    /* (should rework unit movement vectors now?) */
1469 	    changed = TRUE;
1470 	} else {
1471 	    /* Can't happen. */
1472 	}
1473     }
1474     if (changed) {
1475 	strcpy(tmpbuf, short_side_title(side2));
1476 	/* (should be handled by nlang.c) */
1477 	notify_all("%s%s control%s %s now.",
1478 		   tmpbuf,
1479 		   (val ? "" : " no longer"),
1480 		   (short_side_title_plural_p(side2) ? "" : "s"),
1481 		   short_side_title(side));
1482     }
1483 }
1484 
1485 /* What interfaces should use to tweak the autofinish flag. */
1486 
1487 void
set_autofinish(Side * side,int value)1488 set_autofinish(Side *side, int value)
1489 {
1490     side->autofinish = value;
1491 }
1492 
1493 /* What interfaces should use to tweak the autoresearch flag. */
1494 
1495 void
set_autoresearch(Side * side,int value)1496 set_autoresearch(Side *side, int value)
1497 {
1498     side->autoresearch = value;
1499 }
1500 
1501 /* Being at war requires only ones of the sides to consider itself so. */
1502 
1503 /* (Should the other side's relationships be tweaked also?) */
1504 
1505 int
enemy_side(Side * side1,Side * side2)1506 enemy_side(Side *side1, Side *side2)
1507 {
1508     if (trusted_side(side1, side2))
1509       return FALSE;
1510     return TRUE;
1511 }
1512 
1513 /* A formal alliance requires the agreement of both sides. */
1514 
1515 int
allied_side(Side * side1,Side * side2)1516 allied_side(Side *side1, Side *side2)
1517 {
1518     if (trusted_side(side1, side2))
1519       return TRUE;
1520     return FALSE;
1521 }
1522 
1523 /* Neutralness is basically anything else. */
1524 
1525 int
neutral_side(Side * side1,Side * side2)1526 neutral_side(Side *side1, Side *side2)
1527 {
1528     return (!enemy_side(side1, side2) && !allied_side(side1, side2));
1529 }
1530 
1531 void
set_willing_to_save(Side * side,int flag)1532 set_willing_to_save(Side *side, int flag)
1533 {
1534     int oldflag = side->willingtosave;
1535     Side *side2;
1536 
1537     if (flag != oldflag) {
1538 	side->willingtosave = flag;
1539 	/* Inform everybody of our willingness to save. */
1540 	for_all_sides(side2) {
1541 	    if (active_display(side2)) {
1542 		notify(side2, "%s is%s willing to save the game.",
1543 			      side_name(side), (flag ? "" : " not"));
1544 		update_side_display(side2, side, TRUE);
1545 	    }
1546 	}
1547     }
1548 }
1549 
1550 void
set_willing_to_draw(Side * side,int flag)1551 set_willing_to_draw(Side *side, int flag)
1552 {
1553     int oldflag = side->willingtodraw;
1554     Side *side2;
1555 
1556     if (flag != oldflag) {
1557 	side->willingtodraw = flag;
1558 	/* Inform everybody of our willingness to draw. */
1559 	for_all_sides(side2) {
1560 	    if (active_display(side2)) {
1561 		notify(side2, "%s is%s willing to declare the game a draw.",
1562 			      side_name(side), (flag ? "" : " not"));
1563 		update_side_display(side2, side, TRUE);
1564 	    }
1565 	}
1566     }
1567 }
1568 
1569 /* Set the self-unit of the given side.  This is only called when done at
1570    the direction of the side, and may fail if the side can't change its
1571    self-unit voluntarily. */
1572 
1573 void
set_side_self_unit(Side * side,Unit * unit)1574 set_side_self_unit(Side *side, Unit *unit)
1575 {
1576     if (!in_play(unit))
1577       return;
1578     if (side->self_unit
1579         && in_play(side->self_unit)
1580         && !u_self_changeable(side->self_unit->type))
1581       return;
1582     side->self_unit = unit;
1583     /* (should update some part of display?) */
1584 }
1585 
1586 /* Message-forwarding function. */
1587 
1588 void
send_message(Side * side,SideMask sidemask,char * str)1589 send_message(Side *side, SideMask sidemask, char *str)
1590 {
1591     char *sidedesc, buf[BUFSIZE];
1592     SideMask testmask;
1593     Side *side2, *sender;
1594 
1595     sender = side;
1596     testmask = add_side_to_set(side, NOSIDES);
1597     if (sidemask == NOSIDES || empty_string(str)) {
1598 	notify(side, "You say nothing.");
1599 	return;
1600     } else if (sidemask == testmask) {
1601 	notify(side, "You mumble to yourself.");
1602 	return;
1603     } else if (sidemask == ALLSIDES) {
1604 	notify(side, "You broadcast \"%s\" to all.", str);
1605     } else {
1606     	sidedesc = sidemask_desc(buf, sidemask);
1607 	notify(side, "You send \"%s\" to \"%s\".", str, sidedesc);
1608     }
1609     /* Handle messages that are to have anonymous senders. */
1610     if (strlen(str) > 6  && strncmp(str, "(anon)", 6) == 0) {
1611 	str += 6;
1612 	sender = NULL;
1613     }
1614     for_all_sides(side2) {
1615 	if (side2 != side && side_in_set(side2, sidemask)) {
1616 	    receive_message(side2, sender, str);
1617 	}
1618     }
1619 }
1620 
1621 /* Handle the receipt of a message.  Some messages may result in specific
1622    actions, but the default is just to forward to AIs and displays. */
1623 
1624 void
receive_message(Side * side,Side * sender,char * str)1625 receive_message(Side *side, Side *sender, char *str)
1626 {
1627     /* Look for specially-recognized messages. */
1628     if (strcmp("%reveal", str) == 0) {
1629 	reveal_side(sender, side, NULL);
1630     } else {
1631 	/* Give the message to interface if present. */
1632 	if (side_has_display(side)) {
1633 	    update_message_display(side, sender, str, TRUE);
1634 	}
1635 	/* Also give the message to any local AI. */
1636 	if (side_has_ai(side)) {
1637 	    ai_receive_message(side, sender, str);
1638 	}
1639     }
1640 }
1641 
1642 /* General method for passing along info about one side to another. */
1643 
1644 void
reveal_side(Side * sender,Side * recipient,int * types)1645 reveal_side(Side *sender, Side *recipient, int *types)
1646 {
1647     int x, y;
1648     Unit *unit;
1649 
1650     if (sender == NULL)
1651       return;
1652     if (g_see_all())
1653       return;
1654     if (!g_terrain_seen()) {
1655 	for_all_cells(x, y) {
1656 	    if (terrain_view(sender, x, y) != UNSEEN
1657 	        && terrain_view(recipient, x, y) == UNSEEN) {
1658 	        set_terrain_view(recipient, x, y, terrain_view(sender, x, y));
1659 	        /* (should update unit views also) */
1660 	    }
1661 	}
1662     }
1663     for_all_side_units(sender, unit) {
1664 	if (in_play(unit) && (types == NULL || types[unit->type])) {
1665 	    see_exact(recipient, unit->x, unit->y);
1666 	}
1667     }
1668     /* Whether the amount of data is small or large, there is little value
1669        in being selective about updates - just redo entire maps. */
1670     update_area_display(recipient);
1671 }
1672 
1673 /* Modify doctrine according to a specification. */
1674 
1675 void
set_doctrine(Side * side,char * spec)1676 set_doctrine(Side *side, char *spec)
1677 {
1678     int u;
1679     char *arg, *arg2, *rest, substr[BUFSIZE];
1680     Doctrine *doctrine;
1681 
1682     rest = get_next_arg(spec, substr, &arg);
1683     if ((doctrine = find_doctrine_by_name(arg)) != NULL) {
1684 	/* Found a specific named doctrine. */
1685     } else if ((u = utype_from_name(arg)) != NONUTYPE) {
1686 	doctrine = side->udoctrine[u];
1687     } else if (strcmp(arg, "default") == 0) {
1688 	doctrine = side->default_doctrine;
1689     }
1690     if (doctrine->locked) {
1691 	/* (should mention name of doctrine) */
1692 	notify(side, "This doctrine cannot be changed!");
1693 	return;
1694     }
1695     rest = get_next_arg(rest, substr, &arg);
1696     if (strcmp(arg, "resupply") == 0) {
1697 	rest = get_next_arg(rest, substr, &arg2);
1698 	doctrine->resupply_percent = atoi(arg2);
1699     } else if (strcmp(arg, "rearm") == 0) {
1700 	rest = get_next_arg(rest, substr, &arg2);
1701 	doctrine->rearm_percent = atoi(arg2);
1702     } else if (strcmp(arg, "repair") == 0) {
1703 	rest = get_next_arg(rest, substr, &arg2);
1704 	doctrine->repair_percent = atoi(arg2);
1705     } else if (strcmp(arg, "run") == 0) {
1706 	notify(side, "Can't modify construction runs yet");
1707     } else {
1708 	notify(side, "\"%s\" not a known doctrine property", arg);
1709 	notify(side, "Known ones are: ask, resupply, rearm, repair, run");
1710     }
1711 }
1712 
1713 void
set_side_research_topic(Side * side,int a)1714 set_side_research_topic(Side *side, int a)
1715 {
1716     side->research_topic = a;
1717 }
1718 
1719 void
set_side_research_goal(Side * side,int a)1720 set_side_research_goal(Side *side, int a)
1721 {
1722     side->research_goal = a;
1723 }
1724 
1725 void
set_side_startx(Side * side,int x)1726 set_side_startx(Side *side, int x)
1727 {
1728     side->startx = x;
1729 }
1730 
1731 void
set_side_starty(Side * side,int y)1732 set_side_starty(Side *side, int y)
1733 {
1734     side->starty = y;
1735 }
1736 
1737 /* Vision. */
1738 
1739 UnitView *
unit_view_at(Side * side,int x,int y)1740 unit_view_at(Side *side, int x, int y)
1741 {
1742     int hash;
1743     UnitView *uv;
1744 
1745     /* This might be called during synthesis, before sides are set up. */
1746     if (side->unit_views == NULL)
1747       return NULL;
1748     hash = (wrapx(x) ^ y) % VIEW_HASH_SIZE;
1749     for (uv = side->unit_views[hash]; uv != NULL; uv = uv->nextinhash) {
1750 	if (wrapx(x) == uv->x
1751 	    && y == uv->y
1752 	    && uv->transport == NULL) {
1753 		return uv;
1754     	}
1755     }
1756     return NULL;
1757 }
1758 
1759 UnitView *
unit_view_next(Side * side,int x,int y,UnitView * uview)1760 unit_view_next(Side *side, int x, int y, UnitView *uview)
1761 {
1762     UnitView *uv2;
1763 
1764     /* If we are looking among the side views. */
1765     if (side) {
1766 	for (uv2 = uview->nextinhash; uv2 != NULL; uv2 = uv2->nextinhash) {
1767 	    if (wrapx(x) == uv2->x && y == uv2->y && uv2->transport == NULL)
1768 	      return uv2;
1769 	}
1770     }
1771     /* If we are looking among master views. */
1772     else
1773       return uview->nexthere;
1774     return NULL;
1775 }
1776 
1777 /* Look for an existing unit view that is tied to the given unit. */
1778 
1779 UnitView *
find_unit_view(Side * side,Unit * unit)1780 find_unit_view(Side *side, Unit *unit)
1781 {
1782     UnitView *uv, *ov;
1783     int i;
1784 
1785     if (!side) {
1786 	update_master_uview(unit, FALSE);
1787 	return unit->uview;
1788     }
1789     if (side->unit_views == NULL) {
1790 	return NULL;
1791     }
1792     for (i = 0; i < VIEW_HASH_SIZE; ++i) {
1793 	for (uv = side->unit_views[i]; uv != NULL; uv = uv->nextinhash) {
1794 	    if (uv->id == unit->id) {
1795 		return uv;
1796 	    }
1797 	    /* Also check all the occupant views. */
1798 	    for_all_occupant_views_with_occs(uv, ov) {
1799 		if (ov->id == unit->id) {
1800 		    return ov;
1801 		}
1802 	    }
1803 	}
1804     }
1805     return NULL;
1806 }
1807 
1808 /*! \todo This function will need to be modified to behave differently for
1809 	    clients and servers once we are about to do the client-server
1810 	    separation. For clients, it will actually send a network query
1811 	    to the server asking if we can get back a shadow unit for the
1812 	    unit handle stored with the uview. NULL will be returned by the
1813 	    function if the network response is no unit, else a pointer to
1814 	    the shadow unit will be returned. For the server, it will simply
1815 	    return a pointer to the actual unit associated with the uview.
1816 	    For now, we default to the server behavior.
1817 */
1818 
1819 Unit *
query_unit_from_uview(UnitView * uview)1820 query_unit_from_uview(UnitView *uview)
1821 {
1822     return view_unit(uview);
1823 }
1824 
1825 /* Get the updated master uview for a given unit. */
1826 /*! \note This function (as well as a number of others) will have to be
1827 	  changed to take a unit handle of some sort (perhaps unit ID) when
1828 	  true client-server separation is done. There will also be two
1829 	  separate functions: one that does the client query and gets back
1830 	  the mashalled uview, and one that handles the query on the server
1831 	  side, and marshals an appropriate response back to the client. */
1832 /* {Client and Arbiter Function} */
1833 
1834 UnitView *
query_uvstack_from_unit(Unit * unit)1835 query_uvstack_from_unit(Unit *unit)
1836 {
1837     /* If an out-of-play unit was given, then return a NULL uview. */
1838     if (!in_play(unit))
1839       return NULL;
1840     /* Update the master uview first. */
1841     update_master_uview(unit, FALSE);
1842     /* Return the master uview. */
1843     return unit->uview;
1844 }
1845 
1846 /* Get the uvstack for a given location from an omniscient perspective. */
1847 /*! \note See note for 'query_uvstack_from_unit'. */
1848 /* {Client and Arbiter Function} */
1849 
1850 UnitView *
query_uvstack_at(int x,int y)1851 query_uvstack_at(int x, int y)
1852 {
1853     Unit *unit = NULL;
1854 
1855     /* If x and y are out-of-area, then return a NULL uview. */
1856     if (!inside_area(x, y))
1857       return NULL;
1858     /* Get the unit at given location, if any. */
1859     unit = unit_at(x, y);
1860     /* If no unit is there, then return NULL. */
1861     if (!unit)
1862       return NULL;
1863     /* Else, get uview stack from unit. */
1864     return query_uvstack_from_unit(unit);
1865 }
1866 
1867 /* Find out if an uview is in the correct position in a stack (cell or
1868    transport), relative to another uview. */
1869 
1870 int
is_at_correct_uvstack_position(UnitView * uview,UnitView * uview2)1871 is_at_correct_uvstack_position(UnitView *uview, UnitView *uview2)
1872 {
1873     int u = NONUTYPE, u2 = NONUTYPE;
1874     int uso = -1, u2so = -1;
1875 
1876     assert_error(uview, "Attempted to place a NULL uview in a uvstack");
1877     assert_error(uview2, "Attempted to compare an uview in a NULL uvstack");
1878     u = uview->type;
1879     u2 = uview2->type;
1880     uso = u_stack_order(u);
1881     u2so = u_stack_order(u2);
1882     /* Enforce side ordering 1st. */
1883     /*! \todo Add support for holding units belonging to the dside first in
1884 	      the stack, last in the stack, or in the natural side order.
1885 	      Currently, only the natural side order is supported. */
1886     if (uview->siden > uview2->siden)
1887       return FALSE;
1888     if (uview->siden < uview2->siden)
1889       return TRUE;
1890     /* Enforce stack ordering 2nd. */
1891     if (uso < u2so)
1892       return FALSE;
1893     if (uso > u2so)
1894       return TRUE;
1895     /* Enforce utype ordering 3rd. */
1896     if (u > u2)
1897       return FALSE;
1898     if (u < u2)
1899       return TRUE;
1900     /* Enforce uview ID ordering 4th. */
1901     if (uview->id < uview2->id)
1902       return TRUE;
1903     return FALSE;
1904 }
1905 
1906 /* Add uview to the given transport's uvstack. */
1907 
1908 void
add_uview_to_uvstack(UnitView * uview,UnitView * tsptview)1909 add_uview_to_uvstack(UnitView *uview, UnitView *tsptview)
1910 {
1911     UnitView *topview = NULL, *occview = NULL, *nextview = NULL,
1912 	     *prevview = NULL;
1913 
1914     assert_error(uview, "Attempted to add a NULL uview to a uvstack");
1915     assert_error(tsptview,
1916 		 "Attempted to add an uview to a NULL transport uvstack");
1917     topview = tsptview->occupant;
1918     if (topview) {
1919 	/* Insert uview into the occupant list at its correct position. */
1920 	for_all_occupant_views(tsptview, occview) {
1921 	    if (is_at_correct_uvstack_position(uview, occview)) {
1922 		nextview = occview;
1923 #if (0)
1924 		if (uview == nextview->nexthere)
1925 		  nextview->nexthere = NULL;
1926 #endif
1927 		if (occview == topview)
1928 		  topview = uview;
1929 		break;
1930 	    }
1931 	    prevview = occview;
1932 	}
1933 	if (prevview != NULL) {
1934 	    prevview->nexthere = uview;
1935 	}
1936     } else {
1937 	topview = uview;
1938     }
1939     uview->nexthere = nextview;
1940     tsptview->occupant = topview;
1941 }
1942 
1943 /* Initialize and fill out an uview from unit data. */
1944 
1945 void
fill_out_uview(Unit * unit,Side * side,UnitView * uview)1946 fill_out_uview(Unit *unit, Side *side, UnitView *uview)
1947 {
1948     /* Sanity checks. */
1949     assert_error(unit, "Attempted to fill out an unit view with a NULL unit");
1950     assert_error(uview, "Attempted to fill out a NULL unit view");
1951     /* Fill out uview. */
1952     uview->observer = (side ? side->id : -1);
1953     uview->unit = unit;
1954     uview->x = unit->x;
1955     uview->y = unit->y;
1956     uview->siden = unit->side->id;
1957     uview->type = unit->type;
1958     uview->size = unit->size;
1959     uview->id = unit->id;
1960     uview->imf = unit->imf;
1961     uview->image_name = unit->image_name;
1962     uview->complete = completed(unit);
1963     uview->occupant = NULL;
1964     uview->transport = NULL;
1965     uview->nextinhash = NULL;
1966     uview->nexthere = NULL;
1967     uview->vnext = NULL;
1968 }
1969 
1970 /* Update the master uview of an unit. */
1971 
1972 void
update_master_uview(Unit * unit,int lookabove)1973 update_master_uview(Unit *unit, int lookabove)
1974 {
1975     UnitView *uview = NULL;
1976 
1977     /* Return immediately if no unit to update. */
1978     if (!unit)
1979       return;
1980     /* If we are to look above and the unit has a transport,
1981        then update the transport's view first. Once the top of the transport
1982        chain is reached, then occs (including this unit) will be filled out,
1983        and so there is no need to duplicate work. Thus, return afterword. */
1984     if (lookabove && unit->transport) {
1985 	update_master_uview(unit->transport, TRUE);
1986 	return;
1987     }
1988     /* Allocate the uview, if it does already exist. */
1989     uview = unit->uview;
1990     if (!uview) {
1991 	uview = (UnitView *)xmalloc(sizeof(UnitView));
1992 	unit->uview = uview;
1993     }
1994     /* Fill out the uview from unit. */
1995     fill_out_uview(unit, NULL, uview);
1996     /* Link with transport, if any. */
1997     uview->transport = (unit->transport ? unit->transport->uview : NULL);
1998     /* Recurse into and link with first occ, if any. */
1999     /* This will update all of the occ's occs and next neighbors. */
2000     if (unit->occupant)
2001       update_master_uview(unit->occupant, FALSE);
2002     uview->occupant = (unit->occupant ? unit->occupant->uview : NULL);
2003     /* Recurse into and link with next neighbor, if any. */
2004     /* This will update all of the neighbor's occs and next neighbors. */
2005     /* The 'nextinhash' field is also updated with the value of the next
2006        neighbor so that 'unit_view_next' will not be broken. */
2007     if (unit->nexthere)
2008       update_master_uview(unit->nexthere, FALSE);
2009     uview->nexthere = (unit->nexthere ? unit->nexthere->uview : NULL);
2010     uview->nextinhash = uview->nexthere;
2011 }
2012 
2013 /* Add a new unit view to the side's unit views. */
2014 
2015 UnitView *
add_unit_view(Side * side,Unit * unit)2016 add_unit_view(Side *side, Unit *unit)
2017 {
2018     int changed = FALSE, rehash = FALSE, x, y;
2019     UnitView *tranview = NULL, *uview = NULL, *occview = NULL;
2020     Unit *occ;
2021 
2022     /* We need to create any transport view first to avoid an infinite
2023        loop between transport and occupant. */
2024     if (unit->transport) {
2025 	tranview = find_unit_view(side, unit->transport);
2026 	if (tranview == NULL) {
2027 	    /* Recursive. Will climb up transport tree if necessary. */
2028 	    tranview = add_unit_view(side, unit->transport);
2029 	    /* Since occupant views also get generated,
2030 	       we can return after this. */
2031 	    return find_unit_view(side, unit);
2032     	}
2033     }
2034     /* Now we check if our unit has a view. */
2035     uview = find_unit_view(side, unit);
2036     if (uview) {
2037     	x = uview->x;
2038     	y = uview->y;
2039 	/* Blast the view if it is in the wrong location,
2040 	   or if it has the wrong transport. */
2041 	if (x != unit->x
2042 	    || y != unit->y
2043 	    || (uview->transport && !unit->transport)
2044 	    || (!uview->transport && unit->transport)
2045 	    || (uview->transport && unit->transport
2046 	    	&& uview->transport->id != unit->transport->id)) {
2047 		remove_unit_view(side, uview);
2048 		uview = NULL;
2049 		/* Update the old cell display. */
2050 		update_cell_display(side, x, y, UPDATE_ALWAYS);
2051 	}
2052     }
2053     /* We need a new unit view. */
2054     if (uview == NULL) {
2055     	++numunitviews;
2056 	uview = create_bare_unit_view();
2057 	fill_out_uview(unit, side, uview);
2058 #if (0)
2059 	uview->observer = side->id;
2060 	uview->unit = unit;
2061 	uview->type = unit->type;
2062 	uview->size = unit->size;
2063 	uview->id = unit->id;
2064 	uview->imf = unit->imf;
2065 	uview->image_name = unit->image_name;
2066 	uview->complete = completed(unit);
2067 	uview->occupant = NULL;
2068 	uview->transport = tranview;
2069 	uview->nextinhash = NULL;
2070 	uview->nexthere = NULL;
2071 #endif
2072 	uview->transport = tranview;
2073 	/* Insert it into the global list. */
2074 	uview->vnext = viewlist;
2075 	viewlist = uview;
2076 	/* Splice uview into the hash table, but only if it is the image of a
2077 	   top unit. */
2078 	if (unit->transport == NULL) {
2079 	    add_unit_view_raw(side, uview, unit->x, unit->y);
2080 	/* Else splice uview into the occupant list of its transport view. */
2081 	} else {
2082 	    add_uview_to_uvstack(uview, tranview);
2083 	}
2084 	changed = TRUE;
2085     }
2086     if (uview->type != unit->type) {
2087 	uview->type = unit->type;
2088 	changed = TRUE;
2089     }
2090     if (uview->siden != unit->side->id) {
2091 	uview->siden = unit->side->id;
2092 	changed = TRUE;
2093     }
2094     if (uview->name != unit->name) {
2095 	uview->name = unit->name;
2096 	changed = TRUE;
2097     }
2098     if (uview->imf != unit->imf) {
2099 	uview->imf = unit->imf;
2100 	changed = TRUE;
2101     }
2102     if (uview->image_name != unit->image_name) {
2103 	uview->image_name = unit->image_name;
2104 	changed = TRUE;
2105     }
2106     if (uview->size != unit->size) {
2107 	uview->size = unit->size;
2108 	changed = TRUE;
2109     }
2110     if (uview->complete != completed(unit)) {
2111 	uview->complete = completed(unit);
2112 	changed = TRUE;
2113     }
2114     /* Clean out any stale occupant views. */
2115     for_all_occupant_views(uview, occview) {
2116 	remove_unit_view(side, occview);
2117     	changed = TRUE;
2118     }
2119     /* Add any occupant views that should be added. */
2120     if (unit->occupant && occupants_visible(side, unit)) {
2121 	uview->occupant = NULL;
2122 	for_all_occupants(unit, occ)
2123 	  add_unit_view(side, occ);
2124 	if (uview->occupant)
2125 	  changed = TRUE;
2126     }
2127     /* Irrespective of whether any view content changed, we now know
2128        that the view of this unit is current, so date it. */
2129     uview->date = g_turn();
2130     return (changed ? uview : NULL);
2131 }
2132 
2133 void
add_unit_view_raw(Side * side,UnitView * uview,int x,int y)2134 add_unit_view_raw(Side *side, UnitView *uview, int x, int y)
2135 {
2136     int hash;
2137     UnitView *uv2, *prevview;
2138 
2139     if (side->unit_views == NULL)
2140       side->unit_views =
2141 	(UnitView **) xmalloc(VIEW_HASH_SIZE * sizeof(UnitView *));
2142     prevview = NULL;
2143     hash = (wrapx(x) ^ y) % VIEW_HASH_SIZE;
2144     for (uv2 = side->unit_views[hash]; uv2 != NULL; uv2 = uv2->nextinhash) {
2145 	if (is_at_correct_uvstack_position(uview, uv2)) {
2146 	    break;
2147 	}
2148 	prevview = uv2;
2149     }
2150     uview->nextinhash = uv2;
2151     if (prevview == NULL) {
2152 	side->unit_views[hash] = uview;
2153     } else {
2154 	prevview->nextinhash = uview;
2155     }
2156     uview->x = x;
2157     uview->y = y;
2158 }
2159 
2160 int
remove_unit_view(Side * side,UnitView * olduview)2161 remove_unit_view(Side *side, UnitView *olduview)
2162 {
2163     int hash;
2164     UnitView *uv = NULL, *prevview = NULL;
2165 
2166     if (side->unit_views == NULL)
2167       return FALSE;
2168     prevview = uv = NULL;
2169     /* Splice the unit out of any occupant list. */
2170     if (olduview->transport) {
2171     	for_all_occupant_views(olduview->transport, uv) {
2172 	    if (olduview == uv) {
2173 		if (prevview == NULL) {
2174 		    olduview->transport->occupant = uv->nexthere;
2175 		} else {
2176 		    prevview->nexthere = uv->nexthere;
2177 		}
2178 		break;
2179 	    }
2180 	    prevview = uv;
2181      	}
2182     /* Else splice out the view from the hash table. */
2183     } else {
2184 	hash = (wrapx(olduview->x) ^ olduview->y) % VIEW_HASH_SIZE;
2185 	for (uv = side->unit_views[hash]; uv != NULL; uv = uv->nextinhash) {
2186 	    if (uv && uv == olduview) {
2187 		if (prevview == NULL) {
2188 		    side->unit_views[hash] = uv->nextinhash;
2189 		} else {
2190 		    prevview->nextinhash = uv->nextinhash;
2191 		}
2192 		break;
2193 	    }
2194 	    prevview = uv;
2195 	}
2196     }
2197     /* Then clean out the occupant views. */
2198     for_all_occupant_views(olduview, uv) {
2199     	remove_unit_view(side, uv);
2200     }
2201     /* Finally mark the view as garbage. But don't hit its links yet,
2202        since we might be traversing an occupant list here. */
2203     olduview->id = -1;
2204     return TRUE;
2205 }
2206 
2207 /* Get rid of all stale unit views at once. */
2208 
2209 void
flush_stale_views(void)2210 flush_stale_views(void)
2211 {
2212     UnitView *uview, *prevview, *nextuv;
2213     int n = 0;
2214 
2215     if (viewlist == NULL)
2216       return;
2217     uview = viewlist;
2218     while (uview->id == -1) {
2219 	nextuv = uview->vnext;
2220 	flush_one_view(uview);
2221 	uview = nextuv;
2222 	if (uview == NULL)
2223 	  break;
2224     }
2225     viewlist = uview;
2226     prevview = NULL;
2227     for_all_unit_views(uview) {
2228 	if (uview->id == -1) {
2229 	    nextuv = uview->vnext;
2230 	    prevview->vnext = uview->vnext;
2231 	    flush_one_view(uview);
2232 	    uview = prevview;
2233 	    ++n;
2234 	} else {
2235 	    prevview = uview;
2236 	}
2237     }
2238     Dprintf("%d stale unit views flushed.\n", n);
2239     Dprintf("%d unit views left.\n", numunitviews);
2240 }
2241 
2242 /* Keep it clean - hit all links to other places.  Some might not be
2243    strictly necessary, but this is not an area to take chances with. */
2244 
2245 static void
flush_one_view(UnitView * uview)2246 flush_one_view(UnitView *uview)
2247 {
2248     uview->occupant = NULL;
2249     uview->transport = NULL;
2250     uview->nextinhash = NULL;
2251     uview->vnext = NULL;
2252     /* Add it on the front of the list of available views. */
2253     uview->nexthere = freeviews;
2254     freeviews = uview;
2255     --numunitviews;
2256 }
2257 
2258 extern int do_fire_at_action(Unit *unit, Unit *unit2, Unit *unit3, int m);
2259 
2260 /* Check if one unit can perform overwatch fire upon another? */
2261 
2262 int
can_overwatch(Unit * ounit,Unit * unit)2263 can_overwatch(Unit *ounit, Unit *unit)
2264 {
2265     int u = NONUTYPE, ou = NONUTYPE;
2266     int range = -1;
2267     int rslt = A_ANY_OK;
2268 
2269     assert_error(ounit, "Attempted to access a NULL overwatcher");
2270     assert_error(unit, "Attempted to access a NULL unit");
2271     ou = ounit->type;
2272     u = unit->type;
2273     range = distance(ounit->x, ounit->y, unit->x, unit->y);
2274     if (!between(u_range_min(ou), range, u_range(ou)))
2275       return FALSE;
2276     if (!between(uu_zoo_range_min(ou, u), range, uu_zoo_range(ou, u)))
2277       return FALSE;
2278     if (0 >= fire_hit_chance(ou, u))
2279       return FALSE;
2280     /*! \todo Handle any other probablility checks. */
2281     /* Check if overwatcher can perform a valid fire. */
2282     rslt = check_fire_at_action(ounit, ounit, unit, -1);
2283     /* If so, then go for it. */
2284     if (valid(rslt))
2285       return TRUE;
2286     /* If not, it may simply be because of ACP. We need to check this case. */
2287     if ((A_ANY_NO_ACP == rslt) && unit->act) {
2288 	if (u_acp_to_fire(ou) <= (unit->act->acp + uu_acp_overwatch(ou, u)))
2289 	  return TRUE;
2290     }
2291     /* Else, assume that we can't. */
2292     return FALSE;
2293 }
2294 
2295 /* Check if any overwatchers in a particular cell. */
2296 /* (Search Predicate) */
2297 /* {Arbiter Function} */
2298 
2299 int
try_overwatch_from(int x,int y,int * counter,ParamBox * parambox)2300 try_overwatch_from(int x, int y, int *counter, ParamBox *parambox)
2301 {
2302     Unit *unit = NULL, *unit2 = NULL;
2303     int u = NONUTYPE;
2304     Side *oside = NULL;
2305     ParamBoxUnitSide *paramboxus = NULL;
2306 
2307     assert_warning_return(inside_area(x, y),
2308 			  "Tried to overwatch from outside playing area",
2309 			  FALSE);
2310     assert_error(parambox, "Attempted to use a NULL parambox");
2311     assert_error(PBOX_TYPE_UNIT_SIDE == parambox->get_type(),
2312 		 "Attempted to use wrong type of parambox in a search");
2313     paramboxus = (ParamBoxUnitSide *)parambox;
2314     assert_error(paramboxus->unit, "Attempted to access a NULL unit");
2315     assert_error(paramboxus->side,
2316 		 "Attempted to access a NULL overwatcher side");
2317     unit = paramboxus->unit;
2318     oside = paramboxus->side;
2319     u = unit->type;
2320     for_all_stack_with_occs(x, y, unit2) {
2321 	/* Skip any units that are not on the overwatching side. */
2322 	if (unit2->side != oside)
2323 	  continue;
2324 	/* Can the enemy unit perform overwatch fire against the
2325 	   given unit? */
2326 	if (can_overwatch(unit2, unit)) {
2327 	    if (unit2->act)
2328 	      unit2->act->acp += uu_acp_overwatch(unit2->type, u);
2329 	    do_fire_at_action(unit2, unit2, unit, -1);
2330 	    if (counter)
2331 	      ++(*counter);
2332 	    /*! \todo Limit by max num of overwatch firings for victim type. */
2333 	}
2334     }
2335     return FALSE;
2336 }
2337 
2338 /* Check if there any overwatch fire attempts against a given unit.
2339    If so, check if the fire action is valid by the overwatcher against the
2340    given unit. */
2341 /* {Arbiter Function} */
2342 
2343 void
try_overwatch_against(Unit * unit)2344 try_overwatch_against(Unit *unit)
2345 {
2346     Side *oside = NULL;
2347     UnitView *uview = NULL;
2348     int u = NONUTYPE;
2349     ParamBoxUnitSide paramboxus;
2350     int counter = 0;
2351 
2352     /* Sanity checks. */
2353     assert_error(unit, "Attempted to overwatch a NULL unit");
2354     u = unit->type;
2355     /* Compute cache, if necessary. */
2356     if (Xconq::any_overwatch_cache == -1)
2357       compute_overwatch_cache();
2358     /* Look through each side's view of the unit, if any. */
2359     for_all_sides(oside) {
2360 	/* Skip unit's side. */
2361 	if (unit->side == oside)
2362 	  continue;
2363 	/* If the side is not an enemy then skip its reaction. */
2364 	if (!enemy_side(unit->side, oside))
2365 	  continue;
2366 	/* Check if the side can see the given unit. */
2367 	uview = find_unit_view(oside, unit);
2368 	/* If not, then skip side's overwatch reaction. */
2369 	if (!uview)
2370 	  continue;
2371 	/* Setup the parambox for searching. */
2372 	paramboxus.unit = unit;
2373 	paramboxus.side = oside;
2374 	/* If side can see given unit, then start searching for overwatchers. */
2375 	if (0 >= Xconq::overwatch_against_range_min[u])
2376 	  try_overwatch_from(unit->x, unit->y, &counter, &paramboxus);
2377 	/*! \todo Search in ring starting from min range. */
2378 	/*! \todo Limit by max num of overwatch firings for victim type. */
2379 	limited_search_around(unit->x, unit->y,
2380 			      Xconq::overwatch_against_range_max[u],
2381 			      try_overwatch_from, 1, &counter,
2382 			      cover(oside, unit->x, unit->y),
2383 			      (ParamBox *)&paramboxus);
2384     }
2385     if (counter)
2386       Dprintf("%s received overwatch fire from %d units.\n",
2387 	      unit_desig(unit), counter);
2388 }
2389 
2390 /* What happens when a unit appears on a given cell. */
2391 
2392 /* An always-seen unit has builtin spies/tracers to inform everybody
2393    else of all its movements.  When such a unit occupies a cell,
2394    coverage is turned on and remains on until the unit leaves that
2395    cell. */
2396 
2397 /* If this unit with onboard spies wanders into unknown territory,
2398    shouldn't that territory become known as well?  I think the unseen
2399    test should only apply during initialization. */
2400 /* But if always-seen unit concealed during init, will magically appear
2401    when it first moves! */
2402 
2403 void
all_see_occupy(Unit * unit,int x,int y,int inopen)2404 all_see_occupy(Unit *unit, int x, int y, int inopen)
2405 {
2406     Side *side;
2407     int dir, x1, y1;
2408     Unit *unit2, *unit3;
2409     int u = NONUTYPE;
2410     int always = FALSE;
2411 
2412     assert_error(unit, "Attempted to create views of a NULL unit");
2413     u = unit->type;
2414     always = u_see_always(u);
2415     for_all_sides(side) {
2416 	if (side_sees_unit(side, unit)) {
2417 	    see_cell(side, x, y);
2418 	} else if (side_tracking_unit(side, unit)) {
2419 	    see_cell(side, x, y);
2420 	} else if (cover(side, x, y) > 0) {
2421 	    see_cell(side, x, y);
2422 	} else {
2423 	    if (always && terrain_view(side, x, y) != UNSEEN) {
2424 		add_cover(side, x, y, 1);
2425 		set_alt_cover(side, x, y, 0);
2426 	    }
2427 	    if (inopen || always) {
2428 		see_cell(side, x, y);
2429 	    }
2430 	}
2431     }
2432     /* If the occupation happens during the game, nearby units that
2433        are on unfriendly sides should wake up.  (should also be:
2434        "unless they were directed to sleep in presence of enemy") */
2435     if (gameinited) {
2436 	for_all_directions(dir) {
2437 	    if (interior_point_in_dir(x, y, dir, &x1, &y1)) {
2438 	   	for_all_stack(x1, y1, unit2) {
2439 	   	    if (unit2->side != NULL
2440 	   	    	&& unit2->side != unit->side
2441 	   	    	&& units_visible(unit2->side, x, y)
2442 	   	    	&& !unit_trusts_unit(unit2, unit)) {
2443 	   	    	wake_unit(unit2->side, unit2, FALSE);
2444 	   	    }
2445 	   	    for_all_occupants(unit2, unit3) {
2446 			if (unit3->side != NULL
2447 			    && unit3->side != unit->side
2448 			    && units_visible(unit3->side, x, y)
2449 			    && !unit_trusts_unit(unit3, unit)) {
2450 			    wake_unit(unit3->side, unit3, FALSE);
2451 			}
2452 	   	    }
2453 	   	}
2454 	    }
2455 	}
2456 	/* Check for any overwatch against the occupying unit. */
2457 	if (Xconq::any_overwatch_cache == -1)
2458 	  compute_overwatch_cache();
2459 	if (Xconq::any_overwatch_cache
2460 	    && get_packed_bool(Xconq::any_overwatch_chances, 0, u)
2461 	    && !Xconq::suppress_reactions)
2462 	  try_overwatch_against(unit);
2463     }
2464 }
2465 
2466 /* Some highly visible unit types cannot leave a cell without everybody
2467    knowing about the event.  The visibility is attached to the unit, not
2468    the cell, so first the newly-empty cell is viewed, then view coverage
2469    is decremented. */
2470 
2471 void
all_see_leave(Unit * unit,int x,int y,int inopen)2472 all_see_leave(Unit *unit, int x, int y, int inopen)
2473 {
2474     Side *side;
2475     int always = u_see_always(unit->type), domore, update;
2476     UnitView *uview;
2477 
2478     for_all_sides(side) {
2479 	if (side_sees_unit(side, unit)
2480 		   && in_area(unit->x, unit->y)) {
2481 	    see_cell(side, x, y);
2482 	} else if (side_tracking_unit(side, unit)) {
2483 	    see_cell(side, x, y);
2484 	} else if (cover(side, x, y) > 0) {
2485 	    see_cell(side, x, y);
2486 	} else {
2487 	    if (always && terrain_view(side, x, y) != UNSEEN) {
2488 		see_cell(side, x, y);
2489 		if (cover(side, x, y) > 0)
2490 		  add_cover(side, x, y, -1);
2491 		if (side->alt_coverage)
2492 		  /* (should recalc alt coverage, since was 0) */;
2493 	    }
2494 	    /* Won't be called twice, because view coverage is 0 now. */
2495 	    if (inopen) {
2496 		see_cell(side, x, y);
2497 	    }
2498 	    /* special hack to flush images we *know* are garbage */
2499 	    if (cover(side, x, y) < 1) {
2500 		domore = TRUE;
2501 		update = FALSE;
2502 		while (domore) {
2503 		    domore = FALSE;
2504 		    for_all_view_stack_with_occs(side, x, y, uview) {
2505 			if (side->id == uview->siden) {
2506 			    remove_unit_view(side, uview);
2507 			    domore = TRUE;
2508 			    update = TRUE;
2509 			    break;
2510 			}
2511 		    }
2512 		}
2513 		if (update)
2514 		  update_cell_display(side, x, y, UPDATE_ALWAYS);
2515 	    }
2516 	}
2517     }
2518 }
2519 
2520 static int tmpx0, tmpy0, tmpz0;
2521 static int tmpnx, tmpny, tmpnz;
2522 
2523 static void
init_visible_elevation(int x,int y)2524 init_visible_elevation(int x, int y)
2525 {
2526     int elev = checked_elev_at(x, y);
2527 
2528     set_tmp2_at(x, y, elev - tmpz0);
2529 }
2530 
2531 static void
init_visible_elevation_2(int x,int y)2532 init_visible_elevation_2(int x, int y)
2533 {
2534     int elev = checked_elev_at(x, y);
2535 
2536     set_tmp3_at(x, y, elev - tmpnz);
2537 }
2538 
2539 
2540 static void
calc_visible_elevation(int x,int y)2541 calc_visible_elevation(int x, int y)
2542 {
2543     int dir, x1, y1, elev, tmp, tmpa, tmpb;
2544     int adjelev = 9999, viselev, dist, dist1, cellwid = area.cellwidth;
2545 
2546     elev = checked_elev_at(x, y);
2547     dist = distance(x, y, tmpx0, tmpy0);
2548     if (cellwid <= 0)
2549       cellwid = 1;
2550     for_all_directions(dir) {
2551 	if (point_in_dir(x, y, dir, &x1, &y1)) {
2552 	    dist1 = distance(x1, y1, tmpx0, tmpy0);
2553 	    if (dist1 < dist) {
2554 		tmpa = tmp2_at(x1, y1);
2555 		/* Account for the screening effect of the elevation
2556                    difference. */
2557 		/* (dist1 will never be zero) */
2558 		tmpa = (tmpa * dist * cellwid) / (dist1 * cellwid);
2559 		tmpb = checked_elev_at(x1, y1)
2560 		  + t_thickness(terrain_at(x1, y1))
2561 		  - tmpz0;
2562 		tmpb = (tmpb * dist * cellwid) / (dist1 * cellwid);
2563 		tmp = max(tmpa, tmpb);
2564 		adjelev = min(adjelev, tmp + tmpz0);
2565 	    }
2566 	}
2567     }
2568     viselev = max(adjelev, elev);
2569     set_tmp2_at(x, y, viselev - tmpz0);
2570 }
2571 
2572 static void
calc_visible_elevation_2(int x,int y)2573 calc_visible_elevation_2(int x, int y)
2574 {
2575     int dir, x1, y1, elev, tmp, tmpa, tmpb;
2576     int adjelev = 9999, viselev, dist, dist1, cellwid = area.cellwidth;
2577 
2578     elev = checked_elev_at(x, y);
2579     dist = distance(x, y, tmpnx, tmpny);
2580     if (cellwid <= 0)
2581       cellwid = 1;
2582     for_all_directions(dir) {
2583 	if (point_in_dir(x, y, dir, &x1, &y1)) {
2584 	    dist1 = distance(x1, y1, tmpnx, tmpny);
2585 	    if (dist1 < dist) {
2586 		tmpa = tmp3_at(x1, y1);
2587 		/* Account for the screening effect of the elevation
2588                    difference. */
2589 		/* (dist1 will never be zero) */
2590 		tmpa = (tmpa * dist * cellwid) / (dist1 * cellwid);
2591 		tmpb = checked_elev_at(x1, y1)
2592 		  + t_thickness(terrain_at(x1, y1))
2593 		  - tmpnz;
2594 		tmpb = (tmpb * dist * cellwid) / (dist1 * cellwid);
2595 		tmp = max(tmpa, tmpb);
2596 		adjelev = min(adjelev, tmp + tmpnz);
2597 	    }
2598 	}
2599     }
2600     viselev = max(adjelev, elev);
2601     set_tmp3_at(x, y, viselev - tmpnz);
2602 }
2603 
2604 /* Unit's beady eyes are shifting from one location to another.  Since
2605    new things may be coming into view, we have to check and maybe draw
2606    lots of cells (but only need the one output flush, fortunately). */
2607 
2608 /* (LOS comes in here, to make irregular coverage areas) */
2609 
2610 void
cover_area(Side * side,Unit * unit,Unit * oldtransport,int x0,int y0,int nx,int ny)2611 cover_area(Side *side, Unit *unit, Unit *oldtransport, int x0, int y0,
2612 	   int nx, int ny)
2613 {
2614     Side *side2;
2615 
2616     if (side != NULL
2617 	&& completed(unit)
2618 	&& (oldtransport == NULL
2619 	   || uu_occ_vision(unit->type, oldtransport->type) > 0)) {
2620 	if (side->ingame) {
2621 	    /* Active sides keep their allies informed.  Note that
2622 	       this will effectively leak information to allies of
2623 	       allies, even if the unit's side is not an ally
2624 	       directly. */
2625 	    for_all_sides(side2) {
2626 		if (trusted_side(side, side2)
2627 		    || side2->see_all) {
2628 		    cover_area_1(side2, unit, x0, y0, nx, ny);
2629 		}
2630 	    }
2631 	} else {
2632 	    /* Inactive sides just have their own data maintained
2633 	       (not clear if this is critical, but seems sensible) */
2634 	    cover_area_1(side, unit, x0, y0, nx, ny);
2635 	}
2636     }
2637 }
2638 
2639 /* Set this flag to redo coverage without doing all the side effects
2640    that come with see_cell. */
2641 
2642 static int suppress_see_cell;
2643 
2644 /* Set this flag to initialize views without waking any units.  This
2645    is necessary when restoring a game, since we construct the view
2646    using this code, but don't want to modify the units' plans from
2647    what they were when the game was saved. */
2648 
2649 int suppress_see_wakeup;
2650 
2651 static void
cover_area_1(Side * side,Unit * unit,int x0,int y0,int nx,int ny)2652 cover_area_1(Side *side, Unit *unit, int x0, int y0, int nx, int ny)
2653 {
2654     int u = unit->type, range0, nrange, range, x, y, x1, y1, x2, y2;
2655     int y1c, y2c, cov, los, r;
2656     int xmin, ymin, xmax, ymax, oldcov, newcov, anychanges;
2657 
2658     if (side->coverage == NULL)
2659       return;
2660     range0 = nrange = u_vision_range(u);
2661     /* Adjust for the effects of nighttime on vision range. */
2662     if (in_area(x0, y0)) {
2663 	if (night_at(x0, y0)) {
2664 	    range0 =
2665 	      (range0 * ut_vision_night_effect(u, terrain_at(x0, y0))) / 100;
2666 	}
2667     } else {
2668 	range0 = 0;
2669     }
2670     if (in_area(nx, ny)) {
2671 	if (night_at(nx, ny)) {
2672 	    nrange =
2673 	      (nrange * ut_vision_night_effect(u, terrain_at(nx, ny))) / 100;
2674 	}
2675     } else {
2676 	nrange = 0;
2677     }
2678     range = max(range0, nrange);
2679     allocate_area_scratch(1);
2680     anychanges = FALSE;
2681     /* First, set the union of the from and to areas to the existing
2682        coverage. */
2683     /* These may be outside the area - necessary since units may be able
2684        to see farther in x than the height of the area. */
2685     /* Compute the maximum bounds that may be affected. */
2686     if (y0 >= 0) {
2687 	if (ny >= 0) {
2688 	    ymin = min(y0, ny);
2689 	    ymax = max(y0, ny);
2690 	} else {
2691 	    ymin = ymax = y0;
2692 	}
2693     } else if (ny >= 0) {
2694 	ymin = ymax = ny;
2695     }
2696     if (x0 >= 0) {
2697 	if (nx >= 0) {
2698 	    xmin = min(x0, nx);
2699 	    xmax = max(x0, nx);
2700 	} else {
2701 	    xmin = xmax = x0;
2702 	}
2703     } else if (nx >= 0) {
2704 	xmin = xmax = nx;
2705     }
2706     if (any_los) {
2707 	/* Need extra scratch layers, will be used for visible
2708            elevation cache. */
2709 	allocate_area_scratch(3);
2710     }
2711     los = FALSE;
2712     /* (should also adjust for effect of clouds here) */
2713     if (!u_can_see_behind(u)) {
2714 	los = TRUE;
2715 	/* Compute the minimum elevation for visibility at each cell. */
2716 	if (in_area(x0, y0)) {
2717 	    tmpx0 = x0;  tmpy0 = y0;
2718 	    tmpz0 = checked_elev_at(x0, y0)
2719 		+ unit_alt(unit)
2720 		+ ut_eye_height(u, terrain_at(x0, y0));
2721 	    apply_to_area(x0, y0, range0, init_visible_elevation);
2722 	    /* Leave own and adj cells alone, they will always be visible. */
2723 	    for (r = 2; r <= range0; ++r) {
2724 		apply_to_ring(x0, y0, r, r, calc_visible_elevation);
2725 	    }
2726 	    /* We now have a layer indicating how high things must be
2727                to be visible. */
2728 	}
2729 	if (in_area(nx, ny)) {
2730 	    tmpnx = nx;  tmpny = ny;
2731 	    tmpnz = checked_elev_at(nx, ny)
2732 		+ unit_alt(unit)
2733 		+ ut_eye_height(u, terrain_at(nx, ny));
2734 	    apply_to_area(nx, ny, nrange, init_visible_elevation_2);
2735 	    /* Leave own and adj cells alone, they will always be visible. */
2736 	    for (r = 2; r <= nrange; ++r) {
2737 		apply_to_ring(nx, ny, r, r, calc_visible_elevation_2);
2738 	    }
2739 	    /* We now have another layer, indicating how high things must be
2740                to be visible from the new location. */
2741 	}
2742     }
2743     /* Copy the current coverage into the tmp layer. */
2744     y1 = y1c = ymin - range;
2745     y2 = y2c = ymax + range;
2746     /* Clip the iteration bounds. */
2747     if (y1c < 0)
2748       y1c = 0;
2749     if (y2c > area.height - 1)
2750       y2c = area.height - 1;
2751     for (y = y1c; y <= y2c; ++y) {
2752 	x1 = xmin - range;
2753 	x2 = xmax + range;
2754 	for (x = x1; x <= x2; ++x) {
2755 	    if (in_area(x, y)) {
2756 		set_tmp1_at(x, y, cover(side, x, y));
2757 	    }
2758 	}
2759     }
2760     /* Decrement coverage around the old location. */
2761     if (in_area(x0, y0)) {
2762 	y1 = y1c = y0 - range0;
2763 	y2 = y2c = y0 + range0;
2764 	/* Clip the iteration bounds. */
2765 	if (y1c < 0)
2766 	  y1c = 0;
2767 	if (y2c > area.height - 1)
2768 	  y2c = area.height - 1;
2769 	for (y = y1c; y <= y2c; ++y) {
2770 	    x1 = x0 - (y < y0 ? (y - y1) : range0);
2771 	    x2 = x0 + (y > y0 ? (y2 - y) : range0);
2772 	    for (x = x1; x <= x2; ++x) {
2773 		if (in_area(x, y)) {
2774 		    if (!los
2775 			|| ((tmp2_at(x, y) + tmpz0)
2776 			    <= (checked_elev_at(x, y)
2777 				+ t_thickness(terrain_at(x, y))))) {
2778 			cov = tmp1_at(x, y) - 1;
2779 			/* Should never go negative, detect if so. */
2780 			if (cov < 0) {
2781 			    Dprintf("Negative coverage for %s at %d,%d\n",
2782 				    side_desig(side), wrapx(x), y);
2783 			}
2784 			set_tmp1_at(x, y, cov);
2785 		    }
2786 		    if (los && (alt_cover(side, x, y) == (tmp2_at(x, y) + tmpz0)))
2787 		      /* this unit set the min, should recalc alt
2788                          coverage now */;
2789 		}
2790 	    }
2791 	}
2792     }
2793     /* Increment coverage around the new location. */
2794     if (in_area(nx, ny)) {
2795 	y1 = y1c = ny - nrange;
2796 	y2 = y2c = ny + nrange;
2797 	/* Clip the iteration bounds. */
2798 	if (y1c < 0)
2799 	  y1c = 0;
2800 	if (y2c > area.height - 1)
2801 	  y2c = area.height - 1;
2802 	for (y = y1c; y <= y2c; ++y) {
2803 	    x1 = nx - (y < ny ? (y - y1) : nrange);
2804 	    x2 = nx + (y > ny ? (y2 - y) : nrange);
2805 	    for (x = x1; x <= x2; ++x) {
2806 		if (in_area(x, y)) {
2807 		    if (!los
2808 			|| ((tmp3_at(x, y) + tmpnz)
2809 			    <= (checked_elev_at(x, y)
2810 				+ t_thickness(terrain_at(x, y))))) {
2811 			cov = tmp1_at(x, y) + 1;
2812 			set_tmp1_at(x, y, cov);
2813 		    }
2814 		    if (los)
2815 		      set_alt_cover(side, x, y,
2816 				    min(alt_cover(side, x, y),
2817 					(tmp3_at(x, y) + tmpnz)));
2818 		}
2819 	    }
2820 	}
2821     }
2822     /* Now update the actual coverage.  Do this over an area that includes
2823        both the decrement and increment changes. */
2824     y1 = y1c = ymin - range;
2825     y2 = y2c = ymax + range;
2826     /* Clip the iteration bounds. */
2827     if (y1c < 0)
2828       y1c = 0;
2829     if (y2c > area.height - 1)
2830       y2c = area.height - 1;
2831     for (y = y1c; y <= y2c; ++y) {
2832 	x1 = xmin - range;
2833 	x2 = xmax + range;
2834 	for (x = x1; x <= x2; ++x) {
2835 	    if (in_area(x, y)) {
2836 		oldcov = cover(side, x, y);
2837 		newcov = tmp1_at(x, y);
2838 		if (newcov != oldcov) {
2839 		    set_cover(side, x, y, newcov);
2840 		    /* Skip over unit view updating if we're just repairing
2841 		       the coverage layer. */
2842 		    if (suppress_see_cell)
2843 		      continue;
2844 		    if (newcov > oldcov
2845 			&& see_cell(side, x, y)
2846 			&& !suppress_see_wakeup) {
2847 				react_to_seen_unit(side, unit, x, y);
2848 		    }
2849 		    if ((newcov > 0 && oldcov == 0)
2850 			|| (newcov == 0 && oldcov > 0)
2851 			|| (DebugG && newcov != oldcov)) {
2852 				update_cell_display(side, x, y, UPDATE_COVER);
2853 		    }
2854 		    anychanges = TRUE;
2855 		}
2856 	    }
2857 	}
2858     }
2859     /* If we're seeing new things, make sure they're on the display. */
2860     if (anychanges) {
2861 	flush_display_buffers(side);
2862 	/* Also flush the unit view list. */
2863 	flush_stale_views();
2864     }
2865 }
2866 
2867 /* Use this to clear out garbled view coverage.  Note however that this
2868    may not touch any unit views, otherwise players could collect info
2869    about hard-to-see units by refreshing/recomputing over and over. */
2870 
2871 void
reset_coverage(void)2872 reset_coverage(void)
2873 {
2874     Side *side;
2875 
2876     if (g_see_all())
2877       return;
2878     suppress_see_cell = TRUE;
2879     for_all_sides(side)
2880       calc_coverage(side);
2881     suppress_see_cell = FALSE;
2882 }
2883 
2884 /* Same as above but does not suppress see-cell. Needs to be called on
2885 sunrise etc. when unit views should be updated. */
2886 
2887 void
really_reset_coverage(void)2888 really_reset_coverage(void)
2889 {
2890     Side *side;
2891 
2892     if (g_see_all())
2893       return;
2894     for_all_sides(side)
2895       calc_coverage(side);
2896 }
2897 
2898 /* Calculate/recalculate the view coverage layers of a side. */
2899 
2900 /* Note: this code is very inefficient in that each unit view is added
2901 and then removed about 50 times. Should fix this. */
2902 
2903 void
calc_coverage(Side * side)2904 calc_coverage(Side *side)
2905 {
2906     int x, y, pop, visible[MAXSIDES + 1];
2907     Unit *unit;
2908     Side *side2;
2909 
2910     if (side->coverage == NULL)
2911       return;
2912     /* Should figure out why this does not work. */
2913     if (0/*side->see_all*/) {
2914     	for_all_cells(x, y) {
2915     		set_cover(side, x, y, 1);
2916     	}
2917     	return;
2918     }
2919     Dprintf("Calculating all view coverage for %s\n", side_desig(side));
2920     /* Either init all cells to 0, or use populations to decide. */
2921     if (people_sides_defined()) {
2922 	/* First figure out which sides' people will tell us stuff and
2923 	   cache it, so as to speed up the init. */
2924 	for_all_sides(side2) {
2925 	    visible[side2->id] = FALSE;
2926 	    if (trusted_side(side2, side) || side2->controlled_by == side)
2927 	      visible[side2->id] = TRUE;
2928 	}
2929 	for_all_cells(x, y) {
2930 	    pop = people_side_at(x, y);
2931 	    set_cover(side, x, y, ((pop != NOBODY && visible[pop]) ? 1 : 0));
2932 	}
2933     } else {
2934 	for_all_cells(x, y) {
2935 	    set_cover(side, x, y, 0);
2936 	}
2937     }
2938     /* Add coverage by, and of, the units already in place. */
2939     for_all_units(unit) {
2940 	if (in_play(unit)) {
2941 	    x = unit->x;  y = unit->y;
2942 	    if (trusted_side(unit->side, side)
2943 	    	|| side->see_all) {
2944 		/* Units that trust us tell us stuff. */
2945 		cover_area(side, unit, unit->transport, -1, -1, x, y);
2946 	    } else if (u_see_always(unit->type)
2947 		       && terrain_view(side, x, y) != UNSEEN) {
2948 		/* Always-seen units effectively monitor their current
2949 		   location for us, even if they don't like us. */
2950 		add_cover(side, x, y, 1);
2951 	    }
2952 	}
2953     }
2954 }
2955 
2956 /* Look for and clear out any bogus view data. */
2957 
2958 void
reset_all_views(void)2959 reset_all_views(void)
2960 {
2961     Side *side;
2962 
2963     for_all_sides(side) {
2964 	if (!side->see_all) {
2965 	    reset_view(side);
2966 	}
2967     }
2968 }
2969 
2970 void
reset_view(Side * side)2971 reset_view(Side *side)
2972 {
2973     int x, y, domore;
2974     UnitView *uview;
2975 
2976     for_all_cells(x, y) {
2977 	/* Remove any leftover images of our own units. */
2978 	if (cover(side, x, y) < 1) {
2979 	    domore = TRUE;
2980 	    while (domore) {
2981 		domore = FALSE;
2982 		for_all_view_stack_with_occs(side, x, y, uview) {
2983 		    if (side->id == uview->siden) {
2984 			remove_unit_view(side, uview);
2985 			domore = TRUE;
2986 			break;
2987 		    }
2988 		}
2989 	    }
2990 	}
2991     }
2992 }
2993 
2994 void
react_to_seen_unit(Side * side,Unit * unit,int x,int y)2995 react_to_seen_unit(Side *side, Unit *unit, int x, int y)
2996 {
2997     int eu;
2998     Unit *eunit;
2999     UnitView *uview;
3000     Side *es;
3001 
3002     /* (The g_see_all() branch appears to be unused, because
3003 	'calc_coverage' is only called when g_see_all() is not true.) */
3004     if (g_see_all() /* see real unit */) {
3005     	/* (should look at all of stack if can be mixed) */
3006 	if ((eunit = unit_at(x, y)) != NULL) {
3007 	    if (unit->plan && !allied_side(eunit->side, side)) {
3008 		/* should do a more general alarm */
3009 		selectively_wake_unit(unit->side, unit, TRUE, FALSE);
3010 	    }
3011 	}
3012     } else if (side->coverage != NULL) {
3013 	uview = unit_view_at(side, x, y);
3014     	if (uview != NULL) {
3015     	    eu = uview->type;
3016     	    es = side_n(uview->siden);
3017     	    /* react only to certain utypes? */
3018 	    if (unit->plan && !allied_side(es, side)) {
3019 		/* should do a more general alarm */
3020 		selectively_wake_unit(unit->side, unit, TRUE, FALSE);
3021 	    }
3022     	}
3023     } else {
3024     	/* ??? */
3025     }
3026 }
3027 
3028 /* Decide whether any side acquires tracking on a unit. */
3029 
3030 int any_tracking = -1;
3031 
3032 void
maybe_track(Unit * unit)3033 maybe_track(Unit *unit)
3034 {
3035     int x0, y0, dir, x1, y1, chance;
3036     Unit *unit2;
3037 
3038     if (any_tracking < 0) {
3039 	int u1, u2;
3040 
3041 	any_tracking = FALSE;
3042 	for_all_unit_types(u1) {
3043 	    for_all_unit_types(u2) {
3044 		if (uu_track(u1, u2) > 0) {
3045 		    any_tracking = TRUE;
3046 		    break;
3047 		}
3048 	    }
3049 	    if (any_tracking)
3050 	      break;
3051 	}
3052     }
3053     if (!any_tracking)
3054       return;
3055     x0 = unit->x;  y0 = unit->y;
3056     for_all_stack(x0, y0, unit2) {
3057 	if (in_play(unit2)
3058 	    && unit2 != unit
3059 	    && unit2->side != unit->side
3060 	    && unit2->side != NULL) {
3061 	    chance = uu_track(unit2->type, unit->type);
3062 	    if (xrandom(10000) < chance) {
3063 		add_side_to_set(unit2->side, unit->tracking);
3064 	    }
3065 	}
3066     }
3067     for_all_directions(dir) {
3068 	if (interior_point_in_dir(x0, y0, dir, &x1, &y1)) {
3069 	    for_all_stack(x1, y1, unit2) {
3070 		if (in_play(unit2)
3071 		    && unit2 != unit
3072 		    && unit2->side != unit->side
3073 		    && unit2->side != NULL) {
3074 		    chance = uu_track(unit2->type, unit->type);
3075 		    if (xrandom(10000) < chance) {
3076 			add_side_to_set(unit2->side, unit->tracking);
3077 		    }
3078 		}
3079 	    }
3080 	}
3081     }
3082 }
3083 
3084 /* Decide whether any side tracking a unit lost it. */
3085 
3086 void
maybe_lose_track(Unit * unit,int nx,int ny)3087 maybe_lose_track(Unit *unit, int nx, int ny)
3088 {
3089     int t = terrain_at(nx, ny), chance;
3090     Side *side;
3091 
3092     chance = ut_lose_track(unit->type, t);
3093     if (chance > 0) {
3094 	for_all_sides(side) {
3095 	    if (side_tracking_unit(side, unit)
3096 		&& xrandom(10000) < chance) {
3097 		remove_side_from_set(side, unit->tracking);
3098 		/* (should notify?) */
3099 	    }
3100 	}
3101     }
3102 }
3103 
3104 extern void compute_see_chances(void);
3105 
3106 /* Determine whether there is any possibility of an uncertain sighting,
3107    and cache the conclusion. */
3108 /*! \note 'any_see_chances' will be only be set if a see chance is not 100%.
3109 	  Thus, if all the see chances are 0, it will be set. The variable
3110 	  name is somewhat misleading. */
3111 
3112 void
compute_see_chances(void)3113 compute_see_chances(void)
3114 {
3115     using namespace Xconq;
3116     int u1, u2, u3, m1;
3117 
3118     any_see_chances = FALSE;
3119     any_people_see_chances = FALSE;
3120     people_always_see = TRUE;
3121     max_see_chance_range = -1;
3122     any_see_mistake_chances = FALSE;
3123     max_see_mistake_range = -1;
3124     for_all_unit_types(u2) {
3125 	for_all_unit_types(u1) {
3126 	    if (uu_see_at(u1, u2) != 100) {
3127 		any_see_chances = TRUE;
3128 		max_see_chance_range = max(max_see_chance_range, 0);
3129 	    }
3130 	    if (uu_see_adj(u1, u2) != 100) {
3131 		any_see_chances = TRUE;
3132 		max_see_chance_range = max(max_see_chance_range, 1);
3133 	    }
3134 	    if (uu_see(u1, u2) != 100) {
3135 		any_see_chances = TRUE;
3136 	    }
3137 	    max_see_chance_range = max(max_see_chance_range,
3138 				       u_vision_range(u1));
3139 	    if (uu_see_mistake(u1, u2) > 0) {
3140 		for_all_unit_types(u3) {
3141 		    if (uu_looks_like(u2, u3) > 0) {
3142 			any_see_mistake_chances = TRUE;
3143 			break;
3144 		    }
3145 		}
3146 		max_see_mistake_range = max(max_see_mistake_range,
3147 					    u_vision_range(u1));
3148 	    }
3149 	}
3150 	for_all_material_types(m1) {
3151 	    if (m_people(m1) > 0 && um_people_see(u2, m1) > 0) {
3152 		any_people_see_chances = TRUE;
3153 		if (um_people_see(u2, m1) < 100)
3154 		  people_always_see = FALSE;
3155 	    }
3156 	}
3157 	if (people_sides_defined())
3158 	  any_people_see_chances = TRUE;
3159     }
3160 }
3161 
3162 /* Compute the overwatch cache. Useful for optimizing searches for
3163    overwatchers. */
3164 
3165 void
compute_overwatch_cache(void)3166 compute_overwatch_cache(void)
3167 {
3168     using namespace Xconq;
3169     int u1 = NONUTYPE, u2 = NONUTYPE;
3170     int range = -1;
3171 
3172     /* Allocate the overwatch-against range arrays. */
3173     any_overwatch_chances = create_packed_bool_table(1, numutypes);
3174     overwatch_against_range_max = (int *)xmalloc(numutypes * sizeof(int));
3175     overwatch_against_range_min = (int *)xmalloc(numutypes * sizeof(int));
3176     init_packed_bool_table(any_overwatch_chances);
3177     memset(overwatch_against_range_max, -1, numutypes * sizeof(int));
3178     memset(overwatch_against_range_min, INT_MAX, numutypes * sizeof(int));
3179     /* Find out if any overwatch is being done. */
3180     any_overwatch_cache = FALSE;
3181     for_all_unit_types(u1) {
3182 	/* If an unit cannot fire, then it cannot overwatch by definition. */
3183 	if (0 >= u_range(u1))
3184 	  continue;
3185 	/* Check if the firing unit can engage in any overwatch. */
3186 	for_all_unit_types(u2) {
3187 	    if ((-1 < uu_zoo_range(u1, u2)) && (0 < fire_hit_chance(u1, u2))) {
3188 		/*! \todo Also consider an actual probability. */
3189 		any_overwatch_cache = TRUE;
3190 		set_packed_bool(any_overwatch_chances, 0, u2, TRUE);
3191 		range = min(uu_zoo_range(u1, u2), u_range(u1));
3192 		overwatch_against_range_max[u2] =
3193 		    max(overwatch_against_range_max[u2], range);
3194 		range = max(uu_zoo_range_min(u1, u2), u_range_min(u1));
3195 		overwatch_against_range_min[u2] =
3196 		    min(overwatch_against_range_min[u2], range);
3197 	    }
3198 	}
3199     }
3200 }
3201 
3202 /* Update the view of this cell for everybody's benefit.  May have to write
3203    to many displays. */
3204 
3205 void
all_see_cell(int x,int y)3206 all_see_cell(int x, int y)
3207 {
3208     Side *side;
3209 
3210     for_all_sides(side) {
3211 	see_cell(side, x, y);
3212     }
3213 }
3214 
3215 static void mistake_view(Side *side, Unit *seer, UnitView *uview);
3216 
3217 /* Check if one unit sees another, and flag whether that vision is clear
3218    or not. */
3219 /* {Arbiter Function} */
3220 
3221 int
see_unit(Unit * seer,Unit * tosee,SeerNode * seers,int * numseers)3222 see_unit(Unit *seer, Unit *tosee, SeerNode *seers, int *numseers)
3223 {
3224     int dist = -1;
3225     int u = NONUTYPE, us = NONUTYPE;
3226 
3227     assert_error(seers, "Attempted to access a NULL array in seeing code");
3228     assert_error(numseers && (*numseers >= 0),
3229 		 "Attempted to access a bad counter in seeing code");
3230     assert_warning_return(in_play(seer),
3231 			  "Attempted to access an out-of-play unit", FALSE);
3232     assert_warning_return(in_play(tosee),
3233 			  "Attempted to access an out-of-play unit", FALSE);
3234     if (seer == tosee)
3235       return FALSE;
3236     if (seer->side == tosee->side)
3237       return FALSE;
3238     u = tosee->type;
3239     us = seer->type;
3240     dist = distance(tosee->x, tosee->y, seer->x, seer->y);
3241     if (probability(see_chance(seer, tosee))) {
3242 	seers[*numseers].seer = seer;
3243 	if ((uu_see_mistake_range_min(us, u) <= dist)
3244 	    && uu_see_mistake(us, u)) {
3245 	    if (xrandom(10000) < uu_see_mistake(us, u))
3246 	      seers[*numseers].mistakes = TRUE;
3247 	}
3248 	++(*numseers);
3249 	return TRUE;
3250     }
3251     return FALSE;
3252 }
3253 
3254 /* Iterate 'see_unit' over all the occs of a transport. */
3255 /* (Can be used as a search predicate.) */
3256 /* {Arbiter Function} */
3257 
3258 int
side_occs_see_unit(int x,int y,int * numseers,ParamBox * parambox)3259 side_occs_see_unit(int x, int y, int *numseers, ParamBox *parambox)
3260 {
3261     ParamBoxUnitUnitSeers *paramboxuu = NULL;
3262     ParamBoxUnitUnitSeers *paramboxuu2 = NULL;
3263     int foundseer = FALSE;
3264     Unit *seer = NULL;
3265 
3266     assert_warning_return(in_area(x, y), "Attempted to use illegal coordinates",
3267 			  FALSE);
3268     assert_warning_return(parambox, "Attempted to access a NULL parambox",
3269 			  FALSE);
3270 #if (0)
3271     assert_warning_return(PBOX_TYPE_UNIT_UNIT_SEERS == parambox->get_type(),
3272 			  "Attempted to use wrong type of parambox",
3273 			  FALSE);
3274 #endif
3275     paramboxuu = (ParamBoxUnitUnitSeers *)parambox;
3276     assert_warning_return(paramboxuu->unit1,
3277 			  "Could not check visibility of an unit", FALSE);
3278     assert_warning_return(paramboxuu->unit2,
3279 			  "Attempted to access a NULL unit", FALSE);
3280     assert_warning_return(numseers && (*numseers >= 0),
3281 			  "Invalid parambox data encountered", FALSE);
3282     assert_warning_return(paramboxuu->seers,
3283 			  "Attempted to access a NULL array", FALSE);
3284     /* If no possible seers, then return now. */
3285     if (!paramboxuu->unit2->occupant)
3286       return FALSE;
3287     /* Iterate over all occupants. */
3288     for_all_occupants(paramboxuu->unit2, seer) {
3289 	/* Paranoia. Skip any out-of-play unit. */
3290 	if (!in_play(seer))
3291 	  continue;
3292 	/* HACK: We need to pass more information into the recursive routine.
3293 	   The seer may not be of the same side as the side that is supposed
3294 	   to be seeing. For now we must assume that an occ of the correct
3295 	   side is not lurking in an unit of the wrong side. */
3296 	if (seer->side != paramboxuu->unit2->side) {
3297 	    continue;
3298 	}
3299 	/* Descend depth-first before checking anything else. A seer of the
3300 	   correct side may be lurking in a transport of an incorrect side. */
3301 	if (seer->occupant) {
3302 	    paramboxuu2 =
3303 		(ParamBoxUnitUnitSeers *)xmalloc(sizeof(ParamBoxUnitUnitSeers));
3304 	    paramboxuu2->unit1 = paramboxuu->unit1;
3305 	    paramboxuu2->unit2 = seer;
3306 	    paramboxuu2->seers = paramboxuu->seers;
3307 	    if (side_occs_see_unit(x, y, numseers, (ParamBox *)paramboxuu2))
3308 	      foundseer = TRUE;
3309 	    if (paramboxuu2)
3310 	      free(paramboxuu2);
3311 	}
3312 	/*! \todo Put the side filter back in the correct order once the
3313 		  proper side info is being passed to 'side_occs_see_unit'. */
3314 #if (0)
3315 	/* Skip any units not on given side. */
3316 	/* (TODO: Also account for trusted sides.) */
3317 	if (seer->side != paramboxuu->unit2->side) {
3318 	    continue;
3319 	}
3320 #endif
3321 	/* Try seeing with the current seer. */
3322 	if (see_unit(seer, paramboxuu->unit1, paramboxuu->seers, numseers))
3323 	  foundseer = TRUE;
3324 	/* Check if we should conitnue evaluating. */
3325 	if (*numseers >= cover(paramboxuu->unit2->side, x, y))
3326 	  break;
3327     }
3328     /* return foundseer; */
3329     return FALSE;
3330 }
3331 
3332 /* Iterate 'see_unit' over all the units of a stack. */
3333 /* (Can be used as a search predicate.) */
3334 /* {Arbiter Function} */
3335 
3336 int
side_ustack_see_unit(int x,int y,int * numseers,ParamBox * parambox)3337 side_ustack_see_unit(int x, int y, int *numseers, ParamBox *parambox)
3338 {
3339     ParamBoxUnitSideSeers *paramboxus = NULL;
3340     ParamBoxUnitUnitSeers *paramboxuu = NULL;
3341     int foundseer = FALSE;
3342     Unit *seer = NULL;
3343 
3344     assert_warning_return(in_area(x, y), "Attempted to use illegal coordinates",
3345 			  FALSE);
3346     assert_warning_return(parambox, "Attempted to access a NULL parambox",
3347 			  FALSE);
3348     assert_warning_return(PBOX_TYPE_UNIT_SIDE_SEERS == parambox->get_type(),
3349 			  "Attempted to use wrong type of parambox",
3350 			  FALSE);
3351     paramboxus = (ParamBoxUnitSideSeers *)parambox;
3352     assert_warning_return(paramboxus->unit,
3353 			  "Could not check visibility of an unit", FALSE);
3354     assert_warning_return(paramboxus->side,
3355 			  "Attempted to access a NULL side", FALSE);
3356     assert_warning_return(numseers && (*numseers >= 0),
3357 			  "Invalid parambox data encountered", FALSE);
3358     assert_warning_return(paramboxus->seers,
3359 			  "Attempted to access a NULL array", FALSE);
3360     /* If no possible seers, then return now. */
3361     if (!unit_at(x, y))
3362       return FALSE;
3363     /* Iterate over all stack members. */
3364     for_all_stack(x, y, seer) {
3365 	/* Paranoia. Skip any out-of-play units in stack. */
3366 	if (!in_play(seer))
3367 	  continue;
3368 	/* HACK: We need to pass more information into the recursive routine.
3369 	   The seer may not be of the same side as the side that is supposed
3370 	   to be seeing. For now we must assume that an occ of the correct
3371 	   side is not lurking in an unit of the wrong side. */
3372 	if (seer->side != paramboxus->side) {
3373 	    continue;
3374 	}
3375 	/* Descend depth-first before checking anything else. A seer of the
3376 	   correct side may be lurking in a transport of an incorrect side. */
3377 	if (seer->occupant) {
3378 	    paramboxuu =
3379 		(ParamBoxUnitUnitSeers *)xmalloc(sizeof(ParamBoxUnitUnitSeers));
3380 	    paramboxuu->unit1 = paramboxus->unit;
3381 	    paramboxuu->unit2 = seer;
3382 	    paramboxuu->seers = paramboxus->seers;
3383 	    if (side_occs_see_unit(x, y, numseers, (ParamBox *)paramboxuu))
3384 	      foundseer = TRUE;
3385 	    if (paramboxuu)
3386 	      free(paramboxuu);
3387 	}
3388 	/*! \todo Put the side filter back in the correct order once the
3389 		  proper side info is being passed to 'side_occs_see_unit'. */
3390 #if (0)
3391 	/* Skip any units not on given side. */
3392 	/* (TODO: Also account for trusted sides.) */
3393 	if (seer->side != paramboxus->side) {
3394 	    continue;
3395 	}
3396 #endif
3397 	/* Try seeing with the current seer. */
3398 	if (see_unit(seer, paramboxus->unit, paramboxus->seers, numseers))
3399 	  foundseer = TRUE;
3400 	/* Check if we should conitnue evaluating. */
3401 	if (*numseers >= cover(paramboxus->side, x, y))
3402 	  break;
3403     }
3404     /* return foundseer; */
3405     return FALSE;
3406 }
3407 
3408 /* Look at the given position, possibly not seeing anything.  Return
3409    true if a unit was spotted. */
3410 
3411 int
see_cell(Side * side,int x,int y)3412 see_cell(Side *side, int x, int y)
3413 {
3414     int update, updatet, chance, curview;
3415     int m, mupdate, wupdate, flags, domore, rslt, sawthis;
3416     Unit *unit;
3417     UnitView *uview, *newuview;
3418     SeerNode seers [BUFSIZE];
3419     int numseers = 0, i = 0, seenclearly = FALSE, cellcover = 0;
3420     ParamBoxUnitSideSeers paramboxus;
3421 
3422     if (!in_area(x, y))
3423       return FALSE;
3424     update = updatet = rslt = FALSE;
3425     if (cover(side, x, y) > 0) {
3426     	/* Always update our knowledge of the terrain. */
3427     	curview = terrain_view(side, x, y);
3428  	if (curview == UNSEEN || !g_see_terrain_always()) {
3429 	    set_terrain_view(side, x, y, buildtview(terrain_at(x, y)));
3430 	    if (!g_see_terrain_always()) {
3431 		set_terrain_view_date(side, x, y, g_turn());
3432 	    }
3433 	    update = updatet = TRUE;
3434 	    if (side->see_all) {
3435 		add_cover(side, x, y, 1);
3436 	    } else {
3437 		for_all_stack(x, y, unit) {
3438 		    if (u_see_always(unit->type)) {
3439 			add_cover(side, x, y, 1);
3440 			break;
3441 		    }
3442 		}
3443 	    }
3444 	}
3445 	if (any_material_views) {
3446 	    mupdate = see_materials(side, x, y);
3447 	    if (mupdate)
3448 	      update = TRUE;
3449 	}
3450 	if (temperatures_defined() || clouds_defined() || winds_defined()) {
3451 	    wupdate = see_weather(side, x, y);
3452 	    if (wupdate)
3453 	      update = TRUE;
3454 	}
3455 	if (Xconq::any_see_chances < 0)
3456 	  compute_see_chances();
3457 	/* Get rid of any unit views that are no longer valid here. */
3458 	domore = TRUE;
3459 	while (domore) {
3460 	    domore = FALSE;
3461 	    for_all_view_stack(side, x, y, uview) {
3462 		/* Conditionally flush unit views. */
3463 		/*! \note Improve this code to consider view flushing
3464 			  granularity. */
3465 		unit = view_unit(uview);
3466 		if (!unit || (uview->x != unit->x) || (uview->y != unit->y)
3467 		    || (uview->transport
3468 			&& (view_unit(uview->transport) != unit->transport))
3469 		    || (!u_see_always(uview->type)
3470 			&& (uview->date < g_turn()))) {
3471 		    if (remove_unit_view(side, uview)) {
3472 			update = TRUE;
3473 		    }
3474 		    domore = TRUE;
3475 		    break;
3476 		}
3477 	    }
3478 	}
3479 	/* Iterate over all units-to-see in a given location. */
3480 	for_all_stack(x, y, unit) {
3481 	    /* Reset the flag that says whether we've spotted this
3482 	       particular unit in the stack. */
3483 	    sawthis = FALSE;
3484 	    /* If any definite sightings. */
3485 	    if (side_sees_unit(side, unit)) {
3486 		newuview = add_unit_view(side, unit);
3487 		if (newuview)
3488 		  update = TRUE;
3489 		rslt = sawthis = TRUE;
3490 	    /* If any possible sightings. */
3491 	    /* All see chances may be perfect by default ('any_see_chances'
3492 	       will be FALSE), but terrain, night, etc... modifications still
3493 	       take place, and mistaken viewings can still occur. */
3494 	    }
3495 	    else {
3496 		numseers = 0;
3497 		cellcover = cover(side, x, y);
3498 #if (0)
3499 		/* Allocate array of max possible seers. */
3500 		if (cellcover > 0)
3501 		  seers = (SeerNode *)xmalloc(cellcover * sizeof(SeerNode));
3502 #endif
3503 		/* Reset the seers array. */
3504 		memset(seers, 0, BUFSIZE*sizeof(SeerNode));
3505 		/* Setup parambox to iterate through ustacks. */
3506 		paramboxus.unit = unit;
3507 		paramboxus.side = side;
3508 		paramboxus.seers = seers;
3509 		/* Look in the same cell. */
3510 		if (cellcover)
3511 		  side_ustack_see_unit(x, y, &numseers,
3512 				       (ParamBox *)(&paramboxus));
3513 		/* Look in other cells out to the maximum vision range. */
3514 		/* (NOTE: There should probably be a performance choice
3515 		    here. If the max vision range is sufficiently large, then
3516 		    it may be cheaper to iterate through the side units
3517 		    instead of searching the area.) */
3518 		if ((numseers < cellcover)
3519 		    && (0 < Xconq::max_see_chance_range)) {
3520 		    limited_search_around(x, y, Xconq::max_see_chance_range,
3521 					  side_ustack_see_unit, 1, &numseers,
3522 					  cellcover, (ParamBox *)&paramboxus);
3523 		}
3524 		/* Let the caller know that something is seen. */
3525 		if (numseers)
3526 		  rslt = TRUE;
3527 		seenclearly = FALSE;
3528 		/* Now that we have gathered up all the seers, start
3529 		   building unmistaken unit views. */
3530 		for (i = 0; i < numseers; ++i) {
3531 		    /* Skip over mistaken views. */
3532 		    if (seers[i].mistakes)
3533 		      continue;
3534 		    /* Construct an unit view. */
3535 		    /* If coordinated vision, then we build the new uview
3536 		       without hesitation. */
3537 		    /* (NOTE: Currently, uncoordinated vision is not supported
3538 			by the Xconq uview code.) */
3539 		    if (1 /* (TODO: Replace with appropriate flag.) */) {
3540 			newuview = add_unit_view(side, unit);
3541 			seenclearly = TRUE;
3542 		    }
3543 		    /* If this is a new unit view, then a display update is
3544 		       needed. */
3545 		    /* (NOTE: This machinery will probably need to be
3546 			changed if uncoordinated vision or advanced fog-of-war
3547 			make it into Xconq.) */
3548 		    if (newuview)
3549 		      update = TRUE;
3550 		    /* If coordinated vision, then any single accurate
3551 		       sighting will be sufficient, and we don't need to
3552 		       build additional unit views. */
3553 		    if (1 /* (TODO: Replace with appropriate flag.) */)
3554 		      break;
3555 		} /* for all unmistaken views */
3556 		/* If no one saw anything clearly, then investigate the
3557 		   possibility of mistaken views. */
3558 		for (i = 0; i < numseers; ++i) {
3559 		    /* If coordinated vision and something else already
3560 		       clearly seen, then what are we doing here? Get out. */
3561 		    if (1 /* (TODO: Replace with appropriate flag.) */
3562 			&& seenclearly)
3563 		      break;
3564 		    /* If coordinated vision and we are still in this loop,
3565 		       then all seers must be mistaken about what they see. */
3566 		    if (1 /* (TODO: Replace with appropriate flag.) */) {
3567 			newuview = add_unit_view(side, unit);
3568 			/* If this is a new unit view, then a display update is
3569 			   needed. */
3570 			/* (NOTE: This machinery will probably need to be
3571 			    changed if uncoordinated vision or advanced
3572 			    fog-of-war make it into Xconq.) */
3573 			if (newuview)
3574 			  update = TRUE;
3575 			/* If no advanced fog-of-war, then we pick one of the
3576 			   seers at random and agree upon its view of things,
3577 			   and don't bother with other possible views. */
3578 			if (newuview
3579 			    && 1 /* (TODO: Replace with appropriate flag.) */) {
3580 			    /* Mistake the view. */
3581 			    mistake_view(side, seers[xrandom(numseers)].seer,
3582 					 newuview);
3583 			    break;
3584 			}
3585 			/* (TODO: Handle advanced fog-of-war.) */
3586 		    } /* Coordinated vision. */
3587 		    /* Skip over unmistaken views. */
3588 		    if (!(seers[i].mistakes))
3589 		      continue;
3590 		    /* (TODO: Handle uncoordinated vision.) */
3591 		} /* for all mistaken views */
3592 #if (0)
3593 		/* Deallocate array of seers if necessary. */
3594 		if (seers) {
3595 		    free(seers);
3596 		    seers = NULL;
3597 		}
3598 #endif
3599 	    }
3600 	} /* for all stack units */
3601 	/* Check if any populations in the cell see something. */
3602 	/* 'side_sees_unit' will detect an unit if the people of a side
3603 	    always see and are present in a cell. */
3604 	if (!Xconq::people_always_see && Xconq::any_people_see_chances
3605 	    && people_sides_defined()
3606 	    && people_side_at(x, y) == side->id
3607 	    && any_cell_materials_defined()) {
3608 	    for_all_stack(x, y, unit) {
3609 		for_all_material_types(m) {
3610 		    if (cell_material_defined(m)
3611 			&& material_at(x, y, m) > 0) {
3612 			chance = um_people_see(unit->type, m);
3613 			if (probability(chance)) {
3614 			    newuview = add_unit_view(side, unit);
3615 			    if (newuview)
3616 			      update = TRUE;
3617 			    /* Proceed to consider the next unit. */
3618 			    break;
3619 			}
3620 		    }
3621 		}
3622    	    }
3623 	}
3624     }
3625     /* If there was any change in what was visible, tell the display. */
3626     if (update) {
3627 	flags = UPDATE_ALWAYS;
3628 	/* If the view of the terrain changed, adjacent cells probably
3629 	   need to be redrawn as well. */
3630 	if (updatet)
3631 	  flags |= UPDATE_ADJ;
3632 	update_cell_display(side, x, y, flags);
3633     }
3634     /* Indicate whether any units were seen at this location, even if
3635        no display updates were needed. */
3636     return rslt;
3637 }
3638 
3639 /* If the viewing unit might possibly misidentify the type of unit it
3640    saw, compute the chance and replace the view's type with one of the
3641    possible types that it could be mistaken for. */
3642 
3643 static void
mistake_view(Side * side,Unit * seer,UnitView * uview)3644 mistake_view(Side *side, Unit *seer, UnitView *uview)
3645 {
3646     assert_warning_return(seer, "Attempted to see with a NULL unit",);
3647     assert_warning_return(side, "Attempted to access a NULL side",);
3648     assert_warning_return(uview, "Attempted to see a NULL unit view",);
3649     uview->type = mistaken_type(uview->type);
3650     uview->image_name = NULL;
3651     uview->imf = NULL;
3652     set_unit_view_image(uview);
3653 }
3654 
3655 /* Given a unit type, return a similar-looking type that it might be
3656    confused with. */
3657 
3658 static int
mistaken_type(int u2)3659 mistaken_type(int u2)
3660 {
3661     int u3, totalweight, randval;
3662 
3663     totalweight = 0;
3664     for_all_unit_types(u3) {
3665 	totalweight += uu_looks_like(u2, u3);
3666     }
3667     /* If nothing that it looks like, return original type. */
3668     if (totalweight == 0)
3669       return u2;
3670     randval = xrandom(totalweight);
3671     totalweight = 0;
3672     for_all_unit_types(u3) {
3673 	totalweight += uu_looks_like(u2, u3);
3674 	if (randval < totalweight)
3675 	  return u3;
3676     }
3677     return u2;
3678 }
3679 
3680 /* "Bare-bones" viewing, for whenever you know exactly what's there.
3681    This is the lowest level of all viewing routines, and executed a lot. */
3682 
3683 void
see_exact(Side * side,int x,int y)3684 see_exact(Side *side, int x, int y)
3685 {
3686     int oldtview, newtview, update, mupdate, wupdate, domore;
3687     Unit *unit;
3688     UnitView *uview;
3689 
3690     if (!in_area(x, y))
3691       return;
3692     if (side->see_all) {
3693 	/* It may not really be necessary to do anything to the
3694 	   display, but the kernel doesn't know if the interface is
3695 	   drawing all the units that are visible, or is only drawing
3696 	   "interesting" ones, or whatever.  It would be up to the
3697 	   interface to decide that, say, its magnification power for
3698 	   a map is such that only one unit is being displayed, and
3699 	   that the update from here doesn't result in any visible
3700 	   changes to what's already been drawn on the screen. */
3701     	update = TRUE;
3702     } else {
3703 	update = FALSE;
3704     	oldtview = terrain_view(side, x, y);
3705     	newtview = buildtview(terrain_at(x, y));
3706     	set_terrain_view(side, x, y, newtview);
3707 	set_terrain_view_date(side, x, y, g_turn());
3708 	if (oldtview != newtview)
3709 	  update = TRUE;
3710 	mupdate = see_materials(side, x, y);
3711 	if (mupdate)
3712 	  update = TRUE;
3713 	wupdate = see_weather(side, x, y);
3714 	if (wupdate)
3715 	  update = TRUE;
3716 	/* Flush all unit views. */
3717 	domore = TRUE;
3718 	while (domore) {
3719 	    domore = FALSE;
3720 	    for_all_view_stack(side, x, y, uview) {
3721 		if (remove_unit_view(side, uview)) {
3722 		    update = TRUE;
3723 		}
3724 		domore = TRUE;
3725 		break;
3726 	    }
3727 	}
3728 	for_all_stack(x, y, unit) {
3729 	    uview = add_unit_view(side, unit);
3730 	    if (uview)
3731 	      update = TRUE;
3732 	}
3733     }
3734     /* If there was any change in what was visible, tell the display. */
3735     if (update) {
3736 	update_cell_display(side, x, y, UPDATE_ALWAYS | UPDATE_ADJ);
3737     }
3738 }
3739 
3740 static int
see_materials(Side * side,int x,int y)3741 see_materials(Side *side, int x, int y)
3742 {
3743     int m, curview, update;
3744 
3745     update = FALSE;
3746     if (!any_material_views)
3747       return update;
3748     for_all_material_types(m) {
3749 	if (any_material_views_by_m[m]) {
3750 	    curview = material_view(side, x, y, m);
3751 	    if (curview != material_at(x, y, m)) {
3752 		set_material_view(side, x, y, m, material_at(x, y, m));
3753 		update = TRUE;
3754 	    }
3755 	    /* Even if the data didn't change, our information is
3756 	       now up-to-date. */
3757 	    if (1)
3758 	      set_material_view_date(side, x, y, m, g_turn());
3759 	}
3760     }
3761     return update;
3762 }
3763 
3764 static int
see_weather(Side * side,int x,int y)3765 see_weather(Side *side, int x, int y)
3766 {
3767     int curview, update;
3768 
3769     update = FALSE;
3770     if (temperatures_defined()) {
3771 	curview = temperature_view(side, x, y);
3772 	if (curview != temperature_at(x, y)) {
3773 	    set_temperature_view(side, x, y, temperature_at(x, y));
3774 	    update = TRUE;
3775 	}
3776 	/* Even if the data didn't change, our information is
3777 	   now up-to-date. */
3778 	if (!g_see_weather_always())
3779 	  set_temperature_view_date(side, x, y, g_turn());
3780     }
3781     if (clouds_defined()) {
3782 	curview = cloud_view(side, x, y);
3783 	if (curview != raw_cloud_at(x, y)) {
3784 	    set_cloud_view(side, x, y, raw_cloud_at(x, y));
3785 	    update = TRUE;
3786 	}
3787 	curview = cloud_bottom_view(side, x, y);
3788 	if (cloud_bottoms_defined()
3789 	    && (curview != raw_cloud_bottom_at(x, y))) {
3790 	    set_cloud_bottom_view(side, x, y, raw_cloud_bottom_at(x, y));
3791 	    update = TRUE;
3792 	}
3793 	curview = cloud_height_view(side, x, y);
3794 	if (cloud_heights_defined()
3795 	    && (curview != raw_cloud_height_at(x, y))) {
3796 	    set_cloud_height_view(side, x, y, raw_cloud_height_at(x, y));
3797 	    update = TRUE;
3798 	}
3799 	/* Even if the data didn't change, our information is
3800 	   now up-to-date. */
3801 	if (!g_see_weather_always())
3802 	  set_cloud_view_date(side, x, y, g_turn());
3803 	/* Only need one date for the three layers of view data. */
3804     }
3805     if (winds_defined()) {
3806 	curview = wind_view(side, x, y);
3807 	if (curview != raw_wind_at(x, y)) {
3808 	    set_wind_view(side, x, y, raw_wind_at(x, y));
3809 	    update = TRUE;
3810 	}
3811 	/* Even if the data didn't change, our information is
3812 	   now up-to-date. */
3813 	if (!g_see_weather_always())
3814 	  set_wind_view_date(side, x, y, g_turn());
3815     }
3816     return update;
3817 }
3818 
3819 /* A border has been seen if the cells on both sides has been seen. */
3820 
3821 int
seen_border(Side * side,int x,int y,int dir)3822 seen_border(Side *side, int x, int y, int dir)
3823 {
3824     int x1, y1;
3825 
3826     if (side->see_all)
3827       return TRUE;
3828     if (terrain_view(side, x, y) == UNSEEN)
3829       return FALSE;
3830     if (point_in_dir(x, y, dir, &x1, &y1))
3831       if (terrain_view(side, x1, y1) == UNSEEN)
3832 	return FALSE;
3833     return TRUE;
3834 }
3835 
3836 /* Make a printable identification of the given side.  This should be
3837    used for debugging and designing, not regular play. */
3838 
3839 char *
side_desig(Side * side)3840 side_desig(Side *side)
3841 {
3842     Unit *unit;
3843 
3844     if (sidedesigbuf == NULL)
3845       sidedesigbuf = (char *)xmalloc(BUFSIZE);
3846     if (side != NULL) {
3847 	/* The side name is all capitalized in the output. Why? */
3848 	sprintf(sidedesigbuf, "s%d %s", side_number(side), side_name(side));
3849 	if (side->self_unit) {
3850 		unit = find_unit_dead_or_alive(side->self_unit->id);
3851 		if (in_play(unit)) {
3852 			if (!mobile(unit->type) || u_advanced(unit->type)) {
3853 				tprintf(sidedesigbuf, " (capital %s %s)",
3854 						(side->ingame ? "is" : "was"),
3855 						short_unit_handle(unit));
3856 			} else {
3857 				tprintf(sidedesigbuf, " (leader %s %s)",
3858 						(side->ingame ? "is" : "was"),
3859 						short_unit_handle(unit));
3860 			}
3861 		}
3862 	}
3863     } else {
3864 	sprintf(sidedesigbuf, "nullside");
3865     }
3866     return sidedesigbuf;
3867 }
3868 
3869 /* Add a player into the list of players.  All values are defaults here. */
3870 
3871 Player *
add_player(void)3872 add_player(void)
3873 {
3874     Player *player = (Player *) xmalloc(sizeof(Player));
3875 
3876     player->id = nextplayerid++;
3877     /* Note that all names and suchlike slots are NULL. */
3878     ++numplayers;
3879     /* Add this one to the end of the player list. */
3880     if (last_player == NULL) {
3881 	playerlist = last_player = player;
3882     } else {
3883 	last_player->next = player;
3884 	last_player = player;
3885     }
3886     Dprintf("Added player #%d\n", player->id);
3887     return player;
3888 }
3889 
3890 Player *
find_player(int n)3891 find_player(int n)
3892 {
3893     Player *player;
3894 
3895     for_all_players(player) {
3896        if (player->id == n)
3897 	return player;
3898     }
3899     return NULL;
3900 }
3901 
3902 /* Transform a player object into a regularized form. */
3903 
3904 void
canonicalize_player(Player * player)3905 canonicalize_player(Player *player)
3906 {
3907     if (player == NULL)
3908       return;
3909     if (empty_string(player->displayname))
3910       player->displayname = NULL;
3911     if (empty_string(player->aitypename))
3912       player->aitypename = NULL;
3913     /* This seems like a logical place to canonicalize an AI type
3914        of "ai" into a specific type, but we don't necessarily know
3915        the best default until the game is closer to starting. */
3916 }
3917 
3918 /* Make a printable identification of the given player.  The output
3919    here must be correctly parseable according to player spec rules,
3920    although it doesn't have to be pretty or minimal. */
3921 
3922 char *
player_desig(Player * player)3923 player_desig(Player *player)
3924 {
3925     if (playerdesigbuf == NULL)
3926       playerdesigbuf = (char *)xmalloc(BUFSIZE);
3927     if (player != NULL) {
3928 	snprintf(playerdesigbuf, BUFSIZE, "%s,%s/%s@%s+%d",
3929 		(player->name ? player->name : ""),
3930 		(player->aitypename ? player->aitypename : ""),
3931 		(player->configname ? player->configname : ""),
3932 		(player->displayname ? player->displayname : ""),
3933 		player->advantage);
3934     } else {
3935 	sprintf(playerdesigbuf, "nullplayer");
3936     }
3937     return playerdesigbuf;
3938 }
3939 
3940 /* Return the net advantage of the side, accounting for both the
3941    side's predetermined advantage and the player's choice. */
3942 
3943 int
actual_advantage(Side * side)3944 actual_advantage(Side *side)
3945 {
3946     int advantage = max(1, side->advantage);
3947 
3948     if (side->player)
3949       advantage = side->player->advantage;
3950     return advantage;
3951 }
3952 
3953 /* Doctrine handling. */
3954 
3955 Doctrine *
new_doctrine(int id)3956 new_doctrine(int id)
3957 {
3958     Doctrine *doctrine = (Doctrine *) xmalloc(sizeof(Doctrine));
3959 
3960     /* Doctrine ids start at 1 and go up. */
3961     if (id <= 0)
3962       id = next_doctrine_id++;
3963     else
3964       next_doctrine_id = id + 1;
3965     doctrine->id = id;
3966     /* Fill in all the doctrine slots with their default values. */
3967     doctrine->resupply_percent = 50;
3968     doctrine->rearm_percent = 20;
3969     /* 35% is basically 1/3, rounded up. */
3970     doctrine->repair_percent = 35;
3971     doctrine->resupply_complete = 100;
3972     doctrine->rearm_complete = 100;
3973     doctrine->repair_complete = 100;
3974     doctrine->min_turns_food = 5;
3975     doctrine->min_distance_fuel = 20;
3976     doctrine->construction_run = (short *) xmalloc (numutypes * sizeof(short));
3977     /* We just committed on the number of unit types. */
3978     disallow_more_unit_types();
3979     /* Add the new doctrine to the end of the list of doctrines. */
3980     if (last_doctrine != NULL) {
3981 	last_doctrine->next = doctrine;
3982 	last_doctrine = doctrine;
3983     } else {
3984 	doctrine_list = last_doctrine = doctrine;
3985     }
3986     return doctrine;
3987 }
3988 
3989 Doctrine *
find_doctrine_by_name(char * name)3990 find_doctrine_by_name(char *name)
3991 {
3992     Doctrine *doctrine;
3993 
3994     if (name == NULL)
3995       return NULL;
3996     for_all_doctrines(doctrine) {
3997 	if (doctrine->name != NULL && strcmp(name, doctrine->name) == 0)
3998 	  return doctrine;
3999     }
4000     return NULL;
4001 }
4002 
4003 Doctrine *
find_doctrine(int id)4004 find_doctrine(int id)
4005 {
4006     Doctrine *doctrine;
4007 
4008     for_all_doctrines(doctrine) {
4009 	if (doctrine->id == id)
4010 	  return doctrine;
4011     }
4012     return NULL;
4013 }
4014 
4015 #if 0 /* seems useful, but never actually used */
4016 Doctrine *
4017 clone_doctrine(Doctrine *olddoc)
4018 {
4019     int tmpid;
4020     Doctrine *newdoc, *tmpnext;
4021 
4022     newdoc = new_doctrine(0);
4023     tmpid = newdoc->id;
4024     tmpnext = newdoc->next;
4025     memcpy(newdoc, olddoc, sizeof(Doctrine));
4026     newdoc->id = tmpid;
4027     /* Always allocate and copy subarrays. */
4028     newdoc->construction_run = (short *) xmalloc (numutypes * sizeof(short));
4029     memcpy(newdoc->construction_run, olddoc->construction_run, numutypes * sizeof(short));
4030     newdoc->next = tmpnext;
4031     return newdoc;
4032 }
4033 #endif
4034 
4035 /* Standing order handling. */
4036 
4037 StandingOrder *
new_standing_order(void)4038 new_standing_order(void)
4039 {
4040     StandingOrder *sorder;
4041 
4042     sorder = (StandingOrder *) xmalloc(sizeof(StandingOrder));
4043     sorder->types = (char *)xmalloc(numutypes);
4044     return sorder;
4045 }
4046 
4047 /* Add a new standing order for the side.  This function can add to front
4048    or back of existing list of orders. */
4049 
4050 int order_conds_match(StandingOrder *sorder, StandingOrder *sorder2);
4051 
4052 void
add_standing_order(Side * side,StandingOrder * sorder,int pos)4053 add_standing_order(Side *side, StandingOrder *sorder, int pos)
4054 {
4055     StandingOrder *sorder2, *saved;
4056 
4057     if (sorder->task == NULL) {
4058 	/* Cancelling an order. */
4059 	saved = NULL;
4060 	if (side->orders == NULL) {
4061 	    /* No orders, so nothing to do. */
4062 	    notify(side, "No orders to cancel");
4063 	} else if (order_conds_match(sorder, side->orders)) {
4064 	    /* Delete the first order in the list. */
4065 	    saved = side->orders;
4066 	    if (side->last_order == side->orders)
4067 	      side->last_order = side->orders->next;
4068 	    side->orders = side->orders->next;
4069 	} else {
4070 	    for (sorder2 = side->orders; sorder2->next != NULL; sorder2 = sorder2->next) {
4071 		if (order_conds_match(sorder, sorder2->next)) {
4072 		    saved = sorder2->next;
4073 		    if (side->last_order == sorder2->next)
4074 		      side->last_order = sorder2->next->next;
4075 		    sorder2->next = sorder2->next->next;
4076 		    break;
4077 		}
4078 	    }
4079 	    /* If we're here, no match; might be user error, but can't be sure,
4080 	       so don't say anything. */
4081 	}
4082 	if (saved != NULL) {
4083 	    notify(side, "Cancelled order `%s'", standing_order_desc(saved, spbuf));
4084 	}
4085     } else if (pos == 0) {
4086 	/* Add order to front of list. */
4087 	sorder->next = side->orders;
4088 	side->orders = sorder;
4089 	if (side->last_order == NULL)
4090 	  side->last_order = sorder;
4091     } else if (side->last_order != NULL) {
4092 	/* Add order to end of list. */
4093 	side->last_order->next = sorder;
4094 	side->last_order = sorder;
4095     } else {
4096 	/* First standing order for the side. */
4097 	side->orders = side->last_order = sorder;
4098     }
4099 }
4100 
4101 int
order_conds_match(StandingOrder * sorder,StandingOrder * sorder2)4102 order_conds_match(StandingOrder *sorder, StandingOrder *sorder2)
4103 {
4104     return (sorder->condtype == sorder2->condtype
4105 	    && sorder->a1 == sorder2->a1
4106 	    && sorder->a2 == sorder2->a2
4107 	    && sorder->a3 == sorder2->a3);
4108 }
4109 
4110 int
parse_standing_order(Side * side,char * cmdstr)4111 parse_standing_order(Side *side, char *cmdstr)
4112 {
4113     StandingOrder *sorder, *sorder2;
4114 
4115     if (cmdstr[0] == '?') {
4116 	if (side->orders != NULL) {
4117 	    notify(side, "Current standing orders:");
4118 	    for (sorder2 = side->orders; sorder2 != NULL; sorder2 = sorder2->next) {
4119 		notify(side, "  %s", standing_order_desc(sorder2, spbuf));
4120 	    }
4121 	} else {
4122 	    notify(side, "No standing orders in effect.");
4123 	}
4124 	return 0;
4125     }
4126     sorder = new_standing_order();
4127     cmdstr = parse_unit_types(side, cmdstr, sorder->types);
4128     if (cmdstr == NULL)
4129       return (-1);
4130     cmdstr = parse_order_cond(side, cmdstr, sorder);
4131     if (cmdstr == NULL)
4132       return (-2);
4133     cmdstr = parse_task(side, cmdstr, &(sorder->task));
4134     if (cmdstr == NULL)
4135       return (-3);
4136     add_standing_order(side, sorder, 0);
4137     if (sorder->task != NULL) {
4138 	notify(side, "New standing order: %s", standing_order_desc(sorder, spbuf));
4139     }
4140     return 0;
4141 }
4142 
4143 /* (should all go to nlang.c?) */
4144 
4145 char *
parse_unit_types(Side * side,char * str,char * utypevec)4146 parse_unit_types(Side *side, char *str, char *utypevec)
4147 {
4148     char *arg, substr[BUFSIZE], *rest;
4149     int u;
4150 
4151     rest = get_next_arg(str, substr, &arg);
4152     u = utype_from_name(arg);
4153     if (u != NONUTYPE) {
4154 	utypevec[u] = 1;
4155     } else if (strcmp(arg, "all") == 0) {
4156 	for_all_unit_types(u)
4157 	  utypevec[u] = 1;
4158     } else {
4159 	notify(side, "Unit type \"%s\" not recognized", arg);
4160 	return NULL;
4161     }
4162     return rest;
4163 }
4164 
4165 char *
parse_order_cond(Side * side,char * str,StandingOrder * sorder)4166 parse_order_cond(Side *side, char *str, StandingOrder *sorder)
4167 {
4168     int x = 0, y = 0, dist = 0;
4169     char *arg, *arg2, substr[BUFSIZE], *rest;
4170     Unit *unit;
4171 
4172     rest = get_next_arg(str, substr, &arg);
4173     if (strcmp(arg, "at") == 0 || strcmp(arg, "@") == 0) {
4174 	sorder->condtype = sorder_at;
4175     } else if (strcmp(arg, "in") == 0) {
4176 	sorder->condtype = sorder_in;
4177     } else if (strcmp(arg, "within") == 0 || strcmp(arg, "near") == 0) {
4178 	sorder->condtype = sorder_near;
4179     } else {
4180 	notify(side, "Condition type \"%s\" not recognized", arg);
4181 	return NULL;
4182     }
4183     if (sorder->condtype == sorder_near) {
4184 	rest = get_next_arg(rest, substr, &arg);
4185 	dist = strtol(arg, &arg2, 10);
4186 	sorder->a3 = dist;
4187     }
4188     rest = get_next_arg(rest, substr, &arg);
4189     x = strtol(arg, &arg2, 10);
4190     if (arg != arg2 && *arg2 == ',') {
4191 	y = strtol(arg2 + 1, &arg, 10);
4192 	sorder->a1 = x;  sorder->a2 = y;
4193 	return rest;
4194     } else if ((unit = find_unit_by_name(arg)) != NULL) {
4195 	if (sorder->condtype == sorder_at || sorder->condtype == sorder_near) {
4196 	    sorder->a1 = x;  sorder->a2 = y;
4197 	} else if (sorder->condtype == sorder_in) {
4198 	    sorder->a1 = unit->id;
4199 	} else {
4200 	    return NULL;
4201 	}
4202 	return rest;
4203     } else {
4204 	notify(side, "Condition argument \"%s\" not recognized", arg);
4205 	return NULL;
4206     }
4207 }
4208 
4209 char *
standing_order_desc(StandingOrder * sorder,char * buf)4210 standing_order_desc(StandingOrder *sorder, char *buf)
4211 {
4212     int u, v = -1, i = 1;
4213     int *args;
4214 
4215     for_all_unit_types(u) {
4216 	if (sorder->types[u]) {
4217 	    if (v < 0)
4218 	      v = u;
4219 	} else {
4220 	    i = 0;
4221 	}
4222     }
4223     if (v < 0 || sorder->task == NULL) {
4224 	strcpy(buf, "invalid");
4225 	return buf;
4226     }
4227     sprintf(buf, "if %s ", (i ? "all" : u_type_name(v)));
4228 
4229     switch (sorder->condtype) {
4230     case sorder_at:
4231 	tprintf(buf, "at %d,%d ", sorder->a1, sorder->a2);
4232 	break;
4233     case sorder_in:
4234 	tprintf(buf, "in %s ", short_unit_handle(find_unit(sorder->a1)));
4235 	break;
4236     case sorder_near:
4237 	tprintf(buf, "within %d %d,%d ", sorder->a3,  sorder->a1, sorder->a2);
4238 	break;
4239     default:
4240 	strcat(buf, "unknown");
4241 	return buf;
4242     }
4243 
4244     i = sorder->task->type;
4245     args = sorder->task->args;
4246     switch (i) {
4247     case TASK_MOVE_TO:
4248 	tprintf(buf, "%s %d,%d", taskdefns[i].display_name, args[0], args[1]);
4249 	break;
4250     case TASK_SENTRY:
4251 	tprintf(buf, "%s %d", taskdefns[i].display_name, args[0]);
4252 	break;
4253     default:
4254 	task_desc(buf+strlen(buf), NULL, NULL, sorder->task);
4255 	break;
4256     }
4257     return buf;
4258 }
4259 
4260 /* Collect the next whitespace-separated argument. */
4261 /* (should move to util.c or nlang.c) */
4262 
4263 char *
get_next_arg(char * str,char * buf,char ** rsltp)4264 get_next_arg(char *str, char *buf, char **rsltp)
4265 {
4266     char *p;
4267 
4268     strcpy(buf, str);
4269     p = buf;
4270     /* Skip past any leading whitespace. */
4271     while (isspace(*p))
4272       ++p;
4273     if (*p == '"') {
4274 	++p;
4275 	*rsltp = p;
4276 	while (*p != '"' && *p != '\0')
4277 	  ++p;
4278 	*p = '\0';
4279 	/* Increment so later scanning looks past the closing quote. */
4280 	++p;
4281     } else {
4282 	*rsltp = p;
4283 	while (!isspace(*p) && *p != '\0')
4284 	  ++p;
4285 	*p = '\0';
4286     }
4287     return str + (p - buf);
4288 }
4289 
4290 #if 0
4291 
4292 /* Agreement handling here for now. */
4293 
4294 Agreement *agreement_list = NULL;
4295 
4296 Agreement *last_agreement;
4297 
4298 int num_agreements = 0;
4299 
4300 int next_agreement_id = 1;
4301 
4302 char *agreement_desig_buf;
4303 
4304 void
4305 init_agreements(void)
4306 {
4307     agreement_list = last_agreement = NULL;
4308     num_agreements = 0;
4309 }
4310 
4311 Agreement *
4312 create_agreement(int id)
4313 {
4314     Agreement *ag = (Agreement *) xmalloc(sizeof(Agreement));
4315 
4316     if (id == 0)
4317       id = next_agreement_id++;
4318     ag->id = id;
4319     ag->terms = lispnil;
4320     ag->next = NULL;
4321     if (agreement_list != NULL) {
4322 	last_agreement->next = ag;
4323     } else {
4324 	agreement_list = ag;
4325     }
4326     last_agreement = ag;
4327     ++num_agreements;
4328     return ag;
4329 }
4330 
4331 Agreement *
4332 find_agreement(int id)
4333 {
4334     Agreement *ag;
4335 
4336     for_all_agreements(ag) {
4337 	if (ag->id == id)
4338 	  return ag;
4339     }
4340     return NULL;
4341 }
4342 
4343 char *
4344 agreement_desig(Agreement *ag)
4345 {
4346     if (agreement_desig_buf == NULL)
4347       agreement_desig_buf = (char *)xmalloc(BUFSIZE);
4348     sprintf(agreement_desig_buf, "<ag %s %s %s>",
4349 	    (ag->agtype ? ag->agtype : "(null)"),
4350 	    (ag->name ? ag->name : "(null)"),
4351 	    (ag->terms == lispnil ? "(no terms)" : "...terms..."));
4352     return agreement_desig_buf;
4353 }
4354 
4355 #endif
4356 
4357 /* Helper functions to init view layers from rle encoding. */
4358 
4359 void
fn_set_terrain_view(int x,int y,int val)4360 fn_set_terrain_view(int x, int y, int val)
4361 {
4362     int rawval;
4363 
4364     if (1)
4365       rawval = val;
4366     else
4367       /* This is a more efficient encoding, but only usable if can guarantee
4368 	 see-terrain-always upon rereading. */
4369       rawval = (val ? buildtview(terrain_at(x, y)) : 0);
4370     set_terrain_view(tmpside, x, y, rawval);
4371 }
4372 
4373 void
fn_set_terrain_view_date(int x,int y,int val)4374 fn_set_terrain_view_date(int x, int y, int val)
4375 {
4376     set_terrain_view_date(tmpside, x, y, val);
4377 }
4378 
4379 void
fn_set_aux_terrain_view(int x,int y,int val)4380 fn_set_aux_terrain_view(int x, int y, int val)
4381 {
4382     /* Filter anything but the basic six bits. */
4383     val &= 0x3f;
4384     set_aux_terrain_view(tmpside, x, y, tmpttype, val);
4385 }
4386 
4387 void
fn_set_aux_terrain_view_date(int x,int y,int val)4388 fn_set_aux_terrain_view_date(int x, int y, int val)
4389 {
4390     set_aux_terrain_view_date(tmpside, x, y, tmpttype, val);
4391 }
4392 
4393 void
fn_set_material_view(int x,int y,int val)4394 fn_set_material_view(int x, int y, int val)
4395 {
4396     set_material_view(tmpside, x, y, tmpmtype, val);
4397 }
4398 
4399 void
fn_set_material_view_date(int x,int y,int val)4400 fn_set_material_view_date(int x, int y, int val)
4401 {
4402     set_material_view_date(tmpside, x, y, tmpmtype, val);
4403 }
4404 
4405 void
fn_set_temp_view(int x,int y,int val)4406 fn_set_temp_view(int x, int y, int val)
4407 {
4408     set_temperature_view(tmpside, x, y, val);
4409 }
4410 
4411 void
fn_set_temp_view_date(int x,int y,int val)4412 fn_set_temp_view_date(int x, int y, int val)
4413 {
4414     set_temperature_view_date(tmpside, x, y, val);
4415 }
4416 
4417 void
fn_set_cloud_view(int x,int y,int val)4418 fn_set_cloud_view(int x, int y, int val)
4419 {
4420     set_cloud_view(tmpside, x, y, val);
4421 }
4422 
4423 void
fn_set_cloud_bottom_view(int x,int y,int val)4424 fn_set_cloud_bottom_view(int x, int y, int val)
4425 {
4426     set_cloud_bottom_view(tmpside, x, y, val);
4427 }
4428 
4429 void
fn_set_cloud_height_view(int x,int y,int val)4430 fn_set_cloud_height_view(int x, int y, int val)
4431 {
4432     set_cloud_height_view(tmpside, x, y, val);
4433 }
4434 
4435 void
fn_set_cloud_view_date(int x,int y,int val)4436 fn_set_cloud_view_date(int x, int y, int val)
4437 {
4438     set_cloud_view_date(tmpside, x, y, val);
4439 }
4440 
4441 void
fn_set_wind_view(int x,int y,int val)4442 fn_set_wind_view(int x, int y, int val)
4443 {
4444     set_wind_view(tmpside, x, y, val);
4445 }
4446 
4447 void
fn_set_wind_view_date(int x,int y,int val)4448 fn_set_wind_view_date(int x, int y, int val)
4449 {
4450     set_wind_view_date(tmpside, x, y, val);
4451 }
4452 
4453 #ifdef DESIGNERS
4454 
4455 static void paint_view_1(int x, int y);
4456 
4457 static int tmptview;
4458 static int tmpuviewflag;
4459 
4460 /* Paint the side's view with given values. */
4461 
4462 void
paint_view(Side * side,int x,int y,int r,int tview,int uviewflag)4463 paint_view(Side *side, int x, int y, int r, int tview, int uviewflag)
4464 {
4465     tmpside = side;
4466     tmptview = tview;
4467     tmpuviewflag = uviewflag;
4468     apply_to_area_plus_edge(x, y, r, paint_view_1);
4469 }
4470 
4471 static void
paint_view_1(int x,int y)4472 paint_view_1(int x, int y)
4473 {
4474     int tview, oldtview = terrain_view(tmpside, x, y);
4475 
4476     if (oldtview != tmptview) {
4477 	tview = tmptview;
4478 	if (tview == 1234567) {
4479 	    tview = buildtview(terrain_at(x, y));
4480 	}
4481 	set_terrain_view(tmpside, x, y, tview);
4482 	/* If the flag says so, see all units in the cell, otherwise
4483 	   leave all units unseen. */
4484 	/* (should we do a see_cell in any case?) */
4485 	if (tmpuviewflag && tview != UNSEEN) {
4486 	    see_exact(tmpside, x, y);
4487 	}
4488 	update_cell_display(tmpside, x, y, UPDATE_ALWAYS | UPDATE_ADJ);
4489     }
4490 }
4491 
4492 #endif /* DESIGNERS */
4493 
4494 /* Find a side's total supply of a given material.  */
4495 
4496 int
side_material_supply(Side * side,int m)4497 side_material_supply(Side * side, int m)
4498 {
4499 	Unit	* unit;
4500 	int	supply = 0;
4501 
4502 	if (!is_material_type(m)) {
4503 		return -1;
4504 	}
4505 	/* Add up unit supplies. */
4506 	for_all_side_units(side, unit) {
4507 		/* This also counts units under construction, which
4508 		can store materials. */
4509 		if (in_play(unit)) {
4510 			supply += unit->supply[m];
4511 		}
4512 	}
4513 	/* Add stuff in the side's treasury. */
4514 	if (side_has_treasury(side, m)) {
4515 		supply += side->treasury[m];
4516 	}
4517 	return supply;
4518 }
4519 
4520 /* Find a side's total production of a given material. */
4521 
side_material_production(Side * side,int m)4522 int side_material_production(Side * side, int m)
4523 {
4524 	Unit	*unit;
4525 	int	x, y;
4526 	int	production = 0;
4527 
4528 	for_all_side_units(side, unit) {
4529 		if(!is_active(unit)) {
4530 			continue;
4531 		}
4532 		/* Only advanced units collect materials from cells. */
4533 		if (u_advanced(unit->type)) {
4534 			for_all_cells_within_reach(unit, x, y) {
4535 				if (!inside_area(x, y)) {
4536 					continue;
4537 				}
4538 				if (user_at(x, y) == unit->id) {
4539 					production += production_at(x, y, m);
4540 				}
4541 			}
4542 		}
4543 		/* Both advanced and non-advanced units may do this. */
4544 		production += base_production(unit, m);
4545 	}
4546 	return production;
4547 }
4548 /* Find a side's total storage capacity for a given material. */
4549 
side_material_storage(Side * side,int m)4550 int side_material_storage(Side * side, int m)
4551 {
4552 	Unit	*unit;
4553 	int	storage = 0;
4554 
4555 	for_all_side_units(side, unit) {
4556 		/* This also counts units under construction, which
4557 		can store materials. */
4558 		if(!in_play(unit)) {
4559 			continue;
4560 		}
4561 		storage += um_storage_x(unit->type, m);
4562 	}
4563 	/* Add room in the side's treasury if it exists. */
4564 	if (side_has_treasury(side, m)) {
4565 		/* Clip to VARHI to prevent numeric overflow. */
4566 		storage += min(g_treasury_size(), VARHI - storage);
4567 	}
4568 	return storage;
4569 }
4570 
4571 /* Selectively choose an advance from a weighted list accounting for what
4572    advances the side already has and could possibly research. */
4573 
4574 Obj *
choose_side_research_goal_from_weighted_list(Obj * lis,int * totalweightp,Side * side)4575 choose_side_research_goal_from_weighted_list(Obj *lis, int *totalweightp,
4576 					     Side *side)
4577 {
4578     int n, sofar, weight, a = NONATYPE;
4579     char buf[BUFSIZE];
4580     Obj *rest, *head, *tail, *rslt, *adv;
4581 
4582     assert_error(lis, "Attempted to access a NULL list");
4583     assert_error(lis != lispnil, "Attempted to use a nil list");
4584     assert_error(side, "Attempted to access a NULL side");
4585     if (*totalweightp <= 0) {
4586 	for_all_list(lis, rest) {
4587 	    head = car(rest);
4588 	    if (symbolp(head))
4589 	      adv = eval_symbol(head);
4590 	    else if (consp(head))
4591 	      adv = cadr(head);
4592 	    else
4593 	      adv = head;
4594 	    if (!atypep(adv) || !is_advance_type(c_number(adv))) {
4595 		Dprintf(
4596 "Illegal list element encountered in a side research goal list.");
4597 		return lispnil;
4598 	    }
4599 	    else
4600 	      a = c_number(adv);
4601 	    if (has_advance(side, a) || side->research_precluded[a])
4602 	      continue;
4603 	    weight = ((consp(head) && numberp(car(head))) ? c_number(car(head))
4604 							  : 1);
4605 	    *totalweightp += weight;
4606 	}
4607     }
4608     /* If total weight is 0, then return nil. */
4609     if (*totalweightp == 0)
4610       return lispnil;
4611     n = xrandom(*totalweightp);
4612     sofar = 0;
4613     rslt = lispnil;
4614     for_all_list(lis, rest) {
4615 	head = car(rest);
4616 	if (symbolp(head))
4617 	  adv = eval_symbol(head);
4618 	else if (consp(head))
4619 	  adv = cadr(head);
4620 	else
4621 	  adv = head;
4622 	a = c_number(adv);
4623 	if (has_advance(side, a) || side->research_precluded[a])
4624 	  continue;
4625 	if (consp(head) && numberp(car(head))) {
4626 	    sofar += c_number(car(head));
4627 	    tail = cadr(head);
4628 	} else {
4629 	    sofar += 1;
4630 	    tail = head;
4631 	}
4632 	if (sofar > n) {
4633 	    rslt = tail;
4634 	    break;
4635 	}
4636     }
4637     return rslt;
4638 }
4639