1 /* The main simulation-running code in Xconq, turn start and end calcs.
2    Copyright (C) 1986-1989, 1991-2000 Stanley T. Shebs.
3    Copyright (C) 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 code calculates what happens at the beginning and end of each turn. */
11 
12 #include "conq.h"
13 #include "kernel.h"
14 
15 /* Auto Repair */
16 extern int check_repair_action(Unit *actor, Unit *repairer, Unit *repairee);
17 extern int do_repair_action(Unit *actor, Unit *repairer, Unit *repairee);
18 
19 extern int stop_apply;
20 
21 static void vary_winds(void);
22 
23 extern int gamestatesafe;
24 
25 static int visible_to(Unit *unit, Unit *unit2);
26 static void add_new_sides_to_game(void);
27 static void run_tech_leakage(void);
28 static void cache_init_tech_levels(void);
29 static void run_tooling_attrition(void);
30 static void run_cp_attrition(void);
31 static void reset_all_reserves(void);
32 static void save_checkpoint(int curturn);
33 static void compute_moves(void);
34 static void finish_movement(void);
35 #if 0
36 static void test_agreements(void);
37 #endif
38 static void compute_sun(void);
39 static void run_sun(void);
40 static void compute_season(void);
41 static void run_environment(void);
42 static void mix_winds(void);
43 static void all_see_cell_weather(int x, int y);
44 static void run_spies(void);
45 static void run_accidents(void);
46 static void run_attrition(void);
47 static void run_revolts(void);
48 static void unit_revolt(Unit *unit, int force);
49 static void run_surrenders(void);
50 static void unit_surrender(Unit *unit);
51 static void maybe_surrender_to(Unit *unit, Unit *unit2);
52 static void run_self_builds(void);
53 static void run_environment_effects(void);
54 static void damage_unit_with_temperature(Unit *unit, int n);
55 static void run_people_side_changes(void);
56 static void run_appearances(void);
57 static void run_disappearances(void);
58 
59 //! Handle auto-repair for all units in game.
60 static void run_auto_repair(void);
61 //! Auto-repair from within given transport.
62 static void auto_repair_from_in(Unit *transport);
63 //! Auto-repair from given location.
64 static void auto_repair_from_here(int x, int y);
65 
66 static void run_morale_recovery(void);
67 static void run_auto_change_types(void);
68 static int season_effect(int u);
69 static void run_unit_fates(void);
70 static void run_detonation_accidents(void);
71 static void run_people_limits(void);
72 static void spy_on_location(int x, int y);
73 
74 /* Set this flag to suppress normal cell updates. Should only be set if
75 all maps will be redrawn before any units can act. */
76 
77 int suppress_update_cell_display = FALSE;
78 
79 /* The number of the current turn within a year. */
80 
81 int curyearpart = -1;
82 
83 /* The season name for the current turn. */
84 
85 char *curseasonname;
86 
87 /* The full date/season/day-night string that interfaces should display. */
88 
89 char *curdatestr;
90 
91 /* Do we want saves while playing? */
92 
93 int want_checkpoints = FALSE;
94 
95 /* How often to do saves while playing. */
96 
97 int checkpoint_interval = 0;
98 
99 static char *last_checkpoint_filename;
100 
101 /* The number of new sides that have been requested to be added. */
102 
103 int new_sides_requested;
104 
105 char **players_requested;
106 
107 /* True whenever the game has both day and night. */
108 
109 int daynight = FALSE;
110 
111 /* The location of the sun, as a position relative to the area.  The
112    actual values may be far outside the area. */
113 
114 int sunx, suny;
115 
116 /* The sun's previous location. */
117 
118 int lastsunx = -1, lastsuny = -1;
119 
120 /* If the area is uniformly lighted, this is that value. */
121 
122 int area_lighting = -1;
123 
124 /* Flags indicating whether various sets of calculations need to be done. */
125 
126 /* Typically we set to -1 to indicate that the value is uncomputed, then detect
127    when the value is first needed and compute a true/false value, which we then
128    use thereafter. */
129 
130 short any_tooling_attrition = -1;
131 
132 short any_cp_attrition = -1;
133 
134 short any_self_builds = -1;
135 
136 short any_environment_effects = -1;
137 
138 short any_appearances = -1;
139 
140 short any_disappearances = -1;
141 
142 short any_people_side_changes = -1;
143 
144 short *any_people_surrenders = NULL;
145 
146 short any_morale_recovery = -1;
147 
148 short any_tech_leakage = -1;
149 
150 short any_detonation_accidents = -1;
151 
152 short any_lost_vanish = -1;
153 
154 short any_lost_wreck = -1;
155 
156 short any_lost_surrender = -1;
157 
158 short any_lost_revolt = -1;
159 
160 short any_people_max = -1;
161 
162 short any_spying = -1;
163 
164 short any_annual_temp_change = -1;
165 
166 short any_accidents = -1;
167 
168 short any_attrition = -1;
169 
170 short any_revolts = -1;
171 
172 short any_surrenders = -1;
173 
174 namespace Xconq {
175     short any_hp_recovery = FALSE;
176     short any_auto_repair = FALSE;
177     short *cv__could_be_auto_repaired = NULL;
178     short *cv__auto_repaired_range_max = NULL;
179 }
180 
181 short any_auto_change_types = FALSE;
182 
183 static short *surrender_ranges;
184 
185 static char *any_lost_surrenders;
186 
187 /* Do everything that would happen before movement in a turn. */
188 
189 void
run_turn_start(void)190 run_turn_start(void)
191 {
192     int curturn;
193     time_t turncalcstart, turncalcend;
194     Side *side;
195 
196     /* Increment the turn number. */
197     curturn = g_turn();
198     ++curturn;
199     set_g_turn(curturn);
200     /* Add any sides that were requested to be added during the
201        previous turn. */
202     add_new_sides_to_game();
203     /* Warn players if the game is nearly over. */
204     if (curturn >= g_last_turn()) {
205 	if (g_extra_turn() > 0) {
206 	    notify_all("This may be the last turn in the game!");
207 	} else {
208 	    notify_all("This is the last turn in the game!");
209 	}
210     }
211     time(&turncalcstart);
212     update_all_progress_displays("turn start calcs", -1);
213     compute_season();
214     Dprintf("##### TURN %d (%s) #####\n", curturn, curdatestr);
215     /* Mark the change of turn even if only dumping AI and planning info. */
216     if (!Debug)
217       DMprintf("##### TURN %d (%s) #####\n", curturn, curdatestr);
218     for_all_sides(side) {
219 	side->finishedturn = FALSE;
220 	update_turn_display(side, TRUE);
221 	if (realtime_game()) {
222 	    update_clock_display(side, TRUE);
223 	}
224 	/* Update legends and their positions as new terrain comes into view. */
225 	place_legends(side);
226 	/* Needed to update legends in games that have them, but probably a
227 	good idea to redraw the maps each turn anyway. */
228 	update_area_display(side);
229     }
230     /* Do a variety of each-turn backdrop activities. */
231     run_sun();
232     run_environment();
233     run_ui_idler(); /* Take a breather for UI events. */
234     /* Advanced unit support. */
235     run_advanced_units();
236     /* Optionally run economy and supply code. */
237     if (g_people())
238       run_people();
239     run_ui_idler(); /* Take a breather for UI events. */
240     if (g_economy())
241       run_economy();
242     run_ui_idler(); /* Take a breather for UI events. */
243     if (g_supply())
244       run_supply();
245     run_ui_idler(); /* Take a breather for UI events. */
246     run_auto_repair();
247     run_self_builds();
248     run_morale_recovery();
249     run_ui_idler(); /* Take a breather for UI events. */
250     run_auto_change_types();
251     run_appearances();
252     run_accidents();
253     run_attrition();
254     run_revolts();
255     run_surrenders();
256     run_unit_fates();
257     run_detonation_accidents();
258     run_ui_idler(); /* Take a breather for UI events. */
259     sort_units(TRUE);
260     compute_moves();
261     run_spies();
262     run_tech_leakage();
263     run_tooling_attrition();
264     run_cp_attrition();
265     cache_init_tech_levels();
266     reset_all_reserves();
267     gamestatesafe = FALSE;
268     save_checkpoint(curturn);
269     time(&turncalcend);
270     Dprintf("%d seconds to calc at turn start\n",
271 	    idifftime(turncalcend, turncalcstart));
272 }
273 
274 /* Do computations to start the first turn of a restored game. */
275 
276 void
run_restored_turn_start(void)277 run_restored_turn_start(void)
278 {
279     Side *side;
280 
281     compute_season();
282     Dprintf("##### TURN %d (%s) #####\n", g_turn(), curdatestr);
283     for_all_sides(side) {
284 	update_turn_display(side, TRUE);
285 	if (realtime_game()) {
286 	    update_clock_display(side, TRUE);
287 	}
288     }
289     compute_sun();
290     sort_units(TRUE);
291     /* We're done with restore-specific tweaks, turn the flag off. */
292     midturnrestore = FALSE;
293 }
294 
295 /* Do everything associated with the end of a turn. */
296 
297 void
run_turn_end(void)298 run_turn_end(void)
299 {
300     update_all_progress_displays("turn end calcs", -1);
301     finish_movement();
302     run_all_consumption();
303     run_environment_effects();
304     run_people_side_changes();
305     /* This should come after other people-related computations,
306        since this only constrains generic overcrowding. */
307     run_people_limits();
308     flush_dead_units();
309     flush_stale_views();
310     check_post_turn_scores();
311 #if 0
312     test_agreements();
313 #endif
314     run_disappearances();
315 #ifdef DEBUGGING
316     if (Debug)
317       report_malloc();
318 #endif /* DEBUGGING */
319     /* See if we've hit a preset end to the game. */
320     if (g_turn() >= g_last_turn() && !probability(g_extra_turn())) {
321 	notify_all("This is the end of the last turn in the game!");
322 	end_the_game();
323     }
324 }
325 
326 /* Interfaces should call this to have another side added to the current
327    game.  The actual addition happens during turn setup, so as not to
328    risk confusing list traversals or AI calculations. */
329 
330 void
request_additional_side(char * playerspec)331 request_additional_side(char *playerspec)
332 {
333     if (numsides + new_sides_requested + 1 <= g_sides_max()) {
334 	if (players_requested == NULL)
335 	  players_requested =
336 	    (char **) xmalloc((MAXSIDES + 1) * sizeof(char *));
337 	if (empty_string(playerspec))
338 	  playerspec = ",ai";
339 	players_requested[new_sides_requested++] = copy_string(playerspec);
340 	notify_all(
341 "Will add a new side (player \"%s\") at the start of the next turn",
342 		   playerspec);
343     } else {
344 	notify_all(
345 "Additional side requested (player \"%s\"), but not possible to add",
346 		   playerspec);
347     }
348 }
349 
350 /* Add the requested number of new sides into an ongoing game. */
351 
352 static void
add_new_sides_to_game(void)353 add_new_sides_to_game(void)
354 {
355     int i;
356     Side *side, *side2;
357     Player *player;
358     Unit *unit;
359     extern int need_ai_for_new_side;
360 
361     if (new_sides_requested > 0) {
362 	for (i = 0; i < new_sides_requested; ++i) {
363 	    if (numsides >= g_sides_max())
364 	      break;
365 	    /* Grow side-referencing objects. */
366 	    for_all_units(unit) {
367 		if (unit->opinions != NULL) {
368 		    init_unit_opinions(unit, numsides + 1);
369 		}
370 	    }
371 	    side = make_up_a_side();
372 	    player = add_player();
373 	    parse_player_spec(player, players_requested[i]);
374 	    player->side = side;
375 	    side->player = player;
376 	    /* Set the player's advantage to be the side's advantage, if not
377 	       already set. */
378 	    if (player->advantage == 0) {
379 		player->advantage = side->advantage;
380 	    }
381 	    run_synth_methods();
382 	    init_doctrine(side);
383 	    init_self_unit(side);
384 	    if (g_use_side_priority()) {
385 		int maxpri = 0;
386 
387 		for_all_sides(side2) {
388 		    if (side2->priority > maxpri)
389 		      maxpri = side2->priority;
390 		}
391 		side->priority = maxpri + 1;
392 		/* If the indepside's priority was set automatically to be
393 		   one up from regular sides', bump it up to be past the new
394 		   side's priority also. */
395 		if (indepside->priority == side->priority)
396 		  ++(indepside->priority);
397 	    }
398 	    /* Count all of the new side's units as initial gain. */
399 	    for_all_side_units(side, unit) {
400 		count_gain(side, unit->type, initial_gain);
401 	    }
402 	    /* Maybe record that we need to create an AI for the new
403                side later. */
404 	    if (side_wants_ai(side)) {
405 		need_ai_for_new_side = TRUE;
406 	    }
407 	    for_all_sides(side2) {
408 		/* Give all other AIs a chance to rework internal data
409                    structures. */
410 		/* (should move to run_local_ai?) */
411 		if (side_has_ai(side2) && side2 != side) {
412 		    ai_react_to_new_side(side2, side);
413 		}
414 		/* Add the new side to displays. */
415 		update_side_display(side2, side, TRUE);
416 		notify(side2, "A new side %s (played by %s) is in the game.",
417 		       side_desig(side), player_desig(player));
418 	    }
419 	}
420 	if (i > 0) {
421 	    /* Recalculate all view info for all sides; simpler than
422 	       trying to figure out what's really changed. */
423 	    really_reset_coverage();
424 	    reset_all_views();
425 	    compute_all_feature_centroids();
426 	    /* Redraw everything that's displayed. */
427 	    update_everything();
428 	}
429 	if (i < new_sides_requested) {
430 	    notify_all("Cannot create %d of the requested new sides",
431 		       new_sides_requested - i);
432 	}
433     }
434     /* We've handled everything we're going to, reset the counter. */
435     new_sides_requested = 0;
436 }
437 
438 /* Parse the syntax "[username][,ai][/config][@display][+advantage]".  The
439    input string spec may be modified in place. */
440 /* (should move to side.c?) */
441 void
parse_player_spec(Player * player,char * spec)442 parse_player_spec(Player *player, char *spec)
443 {
444     int commapos, slashpos, atpos, pluspos;
445 
446     if (spec != NULL && strcmp(spec, "*") != 0) {
447 	/* Extract (destructively) a trailing advantage specification. */
448 	pluspos = iindex('+', spec);
449 	if (pluspos >= 0) {
450 	    player->advantage = max(1, atoi(&(spec[pluspos + 1])));
451 	    spec[pluspos] = '\0';
452 	}
453 	/* Extract a trailing displayname if given. */
454 	atpos = iindex('@', spec);
455 	if (atpos >= 0) {
456 	    player->displayname = copy_string(spec + atpos + 1);
457 	    spec[atpos] = '\0';
458 	}
459 	/* Extract a trailing configuration name if given. */
460 	slashpos = iindex('/', spec);
461 	if (slashpos >= 0) {
462 	    player->configname = copy_string(spec + slashpos + 1);
463 	    spec[slashpos] = '\0';
464 	}
465 	/* Extract a trailing AI type if given. */
466 	commapos = iindex(',', spec);
467 	if (commapos >= 0) {
468 	    player->aitypename = copy_string(spec + commapos + 1);
469 	    spec[commapos] = '\0';
470 	}
471 	/* Just a plain old string left. */
472 	if (strlen(spec) > 0) {
473 	    if (atpos >= 0) {
474 		/* Display given separately, so this is a name. */
475 		player->name = copy_string(spec);
476 	    } else {
477 		player->displayname = copy_string(spec);
478 	    }
479 	}
480     }
481     canonicalize_player(player);
482 }
483 
484 /* Compute the leakage of technology from one side to another. */
485 
486 static void
run_tech_leakage(void)487 run_tech_leakage(void)
488 {
489     int u;
490     Side *side, *side2;
491 
492     if (any_tech_leakage < 0) {
493 	any_tech_leakage = FALSE;
494 	for_all_unit_types(u) {
495 	    if (u_tech_leakage(u) > 0) {
496 		any_tech_leakage = TRUE;
497 		break;
498 	    }
499 	}
500 	Dprintf("Any tech leakage: %d\n", any_tech_leakage);
501     }
502     if (!any_tech_leakage)
503       return;
504     Dprintf("Running tech leakage\n");
505     for_all_sides(side) {
506 	for_all_sides(side2) {
507 	    if (side != side2 /* (should) and some contact between sides */) {
508 		for_all_unit_types(u) {
509 		    if (side->tech[u] < side2->tech[u]
510 			&& u_tech_leakage(u) > 0) {
511 			side->tech[u] += prob_fraction(u_tech_leakage(u));
512 		    }
513 		}
514 	    }
515 	}
516     }
517 }
518 
519 /* Remember each side's tech levels before it does any develop actions
520    during the turn.  This can be used to keep tech level from going up too
521    fast if the player has lots of units doing development. */
522 
523 static void
cache_init_tech_levels(void)524 cache_init_tech_levels(void)
525 {
526     int u;
527     Side *side;
528 
529     if (using_tech_levels()) {
530 	for_all_sides(side) {
531 	    for_all_unit_types(u) {
532 		side->inittech[u] = side->tech[u];
533 	    }
534 	}
535     }
536 }
537 
538 /* Reduce some units' construction tooling randomly. */
539 
540 static void
run_tooling_attrition(void)541 run_tooling_attrition(void)
542 {
543     int u, u2, att;
544     Unit *unit;
545 
546     /* Test whether tooling attrition is ever possible. */
547     if (any_tooling_attrition < 0) {
548 	any_tooling_attrition = FALSE;
549 	for_all_unit_types(u) {
550 	    for_all_unit_types(u2) {
551 		if (uu_tp_attrition(u, u2) > 0) {
552 		    any_tooling_attrition = TRUE;
553 		    break;
554 		}
555 	    }
556 	    if (any_tooling_attrition)
557 	      break;
558 	}
559 	Dprintf("Any tooling attrition: %d\n", any_tooling_attrition);
560     }
561     if (!any_tooling_attrition)
562       return;
563     for_all_units(unit) {
564 	if (is_active(unit) && unit->tooling != NULL) {
565 	    for_all_unit_types(u2) {
566 		att = uu_tp_attrition(unit->type, u2);
567 		if (att > 0) {
568 		    unit->tooling[u2] -= prob_fraction(att);
569 		}
570 		if (unit->tooling[u2] < 0) unit->tooling[u2] = 0;
571 	    }
572 	}
573     }
574 }
575 
576 /* Reduce some incomplete units' cp. */
577 
578 static void
run_cp_attrition(void)579 run_cp_attrition(void)
580 {
581     int u, att;
582     Unit *unit;
583 
584     /* Test whether tooling attrition is ever possible. */
585     if (any_cp_attrition < 0) {
586 	any_cp_attrition = FALSE;
587 	for_all_unit_types(u) {
588 	    if (u_cp_attrition(u) > 0) {
589 		any_cp_attrition = TRUE;
590 		break;
591 	    }
592 	}
593 	Dprintf("Any cp attrition: %d\n", any_cp_attrition);
594     }
595     if (!any_cp_attrition)
596       return;
597     Dprintf("Running cp attrition\n");
598     for_all_units(unit) {
599 	if (alive(unit) && !completed(unit)) {
600 	    att = u_cp_attrition(unit->type);
601 	    if (att > 0 && xrandom(10000) < att) {
602 		--(unit->cp);
603 		if (unit->cp <= 0) {
604 		    kill_unit(unit, -1 /* for now */);
605 		}
606 	    }
607 	}
608     }
609 }
610 
611 /* At the beginning of a turn, there are no units in reserve. */
612 
613 static void
reset_all_reserves(void)614 reset_all_reserves(void)
615 {
616     Unit *unit;
617 
618     for_all_units(unit) {
619 	if (unit->plan != NULL) {
620 	    unit->plan->reserve = FALSE;
621 	    unit->plan->delayed = FALSE;
622 	}
623 	unit->researchdone = FALSE;
624     }
625 }
626 
627 /* Record a checkpoint, which is just a saved game, saved
628    automatically every n turns.  The code is slightly complicated
629    by our desire to ensure successful saving before removing
630    the previous checkpoint.  Note also that interfaces are not
631    required to incorporate the turn number into the result of
632    checkpoint_filename. */
633 
634 static void
save_checkpoint(int curturn)635 save_checkpoint(int curturn)
636 {
637     char *checkfname, *checkname;
638 
639     if (want_checkpoints
640     	&& checkpoint_interval > 0
641     	&& curturn % checkpoint_interval == 0) {
642 	checkfname = checkpoint_filename(curturn);
643 	checkname = copy_string(find_name(checkfname));
644 	save_game(checkname);
645 	if (last_checkpoint_filename == NULL)
646 	  last_checkpoint_filename = (char *)xmalloc(BUFSIZE);
647 	if (strcmp(checkfname, last_checkpoint_filename) != 0)
648 	  remove_file(last_checkpoint_filename);
649 	strcpy(last_checkpoint_filename, checkfname);
650 	Dprintf("Saved checkpoint %s\n", checkfname);
651     }
652 }
653 
654 /* Compute moves and actions for all the units at once, put everybody that
655    can do anything into a list. */
656 
657 static void
compute_moves(void)658 compute_moves(void)
659 {
660     int curturn = g_turn();
661     Unit *unit;
662     Side *side;
663 
664     for_all_sides(side) {
665 	side->numacting = 0;
666 	side->numfinished = 0;
667 	for_all_side_units(side, unit) {
668 	    /* If (can_be_actor(unit) XOR unit->act), then reconcile the
669                difference. These situations occur because some units
670                are only actors under special circumstances. */
671             if ((can_be_actor(unit) && !(unit->act))
672                 || (!can_be_actor(unit) && unit->act)) {
673 		init_unit_actorstate(unit, TRUE);
674 		/* Attempt to preserve existing plan. */
675 		if (!(unit->plan))
676 		  init_unit_plan(unit);
677 	    }
678 	    if (unit->act) {
679 		/* Unit acp is set to -1 to indicate uninitialization,
680 		   but acp is computed by adding to the previous acp,
681 		   so when starting a new game (as opposed to
682 		   restoring an old one), acp should be inited to
683 		   zero.  (This could maybe be done better.) */
684 		if (curturn == 1)
685 		  unit->act->acp = 0;
686 		set_unit_acp_for_turn(unit);
687 		update_unit_acp_display(side, unit, FALSE);
688 	    }
689 	}
690     }
691 }
692 
693 /* Compute the maximum amount of new ACP an unit can gain in a turn, all things
694    considered, if located in its present cell. */
695 
696 int
new_acp_for_turn(Unit * unit)697 new_acp_for_turn(Unit *unit)
698 {
699     assert_error(unit, "Tried to access a null unit.");
700     return new_acp_for_turn_if_at(unit, unit->x, unit->y);
701 }
702 
703 /* Compute the maximum amount of new ACP an unit can gain in a turn, all things
704    considered, if located in any legitimate cell. */
705 
706 int
new_acp_for_turn_if_at(Unit * unit,int x,int y)707 new_acp_for_turn_if_at(Unit *unit, int x, int y)
708 {
709     int u = NONUTYPE, t = NONTTYPE, acp = -1;
710     int err = 0, mor = 0, moreff = 0, temp = 0, tempeff = 0;
711     Unit *occ = NULL;
712 
713     /* Sanity checks. */
714     assert_error(unit, "Tried to access a null unit.");
715     /* Units still under construction or off-area can't do anything. */
716     if (!completed(unit) || !inside_area(x, y)) {
717 	return 0;
718     }
719     u = unit->type;
720     /* First compute how many action points are available. */
721     /* Start with basic acp, normal or damaged as appropriate. */
722     if (u_acp_damage_effect(u) != lispnil
723 	&& unit->hp < (u_hp_max(u) / u_parts(u))) {
724 	acp = damaged_acp(unit, u_acp_damage_effect(u));
725     } else {
726 	acp = u_acp(u);
727     }
728     /** Additive/subtractive effects. **/
729     /* Occupants */
730     for_all_occupants(unit, occ) {
731 	if (is_active(occ))
732 	  acp += uu_occ_adds_acp(u, occ->type);
733     }
734     /* Night Time */
735     if (night_at(x, y)) {
736     	/* (should account for unit being on a road at night, etc) */
737 	t = terrain_at(x, y);
738     	acp += ut_night_adds_acp(u, t);
739     }
740     /* Shortcircuit the multiplicative effects if they would be useless. */
741     if (acp <= 0)
742       return 0;
743     /** Multiplicative effects. **/
744     /* Occupants */
745     for_all_occupants(unit, occ) {
746 	if (is_active(occ))
747 	  acp = (acp * uu_occ_multiplies_acp(u, occ->type)) / 100;
748     }
749     /* Night Time */
750     if (night_at(x, y)) {
751     	/* (should account for unit being on a road at night, etc) */
752 	t = terrain_at(x, y);
753     	acp = (acp * ut_night_multiplies_acp(u, t)) / 100;
754     }
755     /* Morale */
756     if (u_acp_morale_effect(u) != lispnil) {
757 	mor = unit->morale;
758 	err = interpolate_in_list(mor, u_acp_morale_effect(u), &moreff);
759 	if (err == 0) {
760 	    acp = (acp * moreff) / 100;
761 	} else {
762 	    run_warning("Morale %d out of bounds for acp-morale-effect", mor);
763 	}
764     }
765     /* (TODO: Should add an ACP experience effect.) */
766     /* Temperature */
767     if (temperatures_defined() && u_acp_temp_effect(u) != lispnil) {
768 	temp = temperature_at(x, y);
769 	err = interpolate_in_list(temp, u_acp_temp_effect(u), &tempeff);
770 	if (err == 0) {
771 	    acp = (acp * tempeff) / 100;
772 	} else {
773 	    run_warning(
774 "Temperature %d out of bounds for acp-temperature-effect", temp);
775 	}
776     }
777     /* Season */
778     if (u_acp_season_effect(u) != lispnil) {
779     	acp = (acp * season_effect(u)) / 100;
780     }
781     /* Clip to upper and lower acp-per-turn limits. */
782     acp = max(acp, u_acp_turn_min(u));
783     if (u_acp_turn_max(u) >= 0)
784       acp = min(acp, u_acp_turn_max(u));
785     return acp;
786 }
787 
788 /* Compute the maximum amount of ACP an unit can have for a turn, all things
789    considered, if in its present location. */
790 
791 int
total_acp_for_turn(Unit * unit)792 total_acp_for_turn(Unit *unit)
793 {
794     int newacp = -1, turnacp = -1, minacp = -1, maxacp = -1;
795     int u = NONUTYPE;
796 
797     /* Sanity checks. */
798     assert_error(unit, "Tried to access a null unit.");
799     if (!(unit->act))
800       return 0;
801     u = unit->type;
802     /* Compute the new ACP total. */
803     newacp = new_acp_for_turn(unit);
804     turnacp = unit->act->acp + newacp;
805     /* Clip the accumulated ACP to its limits. */
806     minacp = u_acp_min(u);
807     turnacp = max(turnacp, minacp);
808     maxacp = ((u_acp_max(u) < 0) ? newacp : u_acp_max(u));
809     turnacp = min(turnacp, maxacp);
810     /* Return final value. */
811     return turnacp;
812 }
813 
814 /* Set the action points available to the unit this turn. */
815 
816 void
set_unit_acp_for_turn(Unit * unit)817 set_unit_acp_for_turn(Unit *unit)
818 {
819     /* Sanity checks. */
820     assert_error(unit, "Tried to change the ACP of a null unit.");
821     /* Units still under construction or off-area can't do anything. */
822     if (!completed(unit) || !inside_area(unit->x, unit->y)) {
823 	unit->act->initacp = unit->act->acp = 0;
824 	return;
825     }
826     /* Get the total ACP for the turn. */
827     unit->act->acp = unit->act->initacp = total_acp_for_turn(unit);
828     /* Zero the counts of what actually got done. */
829     unit->act->actualmoves = 0;
830 }
831 
832 /* Compute and return the acp of a damaged unit, using a list of (hp
833    acp) pairs and interpolating between them. */
834 
835 int
damaged_acp(Unit * unit,Obj * effect)836 damaged_acp(Unit *unit, Obj *effect)
837 {
838     int u, err, rslt;
839 
840     u = unit->type;
841     err = interpolate_in_list_ext(unit->hp, effect, 0, 0, 0, 0, u_hp(u),
842 				  u_acp(u), &rslt);
843     if (err != 0) {
844 	run_warning("cannot get damaged acp for %s at hp %d, using %d",
845 		    u_type_name(u), u_acp(u));
846 	rslt = u_acp(u);
847     }
848     return rslt;
849 }
850 
851 /* Compute the numeric "year part" and the textual "season name". */
852 
853 static void
compute_season(void)854 compute_season(void)
855 {
856     Obj *names, *rest, *elt;
857 
858     curseasonname = NULL;
859     if (world.yearlength > 1) {
860 	curyearpart = (g_turn() + g_initial_year_part()) % world.yearlength;
861 	/* Determine the name of the season, if defined. */
862 	names = g_season_names();
863 	if (names != NULL && names != lispnil && consp(names)) {
864 	    for_all_list(names, rest) {
865 		elt = car(rest);
866 		if (consp(elt)
867 		    && numberp(car(elt))
868 		    && numberp(cadr(elt))
869 		    && between(c_number(car(elt)),
870 			       curyearpart,
871 			       c_number(cadr(elt)))
872 		    && stringp(car(cddr(elt))))
873 		  curseasonname = c_string(car(cddr(elt)));
874 	    }
875 	}
876     } else {
877 	curyearpart = 0;
878     }
879     /* Update the preformatted date/season string. */
880     strcpy(curdatestr, absolute_date_string(g_turn()));
881     if (curseasonname != NULL) {
882 	strcat(curdatestr, " (");
883 	strcat(curdatestr, curseasonname);
884 	strcat(curdatestr, ")");
885     }
886     /* Even though this has nothing to do with seasons, this is
887        when the curdatestr is being updated. */
888     if (area_lighting >= 0) {
889 	strcat(curdatestr, " (");
890 	strcat(curdatestr,
891 	       (area_lighting == 2 ? "day" :
892 		(area_lighting == 1 ? "twilight" : "night")));
893 	strcat(curdatestr, ")");
894     }
895 }
896 
897 static int
season_effect(int u)898 season_effect(int u)
899 {
900     int err, rslt;
901 
902     if (curyearpart < 0)
903       compute_season();
904     err = interpolate_in_list(curyearpart, u_acp_season_effect(u), &rslt);
905     if (err != 0) {
906 	rslt = 100;
907     }
908     return rslt;
909 }
910 
911 #if 0
912 
913 /* See how any agreements' terms are holding up. */
914 
915 static void
916 test_agreements(void)
917 {
918     Agreement *ag;
919 
920     for_all_agreements(ag) {
921 	if (ag->state == in_force) {
922 		/* what? */
923 	}
924     }
925 }
926 
927 #endif
928 
929 /* Compute lighting-related data. */
930 
931 static void
compute_sun(void)932 compute_sun(void)
933 {
934     int curtime, highest, y = 0;
935 
936     switch (world.daylength) {
937       /* Sun is at fixed position. */
938       case 0:
939 	daynight = TRUE;
940 	sunx = area.sunx;  suny = area.suny;
941 	break;
942       /* 1 turn == 1 day; no sun effects */
943       case 1:
944       	daynight = FALSE;
945 	break;
946       /* n turns == 1 day */
947       default:
948 	daynight = TRUE;
949 	/* If world has a appropriate circumference, the sun moves over
950 	   it at a regular pace. */
951 	if (world.circumference >= area.width) {
952 	    lastsunx = sunx;  lastsuny = suny;
953 	    curtime = ((g_turn() * 100 + g_initial_day_part())
954 		       % (world.daylength * 100));
955 	    /* Calculate the sun's x position. */
956 	    sunx = ((curtime * world.circumference) / (world.daylength * 100)
957 		    + area.sunx);
958 	    sunx %= world.circumference;
959 	}
960 	break;
961     }
962     switch (world.yearlength) {
963       /* Sun is at fixed y position. */
964       case 0: case 1:
965 	suny = area.suny;
966 	break;
967       /* n > 1 turns == 1 year */
968       default:
969 	lastsuny = suny;
970 	/* Find the highest latitude that direct sunlight can reach.
971 	    Note that if axial tilt is negative, then it is equivalent to
972 	    starting from the autumnal rather than the vernal equinox. */
973 	highest = (world.axial_tilt * (world.circumference / 4)) / 90;
974 	/* Approximate the y position of direct sunlight. */
975 	/* Find position in terms of year part. */
976 	y = g_turn() + g_initial_year_part();
977 	if (world.axial_tilt < 0)
978 	  y += (world.yearlength / 2);
979 	y %= world.yearlength;
980 	/* Descending node. */
981 	if ((y > ((1 * world.yearlength) / 4))
982 	    && (y <= ((3 * world.yearlength) / 4))) {
983 	    highest = -highest;
984 	    y -= (world.yearlength / 4);
985 	}
986 	/* Ascending node. */
987 	else
988 	  y += (world.yearlength / 4);
989 	y %= world.yearlength;
990 	/* Vertical position of direct sunlight over map. */
991 	suny = -highest + ((4 * highest * y) / world.yearlength);
992 	/* Adjust coords for area latitude. */
993 	suny -= area.latitude;
994 	break;
995     }
996     if (daynight) {
997 	Dprintf("Sun is now at %d,%d\n", sunx, suny);
998     }
999 }
1000 
1001 /* Compute the position of the sun for this turn. */
1002 
1003 static void
run_sun(void)1004 run_sun(void)
1005 {
1006     int x, y, oldlighting, anychange = FALSE, anyvariation = FALSE;
1007     Side *side;
1008 
1009     compute_sun();
1010     if (world.daylength <= 1 || world.circumference < area.width)
1011       return;
1012     oldlighting = area_lighting;
1013     area_lighting = -1;
1014     /* Find a cell whose lighting has changed; if so, update the
1015        whole area at once. */
1016     for_all_cells(x, y) {
1017 	if (area_lighting < 0)
1018 	  area_lighting = lighting(x, y, sunx, suny);
1019 	if (!anychange
1020 	    && (lighting(x, y, sunx, suny)
1021 		!= lighting(x, y, lastsunx, lastsuny))) {
1022 	    /* Night may impair units' vision, so redo coverage calcs. Lots of
1023 	    cell updates get triggered here but since we are going to redraw all
1024 	    maps before any unit can act we suppress them all. */
1025 	    suppress_update_cell_display = TRUE;
1026 	    really_reset_coverage();
1027 	    suppress_update_cell_display = FALSE;
1028 	    for_all_sides(side) {
1029 		update_area_display(side);
1030 	    }
1031 	    /* Don't do this code again. */
1032 	    anychange = TRUE;
1033 	}
1034 	/* If not all cells have the same lighting this turn, reset
1035 	   the area_lighting value. */
1036 	if (!anyvariation
1037 	    && lighting(x, y, sunx, suny) != area_lighting) {
1038 	    area_lighting = -1;
1039 	    anyvariation = TRUE;
1040 	}
1041     }
1042     /* Ensure that any new overall lighting value gets reflected on
1043        the screen. */
1044     if (area_lighting >= 0) {
1045 	compute_season();
1046 	for_all_sides(side) {
1047 	    update_turn_display(side, TRUE);
1048 	}
1049 	/* Announce changes in area lighting. */
1050 	if (area_lighting != oldlighting) {
1051 	    switch (area_lighting) {
1052 	      case 0:
1053 		notify_all("Night has fallen.");
1054 		break;
1055 	      case 1:
1056 		notify_all("Twilight.");
1057 		break;
1058 	      case 2:
1059 		notify_all("The sun is up.");
1060 		break;
1061 	    }
1062 	}
1063     }
1064 }
1065 
1066 static int num_key_points;
1067 
1068 struct a_key_point {
1069     int x, y;
1070     int temp;
1071 } *key_points;
1072 
1073 static void calc_key_point_temps(int yearpart);
1074 static int interpolate_temperature(int x, int y);
1075 
1076 static void
calc_key_point_temps(int yearpart)1077 calc_key_point_temps(int yearpart)
1078 {
1079     int i, err, rslt;
1080     Obj *lis, *item, *loc;
1081 
1082     num_key_points = length(area.temp_year);
1083     if (num_key_points > 0 && key_points == NULL) {
1084 	key_points =
1085 	  (struct a_key_point *) xmalloc(num_key_points * sizeof(struct a_key_point));
1086     }
1087     i = 0;
1088     for_all_list(area.temp_year, lis) {
1089 	item = car(lis);
1090 	loc = car(item);
1091 	if (consp(loc)) {
1092 	    key_points[i].x = c_number(car(loc));
1093 	    key_points[i].y = c_number(cadr(loc));
1094 	}
1095 	err = interpolate_in_list(yearpart, cdr(item), &rslt);
1096 	if (err != 0) {
1097 	    run_warning("Year part %d not within range of temp_year list",
1098 			yearpart);
1099 	    rslt = 0;
1100 	}
1101 	key_points[i].temp = rslt;
1102 	++i;
1103     }
1104 }
1105 
1106 #if 1
1107 static int
interpolate_temperature(int x,int y)1108 interpolate_temperature(int x, int y)
1109 {
1110     int dbest, dnextbest, tbest, tnextbest, i, besti, nextbesti, d;
1111 
1112     if (num_key_points == 1)
1113       return key_points[0].temp;
1114     /* Find the closest and next-closest key points. */
1115     besti = 0;
1116     dbest = distance(x, y, key_points[besti].x, key_points[besti].y);
1117     nextbesti = -1;
1118     for (i = 1; i < num_key_points; ++i) {
1119 	d = distance(x, y, key_points[i].x, key_points[i].y);
1120 	if (d < dbest) {
1121 	    nextbesti = besti;
1122 	    dnextbest = dbest;
1123 	    besti = i;
1124 	    dbest = d;
1125 	} else if (nextbesti < 0 || d < dnextbest) {
1126 	    nextbesti = i;
1127 	    dnextbest = d;
1128 	}
1129     }
1130     tbest = key_points[besti].temp;
1131     tnextbest = key_points[nextbesti].temp;
1132     return ((tbest * dnextbest + tnextbest * dbest) / (dnextbest + dbest));
1133 }
1134 #endif
1135 
1136 #if 0  /* experimental but losing */
1137 static int
1138 interpolate_temperature(int x, int y)
1139 {
1140     int dbests[3], tbests[3], bests[3], i, j, num, dist;
1141 
1142     if (num_key_points < 3)
1143       return key_points[0].temp;
1144     /* Find the closest and next-closest key points. */
1145     bests[0] = 0;
1146     dbests[0] = distance(x, y, key_points[0].x, key_points[0].y);
1147     num = 1;
1148     for (i = 1; i < num_key_points; ++i) {
1149 	dist = distance(x, y, key_points[i].x, key_points[i].y);
1150 	for (j = 0; j < num; ++j) {
1151 	    if (dist < dbests[j]) {
1152 		dbests[j] = dist;
1153 		bests[j] = i;
1154 		break;
1155 	    }
1156 	}
1157 	if (j == num && num < 3) {
1158 	    dbests[j] = dist;
1159 	    bests[j] = i;
1160 	    ++num;
1161 	}
1162     }
1163     for (j = 0; j < num; ++j) {
1164 	tbests[j] = key_points[bests[j]].temp;
1165     }
1166     {
1167     int x21, y21, z21, x31, y31, z31, a, b, c, d, rslt;
1168     x21 = key_points[bests[1]].x - key_points[bests[0]].x;
1169     y21 = key_points[bests[1]].y - key_points[bests[0]].y;
1170     z21 = tbests[1] - tbests[0];
1171     x31 = key_points[bests[2]].x - key_points[bests[0]].x;
1172     y31 = key_points[bests[2]].y - key_points[bests[0]].y;
1173     z31 = tbests[2] - tbests[0];
1174     a = y21 * z31 - z21 * y31;
1175     b = z21 * x31 - x21 * z31;
1176     c = x21 * y31 - y21 * x31;
1177     d = - (key_points[bests[0]].x * a + key_points[bests[0]].y * b + tbests[0] * c);
1178     if (c == 0)
1179       return -99;
1180     rslt = - (a * x + b * y + d) / c;
1181     return rslt;
1182     }
1183 }
1184 #endif
1185 
1186 /* Compute environment changes. */
1187 
1188 static void
run_environment(void)1189 run_environment(void)
1190 {
1191     int yrlen = world.yearlength, x, y, dir, t, celltemp, sum;
1192     int anychanges = FALSE;
1193 
1194     if (mintemp == maxtemp && !any_wind_variation_in_layer && !any_clouds)
1195       return;
1196     if (any_annual_temp_change < 0) {
1197 	any_annual_temp_change = FALSE;
1198 	if (yrlen > 0 && area.temp_year != lispnil) {
1199 	    any_annual_temp_change = TRUE;
1200 	}
1201     }
1202     if (any_annual_temp_change) {
1203 	calc_key_point_temps(curyearpart);
1204     }
1205     /* The tmp1 layer will record where any weather changes occur. */
1206     for_all_cells(x, y)
1207       set_tmp1_at(x, y, 0);
1208     if (mintemp != maxtemp /* and any temperature changes */) {
1209 	/* Compute the average temperature at each point in the world. */
1210 	for_all_cells(x, y) {
1211 	    /* Use the tmp2 layer to cache the previous value of the
1212                temperature. */
1213 	    set_tmp2_at(x, y, temperature_at(x, y));
1214 	    t = terrain_at(x, y);
1215 	    if (any_annual_temp_change)
1216 	      celltemp = interpolate_temperature(x, y);
1217 	    else
1218 	      celltemp = t_temp_avg(t);
1219 	    /* Add in a random variation if specified. */
1220 	    if (t_temp_variability(t) > 0) {
1221 		celltemp += (xrandom(t_temp_variability(t))
1222 			     - t_temp_variability(t)/2);
1223 	    }
1224 	    /* Higher elevations can be much colder. */
1225 	    /* (In this pos, will influence lowlands via moderation -
1226 	       realistic?) */
1227 	    if (elevations_defined()
1228 		&& g_temp_floor_elev() != 0
1229 		&& elev_at(x, y) < g_temp_floor_elev()) {
1230 		celltemp -=
1231 		    ((celltemp - g_temp_floor()) * elev_at(x, y))
1232 		    / g_temp_floor_elev();
1233 	    }
1234 	    /* Clip to terrain type's limits. */
1235 	    if (celltemp < t_temp_min(t))
1236 	      celltemp = t_temp_min(t);
1237 	    if (celltemp > t_temp_max(t))
1238 	      celltemp = t_temp_max(t);
1239 	    /* Record the (unmoderated) temperature of the cell. */
1240 	    set_temperature_at(x, y, celltemp);
1241 	}
1242 	/* Sometimes the scale of the world is such that neighboring cells
1243 	   influence each other's temperatures. */
1244 	if (g_temp_mod_range() > 0) {
1245 	    /* only doing a range of 1... */
1246 	    for_all_interior_cells(x, y) {
1247 		sum = temperature_at(x, y);
1248 		for_all_directions(dir)
1249 		  sum += temperature_at(x+dirx[dir], y+diry[dir]);
1250 		set_tmp3_at(x, y, sum / (NUMDIRS + 1));
1251 	    }
1252 	    for_all_interior_cells(x, y) {
1253 		celltemp = tmp3_at(x, y);
1254 		t = terrain_at(x, y);
1255 		/* Clip to terrain type's limits. */
1256 		if (celltemp < t_temp_min(t))
1257 		  celltemp = t_temp_min(t);
1258 		if (celltemp > t_temp_max(t))
1259 		  celltemp = t_temp_max(t);
1260 		set_temperature_at(x, y, celltemp);
1261 	    }
1262 	}
1263 	/* Set a changed bit at any changed cells. */
1264  	for_all_cells(x, y) {
1265 	    if (temperature_at(x, y) != tmp2_at(x, y))
1266 	      set_tmp1_at(x, y, 1);
1267 	    anychanges = TRUE;
1268 	}
1269 	if (numcoattypes > 0) {
1270 	    /* (should make more generic) */
1271 	    for_all_terrain_types(t) {
1272 		if (t_subtype(t) == coatingsubtype) {
1273 		    allocate_area_aux_terrain(t);
1274 		}
1275 	    }
1276 	    for_all_cells(x, y) {
1277 		for_all_terrain_types(t) {
1278 		    if (strcmp(t_type_name(t), "snow") == 0) {
1279 			int olddepth = aux_terrain_at(x, y, t), newdepth;
1280 			if (temperature_at(x, y) <= 3) {
1281 			    newdepth = 1;
1282 			} else {
1283 			    newdepth = 0;
1284 			}
1285 			if (newdepth > tt_coat_max(t, terrain_at(x, y)))
1286 			  newdepth = tt_coat_max(t, terrain_at(x, y));
1287 			if (newdepth < tt_coat_min(t, terrain_at(x, y)))
1288 			  newdepth = tt_coat_min(t, terrain_at(x, y));
1289 			if (newdepth != olddepth) {
1290 			    set_aux_terrain_at(x, y, t, newdepth);
1291 			    set_tmp1_at(x, y, 2);
1292 			    anychanges = TRUE;
1293 			}
1294 		    } else if (strcmp(t_type_name(t), "mud") == 0) {
1295 			int olddepth = aux_terrain_at(x, y, t), newdepth;
1296 			if (between(4, temperature_at(x, y), 9)) {
1297 			    newdepth = 1;
1298 			} else {
1299 			    newdepth = 0;
1300 			}
1301 			if (newdepth > tt_coat_max(t, terrain_at(x, y)))
1302 			  newdepth = tt_coat_max(t, terrain_at(x, y));
1303 			if (newdepth < tt_coat_min(t, terrain_at(x, y)))
1304 			  newdepth = tt_coat_min(t, terrain_at(x, y));
1305 			if (newdepth != olddepth) {
1306 			    set_aux_terrain_at(x, y, t, newdepth);
1307 			    set_tmp1_at(x, y, 2);
1308 			    anychanges = TRUE;
1309 			}
1310 		    }
1311 		}
1312 	    }
1313 	}
1314     }
1315     /* Use the tmp2 layer to cache the previous value of clouds. */
1316     if (any_clouds /* and any cloud changes */) {
1317 	/* Save the previous state. */
1318 	for_all_interior_cells(x, y) {
1319 	    set_tmp2_at(x, y, raw_cloud_at(x, y));
1320 	}
1321 	/* Do completely random changes to clouds. */
1322 	if (1 /* any random changes */) {
1323 	    for_all_cells(x, y) {
1324 		int cloud = raw_cloud_at(x, y), newcloud;
1325 		int t = terrain_at(x, y);
1326 		int anychange;
1327 
1328 		anychange = FALSE;
1329 		if (probability(10)) {
1330 		    newcloud = cloud + (flip_coin() ? 1 : -1);
1331 		    newcloud = max(newcloud, t_clouds_min(t));
1332 		    newcloud = min(newcloud, t_clouds_max(t));
1333 		    if (newcloud != cloud) {
1334 			cloud = newcloud;
1335 			anychange = TRUE;
1336 		    }
1337 		}
1338 		if (anychange) {
1339 		    set_raw_cloud_at(x, y, cloud);
1340 		}
1341 	    }
1342 	}
1343 	/* Let winds move clouds around. */
1344 	if (winds_defined() /* and wind affects clouds */) {
1345 	    int x1, y1, winddir, sum, count, newcloud, t, raw;
1346 
1347 	    for_all_cells(x, y) {
1348 		/* Existing cloud accounts for bulk of cloud present. */
1349 		sum = 6 * 100 * raw_cloud_at(x, y);
1350 		count = 6;
1351 		for_all_directions(dir) {
1352 		    if (point_in_dir(x, y, dir, &x1, &y1)) {
1353 			if (wind_force_at(x1, y1) > 0) {
1354 			    winddir = wind_dir_at(x1, y1);
1355 			    if (winddir == opposite_dir(dir)) {
1356 				sum += 100 * raw_cloud_at(x1, y1);
1357 				++count;
1358 			    }
1359 			}
1360 		    }
1361 		}
1362 		raw = sum / count;
1363 		newcloud = raw / 100;
1364 		/* Round off the results.  Otherwise, all clouds will gradually
1365 		   disappear as the effect of truncation accumulates. */
1366 		if (raw % 100 > 50)
1367 		    ++newcloud;
1368 		t = terrain_at(x, y);
1369 		newcloud = max(newcloud, t_clouds_min(t));
1370 		newcloud = min(newcloud, t_clouds_max(t));
1371 		set_tmp3_at(x, y, newcloud);
1372 	    }
1373 	    /* Copy over the buffered-up changes. */
1374 	    for_all_interior_cells(x, y) {
1375 		set_raw_cloud_at(x, y, tmp3_at(x, y));
1376 	    }
1377 	}
1378 	/* Set a changed bit at any changed cells. */
1379 	for_all_cells(x, y) {
1380 	    if (raw_cloud_at(x, y) != tmp2_at(x, y))
1381 	      set_tmp1_at(x, y, 1);
1382 	    anychanges = TRUE;
1383 	}
1384     }
1385     /* Do wind changes. */
1386     /* Use tmp tmp2 layer to cache old values for the wind. */
1387     if (any_wind_variation_in_layer) {
1388 	/* Save the previous state. */
1389 	for_all_interior_cells(x, y) {
1390 	    set_tmp2_at(x, y, raw_wind_at(x, y));
1391 	}
1392 	vary_winds();
1393 	if (g_wind_mix_range() > 0)
1394 	  mix_winds();
1395 	/* Set a changed bit at any changed cells. */
1396 	for_all_cells(x, y) {
1397 	    if (raw_wind_at(x, y) != tmp2_at(x, y))
1398 	      set_tmp1_at(x, y, 1);
1399 	    anychanges = TRUE;
1400 	}
1401     }
1402     /* See if any displays should change and report if so. */
1403     if (anychanges) {
1404 
1405 #if 1		/* Just redraw the map if there were any changes. */
1406 
1407     	Side *side;
1408 
1409     	for_all_sides(side) {
1410     		update_area_display(side);
1411 	}
1412 
1413 #else	/* This took forever to complete. No point in updating
1414 		cells one by one since run_environment changes the
1415 		whole map if it changes anything at all. */
1416 
1417 	for_all_cells(x, y) {
1418 	    /* A value of 2 means terrain changed, and so we need to
1419 	       do a full update of the cell. */
1420 	    if (tmp1_at(x, y) == 2) {
1421 		Side *side;
1422 		for_all_sides(side) {
1423 		    update_cell_display(side, x, y,
1424 					UPDATE_ALWAYS | UPDATE_ADJ);
1425 		}
1426 	    } else if (tmp1_at(x, y) == 1) {
1427 		/* Just update if the side is displaying any weather
1428 		   data. */
1429 		all_see_cell_weather(x, y);
1430 	    }
1431 	}
1432 
1433 #endif
1434 
1435     }
1436 }
1437 
1438 static void
vary_winds(void)1439 vary_winds(void)
1440 {
1441     int x, y, t, wdir, wforce, newwforce, anychange;
1442 
1443     for_all_interior_cells(x, y) {
1444 	wdir = wind_dir_at(x, y);
1445 	wforce = wind_force_at(x, y);
1446 	t = terrain_at(x, y);
1447 	anychange = FALSE;
1448 	if (probability(t_wind_variability(t))) {
1449 	    wdir = (flip_coin() ? right_dir(wdir) : left_dir(wdir));
1450 	    anychange = TRUE;
1451 	}
1452 	if (probability(t_wind_force_variability(t))) {
1453 	    newwforce = wforce + (flip_coin() ? 1 : -1);
1454 	    newwforce = max(newwforce, t_wind_force_min(t));
1455 	    newwforce = min(newwforce, t_wind_force_max(t));
1456 	    if (newwforce != wforce) {
1457 		wforce = newwforce;
1458 		anychange = TRUE;
1459 	    }
1460 	}
1461 	if (anychange) {
1462 	    set_wind_at(x, y, wdir, wforce);
1463 	}
1464     }
1465 }
1466 
1467 static void
mix_winds(void)1468 mix_winds(void)
1469 {
1470     int num, i, x, y, dir, x1, y1, wdir, wforce, sumx, sumy, n, t;
1471 
1472     num = (area.width * area.height) / 6;
1473 
1474     for (i = 0; i < num; ++i) {
1475 	random_point(&x, &y);
1476 	wdir = wind_dir_at(x, y);
1477 	wforce = wind_force_at(x, y);
1478 	sumx = dirx[wdir] * wforce;  sumy = diry[wdir] * wforce;
1479 	n = 1;
1480 	for_all_directions(dir) {
1481 	    if (point_in_dir(x, y, dir, &x1, &y1)) {
1482 		wdir = wind_dir_at(x1, y1);
1483 		wforce = wind_force_at(x1, y1);
1484 		sumx += dirx[wdir] * wforce;  sumy += diry[wdir] * wforce;
1485 		++n;
1486 	    }
1487 	}
1488 	/* Over time, the rounding-down effect of division would
1489 	   causes all winds to diminish to zero.  Counteract by
1490 	   incrementing the sum. */
1491 	sumx += n - 1;  sumy += n - 1;
1492 	sumx = sumx / n;  sumy = sumy / n;
1493 	if (sumx == 0 && sumy == 0) {
1494 	    wdir = random_dir();
1495 	    wforce = 0;
1496 	} else {
1497 	    wdir = approx_dir(sumx, sumy);
1498 	    wforce = distance(0, 0, sumx, sumy);
1499 	}
1500 	t = terrain_at(x, y);
1501 	wforce = max(wforce, t_wind_force_min(t));
1502 	wforce = min(wforce, t_wind_force_max(t));
1503 	set_wind_at(x, y, wdir, wforce);
1504     }
1505 }
1506 
1507 /* Update all sides with all weather changes that have happened at
1508    the given location. */
1509 
1510 static void
all_see_cell_weather(int x,int y)1511 all_see_cell_weather(int x, int y)
1512 {
1513     int oldview, mask;
1514     Side *side;
1515 
1516     for_all_sides(side) {
1517 	mask = 0;
1518 	if (side->see_all) {
1519 	    mask = UPDATE_TEMP | UPDATE_CLOUDS | UPDATE_WINDS;
1520 	} else if (g_see_weather_always()
1521 		   ? (terrain_view(side, x, y) != UNSEEN)
1522 		   : (cover(side, x, y) > 0)) {
1523 	    if (temperatures_defined()) {
1524 		oldview = temperature_view(side, x, y);
1525 		if (oldview != temperature_at(x, y)) {
1526 		    set_temperature_view(side, x, y, temperature_at(x, y));
1527 		    mask |= UPDATE_TEMP;
1528 		}
1529 	    }
1530 	    if (clouds_defined()) {
1531 		oldview = cloud_view(side, x, y);
1532 		if (oldview != raw_cloud_at(x, y)) {
1533 		    set_cloud_view(side, x, y, raw_cloud_at(x, y));
1534 		    mask |= UPDATE_CLOUDS;
1535 		}
1536 	    }
1537 	    if (winds_defined()) {
1538 		oldview = wind_view(side, x, y);
1539 		if (oldview != raw_wind_at(x, y)) {
1540 		    set_wind_view(side, x, y, raw_wind_at(x, y));
1541 		    mask |= UPDATE_WINDS;
1542 		}
1543 	    }
1544 	}
1545 	if (mask != 0)
1546 	  update_cell_display(side, x, y, mask);
1547     }
1548 }
1549 
1550 /* Given that the spying unit is going to get info about other units at this
1551    location, figure out just what it is going to see. */
1552 
1553 static void
spy_on_location(int x,int y)1554 spy_on_location(int x, int y)
1555 {
1556     int qual;
1557     Unit *unit2, *occ;
1558 
1559     for_all_stack(x, y, unit2) {
1560 	if (unit2->side != tmpunit->side) {
1561 	    qual = uu_spy_quality(tmpunit->type, unit2->type);
1562 	    if (probability(qual)) {
1563 		/* Spy got something, report it. */
1564 		/* (should be more worked-out, dunno exactly how) */
1565 		see_exact(tmpunit->side, x, y);
1566 		for_all_occupants(unit2, occ) {
1567 		    /* (should get info about occupants?) */
1568 		}
1569 		/* Might also be able to track the unit. */
1570 		if (xrandom(10000) < uu_spy_track(tmpunit->type, unit2->type)) {
1571 		    /* (should inform side of tracking?) */
1572 		    add_side_to_set(tmpunit->side, unit2->tracking);
1573 		}
1574 	    }
1575 	}
1576     }
1577 }
1578 
1579 /* Certain kinds of units can do spying for the side they're on. */
1580 
1581 static void
run_spies(void)1582 run_spies(void)
1583 {
1584     int u, chance;
1585     Unit *unit;
1586 
1587     if (any_spying < 0) {
1588 	any_spying = FALSE;
1589 	for_all_unit_types(u) {
1590 	    if (u_spy_chance(u) > 0) {
1591 		any_spying = TRUE;
1592 		break;
1593 	    }
1594 	}
1595 	/* But spying is pointless if everybody can see everything anyway. */
1596 	if (g_see_all())
1597 	  any_spying = FALSE;
1598 	Dprintf("Any spying: %d\n", any_spying);
1599     }
1600     if (!any_spying)
1601       return;
1602     Dprintf("Running spies\n");
1603     for_all_units(unit) {
1604 	if (is_active(unit)) {
1605 	    u = unit->type;
1606 	    chance = u_spy_chance(u);
1607 	    if (chance > 0 && xrandom(10000) < chance) {
1608 		/* Spying is successful, decide how much was seen. */
1609 		tmpunit = unit;
1610 		apply_to_area(unit->x, unit->y, u_spy_range(u), spy_on_location);
1611 	    }
1612 	}
1613     }
1614 }
1615 
1616 /* Test each unit that is out in the open to see if a terrain-related
1617    accident happens to it.  Accidents can either kill the unit instantly or
1618    just damage it. */
1619 
1620 static void
run_accidents(void)1621 run_accidents(void)
1622 {
1623     int u, t, chance, hit;
1624     Unit *unit;
1625 
1626     if (any_accidents < 0) {
1627 	any_accidents = FALSE;
1628 	for_all_unit_types(u) {
1629 	    for_all_terrain_types(t) {
1630 		if (ut_accident_vanish(u, t) > 0
1631 		    || ut_accident_hit(u, t) > 0) {
1632 		    any_accidents = TRUE;
1633 		    break;
1634 		}
1635 	    }
1636 	    if (any_accidents)
1637 	      break;
1638     	}
1639     }
1640     if (!any_accidents)
1641       return;
1642     Dprintf("Running accidents\n");
1643     for_all_units(unit) {
1644 	if (in_play(unit) && unit->transport == NULL) {
1645 	    u = unit->type;
1646 	    t = terrain_at(unit->x, unit->y);
1647 	    chance = ut_accident_vanish(u, t);
1648 	    if (chance > 0 && xrandom(10000) < chance) {
1649 	    	/* Kill the unit outright. */
1650 		kill_unit(unit, H_UNIT_VANISHED);
1651 		/* (should make a hevt) */
1652 		continue;
1653 	    }
1654 	    chance = ut_accident_hit(u, t);
1655 	    if (chance > 0 && xrandom(10000) < chance) {
1656 		/* Damage the unit. */
1657 		hit = roll_dice(ut_accident_damage(u, t));
1658 		if (hit > 0) {
1659 		    unit->hp2 -= hit;
1660 		    damage_unit(unit, accident_dmg, NULL);
1661 		}
1662 	    }
1663 	}
1664     }
1665 }
1666 
1667 /* Attrition only takes out a few hp at a time, but can be deadly...
1668    Note that attrition does not affect incomplete units - use cp-attrition
1669    for those. */
1670 
1671 static void
run_attrition(void)1672 run_attrition(void)
1673 {
1674     int u, t, dmg;
1675     Unit *unit;
1676 
1677     if (any_attrition < 0) {
1678 	any_attrition = FALSE;
1679 	for_all_unit_types(u) {
1680 	    for_all_terrain_types(t) {
1681 		if (ut_attrition(u, t) > 0) {
1682 		    any_attrition = TRUE;
1683 		    break;
1684 		}
1685 	    }
1686 	    if (any_attrition)
1687 	      break;
1688     	}
1689     }
1690     if (!any_attrition)
1691       return;
1692     Dprintf("Running attrition\n");
1693     for_all_units(unit) {
1694 	if (is_active(unit)) {
1695 	    u = unit->type;
1696 	    t = terrain_at(unit->x, unit->y);
1697 	    if (ut_attrition(u, t) <= 0)
1698 	      continue;
1699 	    dmg = prob_fraction(ut_attrition(u, t));
1700 	    /* This is like hit_unit but doesn't have other effects. */
1701 	    unit->hp2 -= dmg;
1702 	    damage_unit(unit, attrition_dmg, NULL);
1703 	}
1704     }
1705 }
1706 
1707 /* Check each unit to see whether it revolts spontaneously.  While
1708    surrender is influenced by nearby units, revolt takes only the
1709    overall state of the world into account. */
1710 
1711 static void
run_revolts(void)1712 run_revolts(void)
1713 {
1714     int u;
1715     Unit *unit;
1716 
1717     if (any_revolts < 0) {
1718 	any_revolts = FALSE;
1719 	for_all_unit_types(u) {
1720 	    if (u_revolt(u) > 0 || u_revolt_opinion_min(u) > 0) {
1721 		any_revolts = TRUE;
1722 		break;
1723 	    }
1724     	}
1725     }
1726     if (!any_revolts)
1727       return;
1728     Dprintf("Running revolts\n");
1729     for_all_units(unit) {
1730 	if (in_play(unit)
1731 	    && (u_revolt(unit->type) > 0
1732 		|| (unit->opinions != NULL
1733 		    && u_revolt_opinion_min(unit->type) > 0))) {
1734 	    unit_revolt(unit, FALSE);
1735 	}
1736     }
1737 }
1738 
1739 /* Test for and run a single revolt. */
1740 
1741 static void
unit_revolt(Unit * unit,int force)1742 unit_revolt(Unit *unit, int force)
1743 {
1744     int u = unit->type, ux = unit->x, uy = unit->y, chance, lo, opin;
1745     int sideweights[MAXSIDES+1], sn2, sum, n, i, psum;
1746     Side *oldside = unit->side, *newside, *side2;
1747     Unit *unit2;
1748 
1749     chance = u_revolt(u);
1750     if (unit->opinions != NULL
1751 	&& u_opinion_min(u) < 0
1752 	&& u_revolt_opinion_min(u) > 0) {
1753 	lo = u_revolt_opinion_min(u);
1754 	opin = unit_opinion(unit, unit->side);
1755 	if (opin < 0)
1756 	  chance += ((lo - chance) * (0 - opin)) / (0 - u_opinion_min(u));
1757     }
1758     if (force || xrandom(10000) < chance) {
1759 	newside = oldside;
1760 	if (oldside != unit->origside
1761 	    && (unit->origside == indepside
1762 		|| unit->origside->ingame)
1763 	    && !trusted_side(oldside, unit->origside)
1764 	    && unit_allowed_on_side(unit, unit->origside)
1765 	    ) {
1766 	    newside = unit->origside;
1767 	} else if (unit->opinions != NULL) {
1768 	    /* Find all the non-allied sides in the game and weight
1769 	       each according to the unit's opinion of the side. */
1770 	    sum = 0;
1771 	    for_all_sides(side2) {
1772 		sn2 = side_number(side2);
1773 		sideweights[sn2] = 0;
1774 		if ((side2 == NULL || side2 == indepside || side2->ingame)
1775 		    && side2 != oldside
1776 		    && !trusted_side(oldside, side2)
1777 		    && unit_allowed_on_side(unit, side2)
1778 		    /* Don't go over to a side that doesn't even know
1779                        we're there. */
1780 		    && side_sees_image(side2, unit)
1781 		    ) {
1782 		    sideweights[sn2] =
1783 		      unit_opinion(unit, side2) + u_opinion_min(u);
1784 		}
1785 		sum += sideweights[sn2];
1786 	    }
1787 	    /* Select one of the sides. */
1788 	    if (sum > 0) {
1789 		n = xrandom(sum);
1790 		psum = 0;
1791 		for (i = 0; i <= numsides; ++i) {
1792 		    psum += sideweights[i];
1793 		    if (n <= psum) {
1794 			newside = side_n(i);
1795 			break;
1796 		    }
1797 		}
1798 	    }
1799 	} else {
1800 	    /* Find all the non-allied sides in the game and weight
1801 	       each according to the number of units of the same type
1802 	       present. */
1803 	    sum = 0;
1804 	    for_all_sides(side2) {
1805 		sn2 = side_number(side2);
1806 		sideweights[sn2] = 0;
1807 		if ((side2 == NULL || side2 == indepside || side2->ingame)
1808 		    && side2 != oldside
1809 		    && !trusted_side(oldside, side2)
1810 		    && unit_allowed_on_side(unit, side2)
1811 		    /* Don't go over to a side that doesn't even know
1812                        we're there. */
1813 		    && side_sees_image(side2, unit)
1814 		    ) {
1815 		    sideweights[sn2] = 1;
1816 		    for_all_side_units(side2, unit2) {
1817 			/* OK if not ideal to count real units, this
1818                            is just a weighting */
1819 			if (in_play(unit2) && unit2->type == unit->type)
1820 			  ++(sideweights[sn2]);
1821 		    }
1822 		}
1823 		sum += sideweights[sn2];
1824 	    }
1825 	    /* Select one of the sides. */
1826 	    if (sum > 0) {
1827 		n = xrandom(sum);
1828 		psum = 0;
1829 		for (i = 0; i <= numsides; ++i) {
1830 		    psum += sideweights[i];
1831 		    if (n <= psum) {
1832 			newside = side_n(i);
1833 			break;
1834 		    }
1835 		}
1836 	    }
1837 	}
1838 	/* Might not have been much of a revolt. */
1839 	if (newside == oldside)
1840 	  return;
1841 	/* Tell the players what happened. */
1842 	/* (should notify other players, if they're observing the unit?) */
1843 	if (newside == indepside) {
1844 	    notify(oldside, "%s revolts, becomes independent!",
1845 		   unit_handle(oldside, unit));
1846 	} else {
1847 	    notify(oldside, "%s revolts, goes over to %s!",
1848 		   unit_handle(oldside, unit), short_side_title(newside));
1849 	    notify(newside, "%s revolts, comes over to your side!",
1850 		   unit_handle(newside, unit));
1851 	}
1852 	change_unit_side(unit, newside, H_UNIT_REVOLTED, NULL);
1853 	/* (should set new opinions and maybe morale) */
1854 	/* Give the previous side a last view of the situation. */
1855 	see_exact(oldside, ux, uy);
1856 	update_cell_display(oldside, ux, uy, UPDATE_ALWAYS);
1857 	all_see_cell(ux, uy);
1858     }
1859 }
1860 
1861 /* Test whether surrenders can happen in this game. */
1862 
1863 static void
run_surrenders(void)1864 run_surrenders(void)
1865 {
1866     int u1, u2, u3, range;
1867     Unit *unit;
1868 
1869     if (any_surrenders < 0) {
1870 	any_surrenders = FALSE;
1871 	for_all_unit_types(u1) {
1872 	    for_all_unit_types(u2) {
1873 		if (uu_surrender_chance(u1, u2) > 0) {
1874 		    any_surrenders = TRUE;
1875 		    if (surrender_ranges == NULL) {
1876 			surrender_ranges =
1877 			  (short *) xmalloc(numutypes * sizeof(short));
1878 			for_all_unit_types(u3)
1879 			  surrender_ranges[u3] = -1;
1880 		    }
1881 		    range = uu_surrender_range(u1, u2);
1882 		    surrender_ranges[u1] = max(range, surrender_ranges[u1]);
1883 		}
1884     	    }
1885     	}
1886     }
1887     if (!any_surrenders)
1888       return;
1889     Dprintf("Running surrenders\n");
1890     /* For each unit, look for units nearby that might surrender to it. */
1891     for_all_units(unit) {
1892 	if (in_play(unit)
1893 	    /* For now anyway, nobody surrenders to independents. */
1894 	    && !indep(unit)) {
1895 	    unit_surrender(unit);
1896 	}
1897     }
1898 }
1899 
1900 /* Units may surrender to enemy units that are visible nearby.
1901    Independents have to be treated specially, since they don't have a
1902    view to work from.  We sort of compute the view "on the fly". */
1903 
1904 static void
unit_surrender(Unit * unit)1905 unit_surrender(Unit *unit)
1906 {
1907     int u = unit->type, dir, x1, y1, range /*, surrounded = TRUE */;
1908     Unit *unit2;
1909 
1910     range = surrender_ranges[u];
1911     if (range < 0) {
1912 	/* This unit won't surrender, nothing to do. */
1913     } else if (range > 1) {
1914 	run_warning("Surrender range of %d not supported, ignoring", range);
1915     } else {
1916 	/* Range is 0 or 1; check other units in this cell. */
1917 	for_all_stack(unit->x, unit->y, unit2) {
1918 	    if (in_play(unit2)
1919 		&& unit2->side != unit->side
1920 		&& uu_surrender_chance(u, unit2->type) > 0
1921 		&& visible_to(unit, unit2)) {
1922 		maybe_surrender_to(unit, unit2);
1923 	    }
1924 	}
1925 	/* Check on adjacent units. */
1926         if (range == 1) {
1927 	    for_all_directions(dir) {
1928 		if (interior_point_in_dir(unit->x, unit->y, dir, &x1, &y1)) {
1929 		    for_all_stack(x1, y1, unit2) {
1930 			if (in_play(unit2)
1931 			    && unit2->side != unit->side
1932 			    && uu_surrender_chance(u, unit2->type) > 0
1933 			    && visible_to(unit, unit2)) {
1934 			    maybe_surrender_to(unit, unit2);
1935 			}
1936 		    }
1937 		}
1938 	    }
1939 	}
1940     }
1941 }
1942 
1943 /* Calculate whether one unit is visible to another, even if the other
1944    is independent. */
1945 /* (should rewrite this) */
1946 int
visible_to(Unit * unit,Unit * unit2)1947 visible_to(Unit *unit, Unit *unit2)
1948 {
1949     if (g_see_all()) {
1950 	return TRUE;
1951     } else if (side_sees_unit(unit->side, unit2)) {
1952 	return TRUE;
1953     } else {
1954 	/* (should be more careful to check see-chances) */
1955     	if (distance(unit->x, unit->y, unit2->x, unit2->y)
1956 	    <= u_vision_range(unit->type))
1957     	  return TRUE;
1958     	else
1959     	  return FALSE;
1960     }
1961 }
1962 
1963 static void
maybe_surrender_to(Unit * unit,Unit * unit2)1964 maybe_surrender_to(Unit *unit, Unit *unit2)
1965 {
1966     int chance;
1967 
1968     chance = uu_surrender_chance(unit->type, unit2->type);
1969     if (xrandom(10000) < chance) {
1970 	capture_unit(unit, unit2, H_UNIT_SURRENDERED);
1971     }
1972 }
1973 
1974 /* Some types of units can become completed and grow to full size
1975    automatically when they get to a certain point. */
1976 
1977 static void
run_self_builds(void)1978 run_self_builds(void)
1979 {
1980     int u, cpper;
1981     Unit *unit;
1982 
1983     /* Precompute whether any self-building ever happens. */
1984     if (any_self_builds < 0) {
1985 	any_self_builds = FALSE;
1986 	for_all_unit_types(u) {
1987 	    if (u_cp_per_self_build(u) > 0) {
1988 		any_self_builds = TRUE;
1989 		break;
1990 	    }
1991 	}
1992 	Dprintf("Any self builds: %d\n", any_self_builds);
1993     }
1994     if (!any_self_builds)
1995       return;
1996     Dprintf("Running self builds\n");
1997     for_all_units(unit) {
1998 	u = unit->type;
1999 	if (in_play(unit)
2000 	    && !fullsized(unit)
2001 	    && (cpper = u_cp_per_self_build(u)) > 0
2002 	    && unit->cp >= u_cp_to_self_build(u)) {
2003 	    unit->cp += cpper;
2004 	    if (unit->cp > u_cp(u))
2005 	      unit->cp = u_cp(u);
2006 	    if (completed(unit)) {
2007 		make_unit_complete(unit);
2008 	    } else {
2009 	    	/* Let the player know that progress was made. */
2010 		update_unit_display(unit->side, unit, TRUE);
2011 	    }
2012 	}
2013     }
2014 }
2015 
2016 static void
run_environment_effects(void)2017 run_environment_effects(void)
2018 {
2019     int err, dmg;
2020     Unit *unit;
2021     Obj *attrition;
2022 
2023     /* Precompute whether any environment effects happen. */
2024     if (any_environment_effects < 0) {
2025 	int u;
2026 
2027 	any_environment_effects = FALSE;
2028 	for_all_unit_types(u) {
2029 	    if (u_temp_attrition(u) != lispnil) {
2030 		any_environment_effects = TRUE;
2031 		break;
2032 	    }
2033 	}
2034 	Dprintf("Any environment effects: %d\n", any_environment_effects);
2035     }
2036     if (!any_environment_effects)
2037       return;
2038     if (!temperatures_defined())
2039       return;
2040     Dprintf("Running environmental effects\n");
2041     for_all_units(unit) {
2042 	if (is_active(unit)) {
2043 	    attrition = u_temp_attrition(unit->type);
2044 	    if (attrition != lispnil
2045 		&& !(unit->transport != NULL
2046 		     && uu_temp_protect(unit->transport->type, unit->type))) {
2047 		err = interpolate_in_list(temperature_at(unit->x, unit->y), attrition, &dmg);
2048 		if (err != 0) {
2049 		    dmg = 0;
2050 		}
2051 		damage_unit_with_temperature(unit, dmg);
2052 	    }
2053 	    /* (should check for storm damage here?) */
2054 	}
2055     }
2056 }
2057 
2058 static void
damage_unit_with_temperature(Unit * unit,int dmg)2059 damage_unit_with_temperature(Unit *unit, int dmg)
2060 {
2061     int n;
2062 
2063     n = prob_fraction(dmg);
2064     if (n >= unit->hp) {
2065 	rescue_occupants(unit);
2066 	kill_unit(unit, H_UNIT_DIED_FROM_TEMPERATURE);
2067     } else if (n > 0) {
2068 	notify(unit->side, "%s loses %d HP due to the temperature",
2069 		unit_handle(unit->side, unit), n);
2070 	unit->hp -= n;
2071 	unit->hp2 -= n;
2072 	update_unit_display(unit->side, unit, TRUE);
2073     }
2074 }
2075 
2076 static void
run_people_side_changes(void)2077 run_people_side_changes(void)
2078 {
2079     int x, y, u, t;
2080     Unit *unit;
2081 
2082     /* Precompute whether any people side changes can happen. */
2083     if (any_people_side_changes < 0) {
2084 	any_people_side_changes = FALSE;
2085 	for_all_unit_types(u) {
2086 	    for_all_terrain_types(t) {
2087 		if (ut_people_surrender(u, t) > 0) {
2088 		    any_people_side_changes = TRUE;
2089 		    break;
2090 		}
2091 	    }
2092 	    if (any_people_side_changes)
2093 	      break;
2094 	}
2095 	Dprintf("Any people side changes: %d\n", any_people_side_changes);
2096     }
2097     if (!any_people_side_changes)
2098       return;
2099     if (!people_sides_defined())
2100       return;
2101     /* Precompute a per-unit-type flag. */
2102     if (any_people_surrenders == NULL) {
2103 	any_people_surrenders = (short *) xmalloc(numutypes * sizeof(short));
2104 	for_all_unit_types(u) {
2105 	    for_all_terrain_types(t) {
2106 		if (ut_people_surrender(u, t) > 0) {
2107 		    any_people_surrenders[u] = TRUE;
2108 		    break;
2109 		}
2110 	    }
2111 	}
2112     }
2113     Dprintf("Running people side changes\n");
2114     for_all_cells(x, y) {
2115 	if (unit_at(x, y) != NULL) {
2116 	    for_all_stack(x, y, unit) {
2117 		/* The people here may change sides. */
2118 	        u = unit->type;
2119 		if (any_people_surrenders[u]
2120 		    && probability(people_surrender_chance(u, x, y))) {
2121 		    change_people_side_around(x, y, u, unit->side);
2122 		}
2123 	    }
2124 	} else {
2125 	    /* Unoccupied cells might see population revert. */
2126 	    /* (this would need multiple-loyalty pops) */
2127 	}
2128     }
2129 }
2130 
2131 int
people_surrender_chance(int u,int x,int y)2132 people_surrender_chance(int u, int x, int y)
2133 {
2134     int m, chance, peop;
2135 
2136     chance = ut_people_surrender(u, terrain_at(x, y));
2137     /* Modify the basic chance according to people types, if present. */
2138     if (any_cell_materials_defined()) {
2139 	for_all_material_types(m) {
2140 	    if (m_people(m) > 0
2141 		&& cell_material_defined(m)) {
2142 		peop = material_at(x, y, m);
2143 		if (peop > 0) {
2144 		    chance = (chance * um_people_surrender(u, m)) / 100;
2145 		}
2146 	    }
2147 	}
2148     }
2149     return chance;
2150 }
2151 
2152 void
change_people_side_around(int x,int y,int u,Side * side)2153 change_people_side_around(int x, int y, int u, Side *side)
2154 {
2155     int pop = people_side_at(x, y), s = side_number(side);
2156     Side *oldside, *side2;
2157 
2158     if (pop != NOBODY
2159         && pop != s
2160         && !trusted_side(side, side_n(pop))) {
2161         oldside = side_n(pop);
2162 	set_people_side_at(x, y, s);
2163 	if (side) {
2164 	    for_all_sides(side2) {
2165 		if (side == side2 || trusted_side(side, side2)) {
2166 		    add_cover(side2, x, y, 1);
2167 		}
2168 	    }
2169 	}
2170 	update_cell_display_all_sides(x, y, UPDATE_ALWAYS | UPDATE_ADJ);
2171 	/* Previous side(s) lose free coverage. */
2172 	for_all_sides(side2) {
2173 	    if (!trusted_side(side, side2)
2174 		&& (oldside == side2 || trusted_side(oldside, side2))) {
2175 		add_cover(side2, x, y, -1);
2176 		/* Update coverage display. */
2177 		update_cell_display(side2, x, y, UPDATE_COVER);
2178 	   }
2179 	}
2180     }
2181     /* (should add ability to change adjacent cells also) */
2182 }
2183 
2184 /* See if the numbers of individuals in a cell exceeds the max, and
2185    migrate or remove so as to bring the numbers back in line. */
2186 
2187 static void
run_people_limits(void)2188 run_people_limits(void)
2189 {
2190     int m, t, x, y, num, ratio, amt, newamt;
2191 
2192     /* Precompute whether there are any people limits. */
2193     if (any_people_max < 0) {
2194 	any_people_max = FALSE;
2195 	for_all_terrain_types(t) {
2196 	    if (t_people_max(t) >= 0) {
2197 		any_people_max = TRUE;
2198 		break;
2199 	    }
2200 	}
2201 	Dprintf("Any people max: %d\n", any_people_max);
2202     }
2203     if (!any_people_max)
2204       return;
2205     if (!any_cell_materials_defined())
2206       return;
2207     Dprintf("Running people limits\n");
2208     for_all_cells(x, y) {
2209 	t = terrain_at(x, y);
2210 	if (t_people_max(t) >= 0) {
2211 	    num = num_people_at(x, y);
2212 	    if (num > t_people_max(t)) {
2213 		/* Too many people here, trim them down. */
2214 		/* Compute the ratio of limit to actual number.
2215 		   (Note that actual number is guaranteed to be nonzero.) */
2216 		ratio = (t_people_max(t) * 100) / num;
2217 		for_all_material_types(m) {
2218 		    if (m_people(m) > 0
2219 			&& cell_material_defined(m)) {
2220 			amt = material_at(x, y, m);
2221 			if (amt > 0) {
2222 			    newamt = (amt * ratio) / 100;
2223 			    set_material_at(x, y, m, newamt);
2224 			    /* (should update sides?) */
2225 			}
2226 		    }
2227 		}
2228 	    }
2229 	}
2230     }
2231 }
2232 
2233 void
update_cell_display_all_sides(int x,int y,int flags)2234 update_cell_display_all_sides(int x, int y, int flags)
2235 {
2236     Side *side;
2237 
2238     for_all_sides(side) {
2239 	/* We have no people/control view layers at the moment, so
2240 	   always update if the terrain has been seen. */
2241 	if (side->ingame && terrain_visible(side, x, y)) {
2242 	    update_cell_display(side, x, y, flags);
2243 	}
2244     }
2245 }
2246 
2247 /* See if it's time for any scheduled arrivals to appear. */
2248 
2249 static void
run_appearances(void)2250 run_appearances(void)
2251 {
2252     char abuf[BUFSIZE];
2253     int curturn, nx, ny, nw, nh, nx0, ny0, nx1, ny1, tries;
2254     int need_rescan, scan_tries;
2255     Unit *unit, *transport;
2256 
2257     /* Precompute whether any units will appear at a given time. */
2258     if (any_appearances < 0) {
2259     	any_appearances = FALSE;
2260 	for_all_units(unit) {
2261 	    if (unit->cp < 0 && unit_appear_turn(unit) >= 0) {
2262 		any_appearances = TRUE;
2263 		break;
2264 	    }
2265 	}
2266 	Dprintf("Any appearances: %d\n", any_appearances);
2267     }
2268     if (!any_appearances)
2269       return;
2270     Dprintf("Running appearances\n");
2271     curturn = g_turn();
2272     /* The unit may be blocked from appearing for some reason, such
2273        as a stacking limit, so scan the list of appearances several
2274        times. */
2275     need_rescan = TRUE;
2276     scan_tries = 5;
2277     while (need_rescan && scan_tries-- > 0) {
2278 	need_rescan = FALSE;
2279 	for_all_units(unit) {
2280 	    /* See if now time for a unit to appear. */
2281 	    if (unit->cp < 0
2282 		&& unit_appear_turn(unit) >= 0
2283 		&& unit_appear_turn(unit) <= curturn) {
2284 		/* Set the unit to its correct cp. */
2285 		unit->cp = (- unit->cp);
2286 		/* Get the base location at which it will appear. */
2287 		nx = nx0 = (- unit->prevx);  ny = ny0 = (- unit->prevy);
2288 		nw = unit_appear_var_x(unit);  nh = unit_appear_var_y(unit);
2289 		tries = ((nw >= 0 && nh >= 0) ? 100 : 1);
2290 		while (tries-- > 0) {
2291 		    if (nw >= 0 && nh >= 0
2292 			&& random_point_in_area(nx0, ny0, nw, nh, &nx1, &ny1)) {
2293 			nx = nx1;  ny = ny1;
2294 		    }
2295 		    /* Do the usual steps to place the unit. */
2296 		    /* (should add case for appearing on conn - share with patch_obj_refs code?) */
2297 		    if (inside_area(nx, ny)) {
2298 			if (unit->transport != NULL) {
2299 			    /* nothing to do?? */
2300 			} else if (type_can_occupy_cell(unit->type, nx, ny)
2301 			    && type_survives_in_cell(unit->type, nx, ny)) {
2302 			    enter_cell(unit, nx, ny);
2303 			    tries = 0;
2304 			} else {
2305 			    /* Search this cell for units to enter. */
2306 			    for_all_stack(nx, ny, transport) {
2307 			 	if (unit->side == transport->side
2308 				    && can_occupy(unit, transport)) {
2309 				    enter_transport(unit, transport);
2310 				    tries = 0;
2311 				    break;
2312 				}
2313 			    }
2314 			}
2315 		    }
2316 		}
2317 		if (inside_area(unit->x, unit->y)) {
2318 		    init_unit_actorstate(unit, FALSE);
2319 		    init_unit_plan(unit);
2320 		    /* (should use generic event notification mech? */
2321 		    destination_desc(abuf, unit->side, unit,
2322 				     unit->x, unit->y, 0);
2323 		    notify(unit->side, "%s has appeared at %s.",
2324 			   unit_handle(unit->side, unit), abuf);
2325 		} else {
2326 		    /* We've got a problem, put the unit back. */
2327 		    unit->cp = (- unit->cp);
2328 		    /* Go around again, perhaps a plausible transport
2329 		       appeared during this pass. */
2330 		    need_rescan = TRUE;
2331 		}
2332 	    }
2333     	}
2334     }
2335 }
2336 
2337 /* Perform any prescheduled disappearances. */
2338 
2339 static void
run_disappearances(void)2340 run_disappearances(void)
2341 {
2342     char buf1[BUFSIZE], buf2[BUFSIZE];
2343     int curturn;
2344     Unit *unit;
2345 
2346     /* Precompute whether any units will disappear at a given time. */
2347     /* Note that this won't be right if any units created during the game
2348        must disappear, but there is no during-the-game way to create a unit
2349        that is scheduled to disappear, so this is no problem. */
2350     if (any_disappearances < 0) {
2351     	any_disappearances = FALSE;
2352 	for_all_units(unit) {
2353 	    if (unit_disappear_turn(unit) >= 0) {
2354 		any_disappearances = TRUE;
2355 		break;
2356 	    }
2357 	}
2358 	Dprintf("Any disappearances: %d\n", any_disappearances);
2359     }
2360     if (!any_disappearances)
2361       return;
2362     Dprintf("Running disappearances\n");
2363     curturn = g_turn();
2364     for_all_units(unit) {
2365     	/* See if now time for a unit to disappear. */
2366     	if (in_play(unit)
2367 	    && unit_disappear_turn(unit) >= 0
2368 	    && unit_disappear_turn(unit) <= curturn) {
2369 	    strcpy(buf1, unit_handle(unit->side, unit));
2370 	    destination_desc(buf2, unit->side, unit, unit->x, unit->y, 0);
2371 	    /* (should eject occupants first if possible) */
2372 	    kill_unit(unit, H_UNIT_LEFT_WORLD);
2373 	    /* (should use generic event notification mech? */
2374 	    notify(unit->side, "%s has disappeared from %s.", buf1, buf2);
2375 	}
2376     }
2377 }
2378 
2379 /* Some types of units can repair themselves or others without doing actions. */
2380 
2381 namespace Xconq {
2382     //! Temp pointer to unit to be auto-repaired.
2383     Unit *auto_repair_unit = NULL;
2384 }
2385 
2386 static void
run_auto_repair(void)2387 run_auto_repair(void)
2388 {
2389     using namespace Xconq;
2390 
2391     Unit *unit = NULL, *transport = NULL;
2392     int u = NONUTYPE;
2393     int hpold = -1;
2394     int i = -1;
2395 
2396     if (!any_auto_repair && !any_hp_recovery)
2397       return;
2398     Dprintf("Running auto repair\n");
2399     // Go through all units and auto-repair as necessary.
2400     for_all_units(unit) {
2401 	// Skip out-of-play units.
2402 	if (!in_play(unit))
2403 	    continue;
2404 	// Useful info.
2405 	u = unit->type;
2406 	hpold = unit->hp;
2407 	auto_repair_unit = unit;
2408 	// Skip units that don't need repairs.
2409 	if (unit->hp >= u_hp(u))
2410 	    continue;
2411 	// Skip units which cannot be auto-repaired,
2412 	//  and which do not benefit from the hp-recovery mechanism.
2413 	if (!cv__could_be_auto_repaired[u] && (0 >= u_hp_recovery(u)))
2414 	    continue;
2415 	// Run the hp-recovery mechanism.
2416 	if (0 < u_hp_recovery(u)) {
2417 	    if (valid(check_repair_action(unit, unit, unit)))
2418 		do_repair_action(unit, unit, unit);
2419 	}
2420 	// If unit can only be auto-repaired inside another unit,
2421 	//  then skip ranged auto-repair attempts.
2422 	if (0 > cv__auto_repaired_range_max[u]) {
2423 	    // Traverse the transport pointers to top of stack.
2424 	    transport = unit->transport ? unit->transport : unit;
2425 	    for (; transport->transport; transport = transport->transport);
2426 	    // Auto-repair from the top-level transport downwards.
2427 	    auto_repair_from_in(transport);
2428 	}
2429 	// Else apply ranged auto-repair.
2430 	// NOTE: We cannot apply to a fat ring because of the way the
2431 	//  'apply_to_ring' algorithm is set up. There would be a bias
2432 	//  towards one edge of the ring, if we did. We apply to concentric
2433 	//  thin rings instead.
2434 	else {
2435 	    auto_repair_from_here(unit->x, unit->y);
2436 	    for (i = 1; (i <= cv__auto_repaired_range_max[u]) && !stop_apply;
2437 		 ++i)
2438 		apply_to_ring(unit->x, unit->y, i, i, auto_repair_from_here);
2439 	}
2440 	// Inform the player if the unit's HP changed.
2441 	if (unit->hp != hpold)
2442 	    update_unit_display(unit->side, unit, TRUE);
2443     }
2444 }
2445 
2446 static void
auto_repair_from_in(Unit * transport)2447 auto_repair_from_in(Unit *transport)
2448 {
2449     using namespace Xconq;
2450 
2451     Unit *occ = NULL, *repairee = NULL, *transport2 = NULL;
2452     int u2 = NONUTYPE, u3 = NONUTYPE;
2453 
2454     assert_error(in_play(transport),
2455 		 "Auto Repair: Attempted to repair within an out-of-play unit");
2456     repairee = auto_repair_unit;
2457     assert_error(in_play(repairee),
2458 		 "Auto Repair: Attempted to repair an out-of-play unit");
2459     // Useful info.
2460     u3 = repairee->type;
2461     // Any repair necessary?
2462     if (repairee->hp == u_hp(u3)) {
2463 	stop_apply = TRUE;
2464 	return;
2465     }
2466     // Iterate over all occs.
2467     for_all_occupants(transport, occ) {
2468 	u2 = occ->type;
2469 	// Use occs to repair with first.
2470 	// QUESTION: Should we disallow occs to repair their friends
2471 	//  from inside units belonging to untrusted sides?
2472 	if (occ->occupant) {
2473 	    // If auto-repair range < 0, then restrict to transport-occ chain.
2474 	    if (0 > uu_auto_repair_range(u2, u3)) {
2475 		// If occ is repairee...
2476 		if (occ == repairee)
2477 		    auto_repair_from_in(occ);
2478 		else {
2479 		    // If occ is in transport chain of repairee...
2480 		    for (transport2 = repairee->transport; transport2;
2481 			 transport2 = transport2->transport) {
2482 			if (transport2 == occ) {
2483 			    auto_repair_from_in(occ);
2484 			    break;
2485 			}
2486 		    }
2487 		    // If repairee is in transport chain of occ...
2488 		    if (!transport2) {
2489 			for (transport2 = transport; transport2;
2490 			     transport2 = transport2->transport) {
2491 			    if (transport2 == repairee) {
2492 				auto_repair_from_in(occ);
2493 				break;
2494 			    }
2495 			}
2496 		    }
2497 		}
2498 	    }
2499 	    // Else, try the auto-repair.
2500 	    else
2501 		auto_repair_from_in(occ);
2502 	}
2503 	// Skip untrusted units.
2504 	if (!trusted_side(occ->side, repairee->side))
2505 	    continue;
2506 	// Skip repairee, if already done.
2507 	if ((occ == repairee) && (0 < u_hp_recovery(u2)))
2508 	    continue;
2509 	// Auto-repair, if possible.
2510 	if (valid(check_repair_action(occ, occ, repairee)))
2511 	    do_repair_action(occ, occ, repairee);
2512     } // for all occupants
2513 }
2514 
2515 static void
auto_repair_from_here(int x,int y)2516 auto_repair_from_here(int x, int y)
2517 {
2518     using namespace Xconq;
2519 
2520     Unit *repairer = NULL, *repairee = NULL;
2521     int u3 = NONUTYPE;
2522 
2523     repairee = auto_repair_unit;
2524     assert_error(in_play(repairee),
2525 		 "Auto Repair: Attempted to repair an out-of-play unit");
2526     // Useful info.
2527     u3 = repairee->type;
2528     // Any repair necessary?
2529     if (repairee->hp == u_hp(u3)) {
2530 	stop_apply = TRUE;
2531 	return;
2532     }
2533     // Iterate through cell ustack.
2534     for_all_stack(x, y, repairer) {
2535 	// Use occs to repair with first.
2536 	// QUESTION: Should we allow occs to repair their friends
2537 	//  from inside units belonging to untrusted sides?
2538 	if (repairer->occupant)
2539 	    auto_repair_from_in(repairer);
2540 	// Skip untrusted units.
2541 	if (!trusted_side(repairer->side, repairee->side))
2542 	    continue;
2543 	// Skip repairee, if already done.
2544 	if ((repairer == repairee) && (0 < u_hp_recovery(repairer->type)))
2545 	    continue;
2546 	// Auto-repair, if possible.
2547 	if (valid(check_repair_action(repairer, repairer, repairee)))
2548 	    do_repair_action(repairer, repairer, repairee);
2549     } // for all cell ustack
2550 }
2551 
2552 /* Some types of units recover lost morale spontaneously. */
2553 
2554 static void
run_morale_recovery(void)2555 run_morale_recovery(void)
2556 {
2557     int u, moralerecovery, moralemax;
2558     Unit *unit;
2559 
2560     /* Precompute whether any units ever recover morale. */
2561     if (any_morale_recovery < 0) {
2562 	any_morale_recovery = FALSE;
2563     	for_all_unit_types(u) {
2564 	    if (u_morale_recovery(u) > 0) {
2565 		any_morale_recovery = TRUE;
2566 		break;
2567 	    }
2568 	}
2569 	Dprintf("Any morale recovery: %d\n", any_morale_recovery);
2570     }
2571     if (!any_morale_recovery)
2572       return;
2573     Dprintf("Running morale recovery\n");
2574     for_all_units(unit) {
2575 	if (is_active(unit)) {
2576 	    u = unit->type;
2577 	    moralerecovery = u_morale_recovery(u);
2578 	    moralemax = u_morale_max(u);
2579 	    if (moralerecovery > 0 && unit->morale < moralemax) {
2580 		/* Change the morale (using a routine that does all the
2581 		   notification). */
2582 		change_morale(unit, 1, prob_fraction(moralerecovery));
2583 	    }
2584 	}
2585     }
2586 }
2587 
2588 /* Auto upgrade/downgrade any units that can do so. */
2589 
2590 static void
run_auto_change_types(void)2591 run_auto_change_types (void)
2592 {
2593     Unit *unit = NULL;
2594     int u = NONUTYPE, u2 = NONUTYPE;
2595     Side *side = NULL;
2596 
2597     if (!any_auto_change_types)
2598         return;
2599     Dprintf("Running auto unit type changes.\n");
2600     for_all_units(unit) {
2601         if (!is_active(unit))
2602           continue;
2603         u = unit->type;
2604         side = unit->side;
2605         if (is_unit_type(u2 = u_auto_upgrade_to(u))
2606             && (A_ANY_OK == check_change_type_action(unit, unit, u2))) {
2607 	    /* If unit is in transport. */
2608 	    if (unit->transport) {
2609 		if (type_can_occupy_without(u2, unit->transport, unit)) {
2610 		    notify(side, "%s changes into a %s.",
2611 			   unit_handle(side, unit), u_type_name(u2));
2612 		    change_unit_type(unit, u2, H_UNIT_TYPE_CHANGED, NULL);
2613 		    continue;
2614 		}
2615 		else {
2616 		    notify(side,
2617 "%s could have changed into a %s, but there was no room.",
2618 			   unit_handle(side, unit), u_type_name(u2));
2619 		    continue;
2620 		}
2621 	    }
2622 	    /* Else, unit is directly in the cell. */
2623 	    else {
2624 		if (type_can_occupy_cell_without(u2, unit->x, unit->y, unit)) {
2625 		    notify(side, "%s changes into a %s.",
2626 			   unit_handle(side, unit), u_type_name(u2));
2627 		    change_unit_type(unit, u2, H_UNIT_TYPE_CHANGED, NULL);
2628 		    continue;
2629 		}
2630 		else {
2631 		    notify(side,
2632 "%s could have changed into a %s, but there was no room.",
2633 			   unit_handle(side, unit), u_type_name(u2));
2634 		    continue;
2635 		}
2636 	    }
2637         }
2638     }
2639     return;
2640 }
2641 
2642 /* Decide what happens to units belonging to sides that have lost.
2643    Not all units will necessarily disappear right away, so this runs
2644    at each turn. */
2645 
2646 static void lost_unit_surrender(Unit *unit);
2647 static void maybe_surrender_lost_to(Unit *unit, Unit *unit2);
2648 
2649 static void
run_unit_fates(void)2650 run_unit_fates(void)
2651 {
2652     int u, u1, u2, chance, anylost;
2653     Side *side, *origside;
2654     Unit *unit;
2655 
2656     if (any_lost_vanish < 0) {
2657 	any_lost_vanish = FALSE;
2658 	for_all_unit_types(u1) {
2659 	    if (u_lost_vanish(u1) > 0) {
2660 		any_lost_vanish = TRUE;
2661 		break;
2662 	    }
2663 	}
2664     }
2665     if (any_lost_wreck < 0) {
2666 	any_lost_wreck = FALSE;
2667 	for_all_unit_types(u1) {
2668 	    if (u_lost_wreck(u1) > 0) {
2669 		any_lost_wreck = TRUE;
2670 		break;
2671 	    }
2672 	}
2673     }
2674     if (any_lost_surrender < 0) {
2675 	any_lost_surrender = FALSE;
2676 	for_all_unit_types(u1) {
2677 	    for_all_unit_types(u2) {
2678 		if (uu_lost_surrender(u1, u2) > 0) {
2679 		    any_lost_surrender = TRUE;
2680 		    if (any_lost_surrenders == NULL)
2681 		      any_lost_surrenders = (char *)xmalloc(numutypes);
2682 		    any_lost_surrenders[u1] = TRUE;
2683 		    break;
2684 		}
2685 	    }
2686 	}
2687     }
2688     if (any_lost_revolt < 0) {
2689 	any_lost_revolt = FALSE;
2690 	for_all_unit_types(u1) {
2691 	    if (u_lost_revolt(u1) > 0) {
2692 		any_lost_revolt = TRUE;
2693 		break;
2694 	    }
2695 	}
2696     }
2697     if (!(any_lost_vanish
2698 	  || any_lost_wreck
2699 	  || any_lost_surrender
2700 	  || any_lost_revolt))
2701       return;
2702     /* Don't kick in until at least one side has lost. */
2703     anylost = FALSE;
2704     for_all_sides(side) {
2705 	if (side_lost(side)) {
2706 	    anylost = TRUE;
2707 	    break;
2708 	}
2709     }
2710     if (!anylost)
2711       return;
2712     /* Although it would be more efficient to only scan units on sides
2713        that have lost, units may be changing sides, so per-side list
2714        scanning will lose. */
2715     for_all_units(unit) {
2716 	if (side_lost(unit->side)) {
2717 	    if (in_play(unit)) {
2718 		u = unit->type;
2719 		if (any_lost_wreck) {
2720 		    chance = u_lost_wreck(u);
2721 		    if (chance > 0 && xrandom(10000) < chance) {
2722 			wreck_unit(unit, H_UNIT_WRECKED, WRECK_TYPE_SIDE_LOST,
2723 				   -1, NULL);
2724 		    }
2725 		}
2726 	    }
2727 	    if (in_play(unit)) {
2728 		u = unit->type;
2729 		if (any_lost_vanish) {
2730 		    chance = u_lost_vanish(u);
2731 		    if (chance > 0 && xrandom(10000) < chance) {
2732 			kill_unit(unit, H_UNIT_VANISHED);
2733 		    }
2734 		}
2735 	    }
2736 	    if (in_play(unit)) {
2737 		origside = unit->side;
2738 		if (any_lost_surrender && any_lost_surrenders[u]) {
2739 		    lost_unit_surrender(unit);
2740 		}
2741 		if (any_lost_revolt && unit->side == origside) {
2742 		    chance = u_lost_revolt(u);
2743 		    if (chance > 0 && xrandom(10000) < chance) {
2744 			unit_revolt(unit, TRUE);
2745 		    }
2746 		}
2747 	    }
2748 	}
2749     }
2750 }
2751 
2752 static void
lost_unit_surrender(Unit * unit)2753 lost_unit_surrender(Unit *unit)
2754 {
2755     int u = unit->type, dir, x1, y1;
2756     Unit *unit2;
2757 
2758     for_all_stack(unit->x, unit->y, unit2) {
2759 	if (in_play(unit2)
2760 	    && unit2->side != unit->side
2761 	    && uu_lost_surrender(u, unit2->type) > 0
2762 	    && visible_to(unit, unit2)) {
2763 	    maybe_surrender_lost_to(unit, unit2);
2764 	}
2765     }
2766     /* Check on adjacent units. */
2767     for_all_directions(dir) {
2768 	if (interior_point_in_dir(unit->x, unit->y, dir, &x1, &y1)) {
2769 	    for_all_stack(x1, y1, unit2) {
2770 		if (in_play(unit2)
2771 		    && unit2->side != unit->side
2772 		    && uu_surrender_chance(u, unit2->type) > 0
2773 		    && visible_to(unit, unit2)) {
2774 		    maybe_surrender_lost_to(unit, unit2);
2775 		}
2776 	    }
2777 	}
2778     }
2779 }
2780 
2781 static void
maybe_surrender_lost_to(Unit * unit,Unit * unit2)2782 maybe_surrender_lost_to(Unit *unit, Unit *unit2)
2783 {
2784     int chance;
2785 
2786     chance = uu_lost_surrender(unit->type, unit2->type);
2787     if (xrandom(10000) < chance) {
2788 	capture_unit(unit, unit2, H_UNIT_SURRENDERED);
2789     }
2790 }
2791 
2792 static void
run_detonation_accidents(void)2793 run_detonation_accidents(void)
2794 {
2795     int u, t, x, y, z, chance;
2796     Unit *unit;
2797 
2798     /* Precompute whether accidental detonation can ever occur. */
2799     if (any_detonation_accidents < 0) {
2800 	any_detonation_accidents = FALSE;
2801 	for_all_unit_types(u) {
2802 	    for_all_terrain_types(t) {
2803 		if (ut_detonation_accident(u, t) > 0) {
2804 		    any_detonation_accidents = TRUE;
2805 		    break;
2806 		}
2807 	    }
2808 	    if (any_detonation_accidents)
2809 	      break;
2810 	}
2811 	Dprintf("Any detonation accidents: %d\n", any_detonation_accidents);
2812     }
2813     if (!any_detonation_accidents)
2814       return;
2815     Dprintf("Running detonation accidents\n");
2816     for_all_units(unit) {
2817 	if (in_play(unit) && completed(unit)) {
2818 	    x = unit->x;  y = unit->y;  z = unit->z;
2819 	    t = terrain_at(x, y);
2820 	    /* (should account for being an occupant?) */
2821 	    chance = ut_detonation_accident(unit->type, t);
2822 	    if (chance > 0 && xrandom(10000) < chance) {
2823 		extern int max_u_detonate_effect_range;
2824 
2825 		/* Detonate the unit right where it is. */
2826 		detonate_unit(unit, x, y, z);
2827 		reckon_damage_around(x, y, max_u_detonate_effect_range, unit);
2828 	    }
2829 	}
2830     }
2831 }
2832 
2833 /* Take care of details that no longer require any interaction, at least
2834    none that can't wait until the next turn. */
2835 
2836 static void
finish_movement(void)2837 finish_movement(void)
2838 {
2839     int lostacp;
2840     Unit *unit;
2841     Side *side;
2842 
2843     for_all_sides(side) {
2844 	if (Debug) {
2845 	    lostacp = 0;
2846 	    for_all_side_units(side, unit) {
2847 		if (is_active(unit) && unit->act && unit->act->acp > 0) {
2848 		    /* Note that we don't count acp-min here, would be
2849 		       way too confusing. */
2850 		    lostacp += unit->act->acp;
2851 		}
2852 	    }
2853 	    if (lostacp > 0) {
2854 		Dprintf("%s forfeited %d acp overall.\n",
2855 			side_desig(side), lostacp);
2856 	    }
2857 	}
2858     }
2859     for_all_sides(side)  {
2860 	update_side_display_all_sides(side, TRUE);
2861     }
2862 }
2863