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, ¶mboxus);
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 *)¶mboxus);
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 *)(¶mboxus));
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 *)¶mboxus);
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