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