1 /* The combat-related actions of Xconq.
2    Copyright (C) 1987-1989, 1991-2000 Stanley T. Shebs.
3    Copyright (C) 2004-2005 Eric A. McDonald.
4 
5 Xconq is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.  See the file COPYING.  */
9 
10 #include "conq.h"
11 #include "kernel.h"
12 
13 static int one_attack(Unit *atker, Unit *defender);
14 static void fire_on_unit(Unit *atker, Unit *other);
15 static void attack_unit(Unit *atker, Unit *other);
16 static void maybe_hit_unit(Unit *atker, Unit *other, int fire, int fallsoff);
17 static void hit_unit(Unit *unit, int hit, Unit *atker);
18 static void model_1_attack(Unit *unit, int x, int y);
19 static int real_attack_value(Unit *unit);
20 static int real_defense_value(Unit *unit);
21 
22 static void reckon_damage(int fire);
23 static void reckon_damage_here(int x, int y);
24 static void report_damage(Unit *unit, Unit *atker, Unit *mainunit, int fire);
25 static int will_report_damage(Unit *unit);
26 static void rescue_one_occupant(Unit *occ);
27 static int retreat_unit(Unit *unit, Unit *atker);
28 static int retreat_in_dir(Unit *unit, int dir);
29 static void attempt_to_capture_unit(Unit *atker, Unit *other);
30 static void capture_unit_2(Unit *unit, Unit *pris, Side *prevside);
31 static void capture_occupant(Unit *unit, Unit *pris, Unit *occ, Side *newside);
32 static void detonate_on_cell(int x, int y);
33 static void hit_unit_with_detonation(Unit *unit, int hit, Unit *atker);
34 static int found_blocking_elevation(int u, int ux, int uy, int uz, int u2, int u2x, int u2y, int u2z);
35 static Unit *mobile_enemy_threat(Unit *unit, int range);
36 static int enough_ammo_to_attack_unit(Unit *unit, Unit *other);
37 static int enough_ammo_to_fire_at_unit(Unit *unit, Unit *other);
38 static int enough_ammo_to_fire_one_round(Unit *unit);
39 
40 static void damage_terrain(int u, int x, int y);
41 static int damaged_terrain_type(int t);
42 
43 /* We can't declare all the action functions as static because some of them
44    are in other files, but don't let them be visible to all files. */
45 
46 #undef  DEF_ACTION
47 #define DEF_ACTION(name,code,args,prepfn,netprepfn,DOFN,checkfn,ARGDECL,doc)  \
48   extern int DOFN ARGDECL;
49 
50 #include "action.def"
51 
52 /* Destruction stuff. */
53 
54 typedef enum {
55     DESTRUCT_ORDINARY = 0,
56     DESTRUCT_VANISH
57 } DestructionResult;
58 
59 static DestructionResult determine_destruction_result(Unit *unit);
60 
61 /* Detonation stuff. */
62 
63 int max_u_detonate_effect_range = -1;
64 
65 int max_t_detonate_effect_range = -1;
66 
67 int max_detonate_on_approach_range = -1;
68 
69 /* Remember what the main units involved are, so display is handled
70    relative to them and not to any occupants. */
71 
72 static Unit *amain, *omain;
73 
74 int numsoundplays;
75 
76 /* Useful, little functions. */
77 
78 //! Chance that u will hit u2 by firing.
79 
80 int
fire_hit_chance(int u,int u2)81 fire_hit_chance(int u, int u2)
82 {
83     return (uu_fire_hit(u, u2) != -1) ? uu_fire_hit(u, u2) : uu_hit(u, u2);
84 }
85 
86 //! Damage that u does to u2 by firing.
87 
88 int
fire_damage(int u,int u2)89 fire_damage(int u, int u2)
90 {
91     return (uu_fire_damage(u, u2) != -1) ? uu_fire_damage(u, u2)
92                                          : uu_damage(u, u2);
93 }
94 
95 //! Chance for u to capture independent u2.
96 
97 int
indep_capture_chance(int u,int u2)98 indep_capture_chance(int u, int u2)
99 {
100     return (uu_indep_capture(u, u2) != -1) ? uu_indep_capture(u, u2)
101                                            : uu_capture(u, u2);
102 }
103 
104 //! Chance for u to capture u2 on a given side?
105 
106 int
capture_chance(int u,int u2,Side * side2)107 capture_chance(int u, int u2, Side *side2)
108 {
109     if (side2 != indepside)
110       return uu_capture(u, u2);
111     return (indep_capture_chance(u, u2));
112 }
113 
114 /* Unit/utype status/analysis functions. */
115 
116 //! Could u fire at u2?
117 /*! \todo Remove ACP restrictions. */
118 
119 int
could_fire_at(int u,int u2)120 could_fire_at(int u, int u2)
121 {
122     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
123     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
124     if (!u_acp_independent(u) && !u_acp_to_fire(u))
125       return FALSE;
126     return ((g_combat_model() == 0) && (0 < fire_hit_chance(u, u2)));
127 }
128 
129 //! Could u fire at >= 1 utypes?
130 
131 int
could_fire_at_any(int u)132 could_fire_at_any(int u)
133 {
134     int u2 = NONUTYPE;
135 
136     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
137     for_all_unit_types(u2) {
138         if (could_fire_at(u, u2))
139 	  return TRUE;
140     }
141     return FALSE;
142 }
143 
144 //! Can a given unit fire?
145 /*!
146     \todo Get rid of combat models.
147     \todo Get rid of ACP restrictions.
148     \todo Consider 'consumption-per-fire' and 'hit-by'.
149 */
150 
151 int
can_fire(Unit * actor,Unit * firer)152 can_fire(Unit *actor, Unit *firer)
153 {
154     int rslt = A_ANY_OK;
155     int acp = 0;
156     int u2 = NONUTYPE;
157     int m2 = NONMTYPE;
158 
159     /* In combat model 1, we can't attack units by firing. */
160     if (g_combat_model() == 1)
161       return A_ANY_ERROR;
162     /* Can the ACP source and firer act? */
163     if (!valid(rslt = can_act(actor, firer)))
164       return rslt;
165     u2 = firer->type;
166     /* Is there enough ACP to fire? */
167     acp = u_acp_to_fire(u2);
168     if (acp < 1)
169       return A_ANY_CANNOT_DO;
170     if (!has_enough_acp(actor, acp))
171       return A_ANY_NO_ACP;
172     /* Check whether we can attack from inside a transport. */
173     if (firer->transport
174 	&& uu_occ_combat(u2, firer->transport->type) == 0)
175       return A_ANY_OCC_CANNOT_DO;
176     /* We have to have a minimum level of supply to be able to attack. */
177     for_all_material_types(m2) {
178 	if (firer->supply[m2] < um_to_fire(u2, m2))
179 	  return A_ANY_NO_MATERIAL;
180     }
181     return rslt;
182 }
183 
184 //! Can a given unit fire at a given utype?
185 
186 int
can_fire_at(Unit * actor,Unit * firer,int u)187 can_fire_at(Unit *actor, Unit *firer, int u)
188 {
189     int rslt = A_ANY_OK;
190 
191     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
192     if (!could_fire_at(firer->type, u))
193       return A_ANY_CANNOT_DO;
194     if (!valid(rslt = can_fire(actor, firer)))
195       return rslt;
196     return rslt;
197 }
198 
199 //! Can a given unit fire at >= 1 enemy utypes?
200 
201 int
can_fire_at_any(Unit * actor,Unit * firer)202 can_fire_at_any(Unit *actor, Unit *firer)
203 {
204     int rslt = A_ANY_OK;
205     int u = NONUTYPE;
206 
207     for_all_unit_types(u) {
208 	if (valid(rslt = can_fire_at(actor, firer, u)))
209 	  return A_ANY_OK;
210     }
211     return A_ANY_CANNOT_DO;
212 }
213 
214 //! Could u hit u2 by attacks?
215 /*! \todo Remove ACP restrictions.  */
216 
217 int
could_attack(int u,int u2)218 could_attack(int u, int u2)
219 {
220     if (!u_acp_independent(u) && !uu_acp_to_attack(u, u2))
221       return FALSE;
222     return (((g_combat_model() == 0) && uu_hit(u, u2))
223             || ((g_combat_model() == 1) && u_attack(u)));
224 }
225 
226 //! Could the given utype attack >= 1 utypes?
227 
228 int
could_attack_any(int u)229 could_attack_any(int u)
230 {
231     int u2 = NONUTYPE;
232 
233     for_all_unit_types(u2) {
234 	if (could_attack(u, u2))
235 	  return TRUE;
236     }
237     return FALSE;
238 }
239 
240 //! Can a given unit attack a given utype?
241 /*!
242     \todo Get rid of ACP restrictions.
243     \todo Consider 'consumption-per-attack' and 'hit-by'.
244 */
245 
246 int
can_attack(Unit * actor,Unit * attacker,int u3)247 can_attack(Unit *actor, Unit *attacker, int u3)
248 {
249     int rslt = A_ANY_OK;
250     int acp = 0;
251     int u2 = NONUTYPE;
252     int m = NONMTYPE;
253 
254     if (!valid(rslt = can_act(actor, attacker)))
255       return rslt;
256     u2 = attacker->type;
257     /* Is there enough ACP to attack? */
258     acp = uu_acp_to_attack(u2, u3);
259     if (acp < 1)
260       return A_ANY_CANNOT_DO;
261     if (!has_enough_acp(actor, acp))
262       return A_ANY_NO_ACP;
263     /* Check whether we can attack from inside a transport. */
264     if (attacker->transport
265 	&& uu_occ_combat(u2, attacker->transport->type) == 0)
266       return A_ANY_OCC_CANNOT_DO;
267     /* We have to have a minimum level of supply to be able to attack. */
268     for_all_material_types(m) {
269 	if (attacker->supply[m] < um_to_attack(u2, m))
270 	  return A_ANY_NO_MATERIAL;
271     }
272     return rslt;
273 }
274 
275 //! Can a given unit attack >= 1 enemy utypes?
276 
277 int
can_attack_any(Unit * actor,Unit * attacker)278 can_attack_any(Unit *actor, Unit *attacker)
279 {
280     int rslt = A_ANY_OK;
281     int u = NONUTYPE;
282 
283     for_all_unit_types(u) {
284 	if (valid(rslt = can_attack(actor, attacker, u)))
285 	  return A_ANY_OK;
286     }
287     return A_ANY_CANNOT_DO;
288 }
289 
290 //! Could u hit u2 by attacks or fire?
291 
292 int
could_hit(int u,int u2)293 could_hit(int u, int u2)
294 {
295     return (could_attack(u, u2) || could_fire_at(u, u2));
296 }
297 
298 //! Can given unit detonate?
299 /* \todo Remove ACP restrictions. */
300 
301 int
can_detonate(Unit * actor,Unit * detonator)302 can_detonate(Unit *actor, Unit *detonator)
303 {
304     int rslt = A_ANY_OK;
305     int acp = 0;
306     int u2 = NONUTYPE;
307 
308     /* Can actor and detonator act? */
309     if (!valid(rslt = can_act(actor, detonator)))
310       return rslt;
311     u2 = detonator->type;
312     /* The unit must actually be able to detonate. */
313     acp = u_acp_to_detonate(u2);
314     if (acp < 1)
315       return A_ANY_CANNOT_DO;
316     if (!has_enough_acp(actor, acp))
317       return A_ANY_NO_ACP;
318     return rslt;
319 }
320 
321 //! Could u capture u2 by fire?
322 /*
323     \todo Get rid of combat models.
324     \todo Remove ACP restrictions.
325 */
326 
327 int
could_capture_by_fire(int u,int u2,Side * oside)328 could_capture_by_fire(int u, int u2, Side *oside)
329 {
330     if (!u_acp_independent(u) && !u_acp_to_fire(u))
331       return FALSE;
332     if (g_combat_model() == 1)
333       return FALSE;
334     if (fire_hit_chance(u, u2))
335       return (0 < capture_chance(u, u2, oside));
336     return FALSE;
337 }
338 
339 //! Could u capture u2 by attacks?
340 /*
341     \todo Get rid of combat models.
342     \todo Remove ACP restrictions.
343 */
344 
345 int
could_capture_by_attacks(int u,int u2,Side * oside)346 could_capture_by_attacks(int u, int u2, Side *oside)
347 {
348     if (!u_acp_independent(u) && !uu_acp_to_attack(u, u2))
349       return FALSE;
350     /* Since capture only can happen through overrun actions in
351 	combat model 1, and such actions are blocked if u_attack(u) is
352 	zero (see model_1_attack) we return 0. Exception: if there is
353 	an encounter result specified, we return the capture chance
354 	(if non-zero) since the encounter code is executed before the
355 	check of u_attack(u). */
356     if ((g_combat_model() == 1) && !u_attack(u))
357       return FALSE;
358     if (((g_combat_model() == 0) && uu_hit(u, u2)) || (g_combat_model() == 1))
359       return (0 < capture_chance(u, u2, oside));
360     return FALSE;
361 }
362 
363 //! Could u capture u2 by direct capture?
364 /*
365     \todo Get rid of combat models.
366     \todo Remove ACP restrictions.
367 */
368 
369 int
could_capture_by_capture(int u,int u2,Side * oside)370 could_capture_by_capture(int u, int u2, Side *oside)
371 {
372     if (!u_acp_independent(u) && !uu_acp_to_capture(u, u2))
373       return FALSE;
374     if (g_combat_model() == 1)
375       return FALSE;
376     return (0 < capture_chance(u, u2, oside));
377 }
378 
379 //! Could u capture u2 by any means?
380 
381 int
could_capture(int u,int u2,Side * oside)382 could_capture(int u, int u2, Side *oside)
383 {
384     return (could_capture_by_attacks(u, u2, oside)
385             || could_capture_by_fire(u, u2, oside)
386             || could_capture_by_capture(u, u2, oside));
387 }
388 
389 //! Could the given utype capture any utypes by any means?
390 
391 int
could_capture_any(int u)392 could_capture_any(int u)
393 {
394     int u2 = NONUTYPE;
395 
396     for_all_unit_types(u2) {
397 	/* Capture can happen by both direct action and as result of an
398 	   attack in combat model 0. */
399 	if (g_combat_model() == 0) {
400 		if ((uu_acp_to_attack(u, u2) > 0
401 		    || uu_acp_to_capture(u, u2) > 0)
402 		    && (uu_capture(u, u2) > 0 || uu_indep_capture(u, u2) > 0))
403 		  return TRUE;
404 	/* Capture can only happen as result of an attack in combat model 1. */
405 	} else if (g_combat_model() == 1) {
406 		if (uu_acp_to_attack(u, u2) > 0
407 		    && (uu_capture(u, u2) > 0 || uu_indep_capture(u, u2) > 0))
408 		  return TRUE;
409 	}
410     }
411     return FALSE;
412 }
413 
414 //! Can a given unit capture a given utype on a given side?
415 
416 int
can_capture(Unit * actor,Unit * captor,int u3,Side * eside)417 can_capture(Unit *actor, Unit *captor, int u3, Side *eside)
418 {
419     int rslt = A_ANY_OK;
420     int acp = 0;
421     int u2 = NONUTYPE;
422     int m = NONMTYPE;
423 
424     /* Can actor and captor act? */
425     if (!valid(rslt = can_act(actor, captor)))
426       return rslt;
427     u2 = captor->type;
428     /* We can't capture units on our side. */
429     if (actor->side == eside)
430       return A_ANY_ERROR;
431     /* Enough ACP to capture? */
432     acp = uu_acp_to_capture(u2, u3);
433     if (acp < 1)
434       return A_ANY_CANNOT_DO;
435     if (!has_enough_acp(actor, acp))
436       return A_ANY_NO_ACP;
437     /* Is there even a chance to capture the enemy utype? */
438     if (capture_chance(u2, u3, eside) == 0)
439       return A_ANY_CANNOT_DO;
440     /* We have to have a minimum level of supply to be able to capture. */
441     /* (attack material table not really appropriate) */
442     for_all_material_types(m) {
443 	if (captor->supply[m] < um_to_attack(u2, m))
444 	  return A_ANY_NO_MATERIAL;
445     }
446     return rslt;
447 }
448 
449 /* Attack action. */
450 
451 /* This is an attack on a given unit at a given level of commitment. */
452 
453 int
prep_attack_action(Unit * unit,Unit * unit2,Unit * defender,int n)454 prep_attack_action(Unit *unit, Unit *unit2, Unit *defender, int n)
455 {
456     if (unit == NULL || unit->act == NULL || unit2 == NULL)
457       return FALSE;
458     unit->act->nextaction.type = ACTION_ATTACK;
459     unit->act->nextaction.args[0] = defender->id;
460     unit->act->nextaction.args[1] = n;
461     unit->act->nextaction.actee = unit2->id;
462     return TRUE;
463 }
464 
465 int
do_attack_action(Unit * unit,Unit * unit2,Unit * defender,int n)466 do_attack_action(Unit *unit, Unit *unit2, Unit *defender, int n)
467 {
468     int u2 = unit2->type, u3 = defender->type;
469     int withdrawchance, surrenderchance;
470 
471     action_point(unit2->side, defender->x, defender->y);
472     action_point(defender->side, defender->x, defender->y);
473     /* Defender might be a type that can sneak away to avoid attack. */
474     withdrawchance = uu_withdraw_per_attack(u2, u3);
475     if (withdrawchance > 0) {
476 	if (probability(withdrawchance)) {
477 	    if (retreat_unit(defender, unit2)) {
478     		if (alive(unit))
479     		  use_up_acp(unit, uu_acp_to_attack(u2, u3));
480 		return A_ANY_DONE;
481 	    }
482 	}
483     }
484     /* Defender might instead choose to surrender right off. */
485     surrenderchance = uu_surrender_per_attack(u2, u3);
486     if (surrenderchance > 0
487 	&& unit2->side
488 	&& unit2->side->tech[u3] >= u_tech_to_own(u3)) {
489 	if (probability(surrenderchance)) {
490 	    capture_unit(unit2, defender, H_UNIT_CAPTURED);
491 	    if (alive(unit))
492 	      use_up_acp(unit, uu_acp_to_attack(u2, u3));
493 	    return A_ANY_DONE;
494 	}
495     }
496     /* Carry out a normal attack. */
497     one_attack(unit, defender);
498     if (alive(unit))
499       use_up_acp(unit, uu_acp_to_attack(u2, u3));
500     /* The defender in an attack has to take time to defend itself. */
501     if (alive(defender))
502       use_up_acp(defender, uu_acp_to_defend(u2, u3));
503     return A_ANY_DONE;
504 }
505 
506 int
check_attack_action(Unit * unit,Unit * unit2,Unit * defender,int n)507 check_attack_action(Unit *unit, Unit *unit2, Unit *defender, int n)
508 {
509     int u, u2, u3, u2x, u2y, dfx, dfy, dist;
510     int rslt = A_ANY_OK;
511 
512     /* In combat model 1, we can't attack units directly. */
513     if (g_combat_model() == 1)
514       return A_ANY_ERROR;
515     if (!in_play(defender))
516       return A_ANY_ERROR;
517     /* We can't attack ourselves. */
518     if (unit2 == defender)
519       return A_ANY_ERROR;
520     if (!valid(rslt = can_attack(unit, unit2, defender->type)))
521       return rslt;
522     if (!indep(unit2) && unit2->side == defender->side)
523       return A_ANY_ERROR;
524     u = unit->type;
525     u2 = unit2->type;
526     u3 = defender->type;
527     u2x = unit2->x;  u2y = unit2->y;
528     dfx = defender->x;  dfy = defender->y;
529     dist = distance(u2x, u2y, dfx, dfy);
530     if (dist < uu_attack_range_min(u2, u3))
531       return A_ANY_TOO_NEAR;
532     if (dist > uu_attack_range(u2, u3))
533       return A_ANY_TOO_FAR;
534     if (uu_hit(u2, u3) <= 0)
535       return A_ATTACK_CANNOT_HIT;
536     /* (should prorate ammo needs by intensity of attack) */
537     if (!enough_ammo_to_attack_unit(unit2, defender))
538       return A_ANY_NO_AMMO;
539     /* Allow attacks even if zero damage, this amounts to "harassment". */
540     return A_ANY_OK;
541 }
542 
543 /* Overrun action. */
544 
545 /* Overrun is an attempt to occupy a given cell that may include attempts
546    to attack and/or capture any units in the way. */
547 
548 int
prep_overrun_action(Unit * unit,Unit * unit2,int x,int y,int z,int n)549 prep_overrun_action(Unit *unit, Unit *unit2, int x, int y, int z, int n)
550 {
551     if (unit == NULL || unit->act == NULL || unit2 == NULL)
552       return FALSE;
553     unit->act->nextaction.type = ACTION_OVERRUN;
554     unit->act->nextaction.args[0] = x;
555     unit->act->nextaction.args[1] = y;
556     unit->act->nextaction.args[2] = z;
557     unit->act->nextaction.args[3] = n;
558     unit->act->nextaction.actee = unit2->id;
559     return TRUE;
560 }
561 
562 int
do_overrun_action(Unit * unit,Unit * unit2,int x,int y,int z,int n)563 do_overrun_action(Unit *unit, Unit *unit2, int x, int y, int z, int n)
564 {
565     int u, u2, u3, acpused, mpcost, acpcost, speed, ox, oy, oz;
566     int withdrawchance, surrenderchance, gotonext;
567     Unit *defender;
568 
569     u = unit->type;  u2 = unit2->type;
570     ox = unit2->x;  oy = unit2->y;  oz = unit2->z;
571     action_point(unit2->side, x, y);
572     acpused = 0;
573     switch(g_combat_model()) {
574       case 0:
575 	/* Attack every defender in turn. */
576 	for_all_stack(x, y, defender) {
577 	    u3 = defender->type;
578 	    /* Don't attack any of our buddies. */
579 	    if (unit_trusts_unit(unit2, defender))
580 	      continue;
581 	    action_point(defender->side, x, y);
582 	    gotonext = FALSE;
583 	    /* Defender might be a type that can sneak away to avoid
584                attack. */
585 	    withdrawchance = uu_withdraw_per_attack(u2, u3);
586 	    if (withdrawchance > 0) {
587 		if (probability(withdrawchance)) {
588 		    if (retreat_unit(defender, unit2)) {
589 			gotonext = TRUE;
590 		    }
591 		}
592 	    }
593 	    /* Defender might instead choose to surrender right off. */
594 	    surrenderchance = uu_surrender_per_attack(u2, u3);
595 	    if (surrenderchance > 0
596 		&& unit2->side
597 		&& unit2->side->tech[u3] >= u_tech_to_own(u3)) {
598 		if (probability(surrenderchance)) {
599 		    capture_unit(unit2, defender, H_UNIT_CAPTURED);
600 		    gotonext = TRUE;
601 		}
602 	    }
603             /* If any units were captured, the captor may have become
604                a garrison. If so, then the captor is considered dead.
605                Check for this before trying to fire/attack from (-1,-1)!
606                (If the last unit in the stack is the one garrisoned,
607                then this is a kind of Pyrrhic victory. For the
608                time being, we will count this as a failure so that major
609                surgery does not have to be done on the overrun code.)
610             */
611             if (!alive(unit2))
612               return A_OVERRUN_FAILED;
613 	    /* (should automatically prefer direct attack if better odds) */
614 	    if (valid(check_fire_at_action(unit, unit, defender, -1))) {
615 		do_fire_at_action(unit, unit, defender, -1);
616 		acpused += u_acp_to_fire(u2);
617 		/* Unlike the case below, target acp consumption has
618 		   already been dealt with in fire_on_unit, which is
619 		   called by do_fire_at_action. */
620 	    }
621 	    else if (valid(check_attack_action(unit, unit, defender, 100))) {
622 		if (!gotonext)
623 		  one_attack(unit2, defender);
624 		if (alive(unit))
625 		  use_up_acp(unit, uu_acp_to_attack(u2, u3));
626 		acpused += uu_acp_to_attack(u2, u3);
627 		/* The target of an attack has to take time to defend
628 		   itself. */
629 		if (!gotonext && alive(defender)) {
630 		    use_up_acp(defender, uu_acp_to_defend(u, u3));
631 		}
632 	    }
633 	}
634 	if (!alive(unit2))
635 	  return A_OVERRUN_FAILED;
636 	if (in_blocking_zoc(unit2, x, y, z))
637 	  return A_OVERRUN_FAILED;
638 	/* Try to enter the cleared cell now - might still have
639 	   friendlies filling it up already, so check first. We don't
640 	   check for type_survives_in_cell, so suicide by deadly
641 	   terrain remains possible. */
642 	if (type_can_occupy_cell(unit2->type, x, y)) {
643 	    mpcost = move_unit(unit2, x, y);
644 	    /* Note that we'll say the action succeeded even if
645 	       the cell did not have enough room for us to actually
646 	       be in it, which is a little weird. */
647 	    /* Now add up any extra movement costs of entering the new cell. */
648 	    mpcost += zoc_move_cost(unit2, ox, oy, oz);
649 	    acpcost = 0;
650 	    speed = unit_speed(unit2, x, y);
651 	    if (speed > 0)
652 	      acpcost = (mpcost * 100) / speed;
653 	    acpcost -= acpused;
654 	    if (acpcost > 0) {
655 		/* Take the movement cost out of the moving unit if
656                    possible. */
657 		use_up_acp(unit2, acpcost);
658 	    }
659 	    /* Count the unit as having actually moved. */
660 	    if (unit2->act)
661 	      ++(unit2->act->actualmoves);
662 	}
663       break;
664       case 1:
665 	model_1_attack(unit2, x, y);
666 	break;
667       default:
668 	break;
669     }
670     return A_OVERRUN_SUCCEEDED;
671 }
672 
673 int
check_overrun_action(Unit * unit,Unit * unit2,int x,int y,int z,int n)674 check_overrun_action(Unit *unit, Unit *unit2, int x, int y, int z, int n)
675 {
676     int u, u2, u2x, u2y, u2z, u3, totcost, speed, mpavail, m;
677     Unit *defender;
678 
679     if (!in_play(unit))
680       return A_ANY_ERROR;
681     if (!in_play(unit2))
682       return A_ANY_ERROR;
683     if (!inside_area(x, y))
684       return A_ANY_ERROR;
685     if (n == 0)
686       return A_ANY_ERROR;
687     u = unit->type;
688     u2 = unit2->type;
689     if (!has_enough_acp(unit, 1))
690       return A_ANY_NO_ACP;
691     /* Check whether we can attack from inside a transport. */
692     if (unit2->transport && uu_occ_combat(u2, unit2->transport->type) == 0)
693       return A_ANY_OCC_CANNOT_DO;
694     u2x = unit2->x;  u2y = unit2->y;  u2z = unit2->z;
695     /* We have to be in the same cell or an adjacent one. */
696     if (!between(0, distance(u2x, u2y, x, y), 1))
697       return A_ANY_TOO_FAR;
698     /* Now start looking at the move costs. */
699     u3 = (unit2->transport ? unit2->transport->type : NONUTYPE);
700     totcost = total_move_cost(u2, u3, u2x, u2y, u2z, x, y, u2z);
701     speed = unit_speed(unit2, x, y);
702     mpavail = (unit->act->acp * speed) / 100;
703     /* Zero mp always disallows movement, unless intra-cell. */
704     if (mpavail <= 0 && !(u2x == x && u2y == y && u2z == u2z))
705       return A_MOVE_NO_MP;
706     /* The free mp might get us enough moves, so add it before comparing. */
707     if (mpavail + u_free_mp(u2) < totcost)
708       return A_MOVE_NO_MP;
709     /* We have to have a minimum level of supply to be able to attack. */
710     for_all_material_types(m) {
711 	if (unit2->supply[m] < um_to_attack(u2, m))
712 	  return A_ANY_NO_MATERIAL;
713     }
714     switch(g_combat_model()) {
715       case 0:
716 	for_all_stack(x, y, defender) {
717 	    /* If we can't attack the unit, then we can't possibly overrun. */
718 	    if (uu_acp_to_attack(u2, defender->type) == 0)
719 	      return A_OVERRUN_CANNOT_HIT;
720 	    /* (should test if units here can be attacked en masse) */
721 	    /* (should prorate ammo needs by intensity of overrun) */
722 	    if (!enough_ammo_to_attack_unit(unit2, defender))
723 	      return A_ANY_NO_AMMO;
724 	}
725 	break;
726       case 1:
727 	/* Assume we can always attempt to overrun */
728 	break;
729       default:
730 	return A_ANY_ERROR;
731     }
732     return A_ANY_OK;
733 }
734 
735 /* Return true if the attacker defeated the defender, and can therefore
736    try to move into the defender's old position. */
737 
738 static int
one_attack(Unit * atker,Unit * defender)739 one_attack(Unit *atker, Unit *defender)
740 {
741     int ua = atker->type, ud = defender->type;
742     int ax = atker->x, ay = atker->y, ox = defender->x, oy = defender->y;
743     int counter;
744     Side *as = atker->side, *os = defender->side;
745     SideMask observers;
746 
747     amain = atker;  omain = defender;
748     attack_unit(atker, defender);
749     /* Do a counterattack if appropriate.  We must be able to counterattack,
750        and have enough acp to do so. */
751     counter = uu_counterattack(ua, ud);
752     if (counter > 0
753 	&& has_enough_acp(defender, uu_acp_to_defend(ua, ud))
754 	&& alive(atker)) {
755 	/* (should use value to set strength/commitment of counterattack) */
756 	attack_unit(defender, atker);
757     }
758     if (0 /* recording attacks */) {
759 	observers = add_side_to_set(atker->side, NOSIDES);
760 	observers = add_side_to_set(defender->side, observers);
761 	/* (should let other watching sides see event also) */
762 	record_event(H_UNIT_ASSAULTED, observers, atker->id, defender->id,
763 		     ox, oy);
764     }
765     reckon_damage(FALSE);
766 #if (0)
767     see_exact(as, ax, ay);
768     see_exact(as, ox, oy);
769     see_exact(os, ax, ay);
770     see_exact(os, ox, oy);
771 #else
772     see_cell(as, ax, ay);
773     see_cell(as, ox, oy);
774     see_cell(os, ax, ay);
775     see_cell(os, ox, oy);
776 #endif
777     update_cell_display(as, ax, ay, UPDATE_ALWAYS);
778     update_cell_display(as, ox, oy, UPDATE_ALWAYS);
779     update_cell_display(os, ax, ay, UPDATE_ALWAYS);
780     update_cell_display(os, ox, oy, UPDATE_ALWAYS);
781     all_see_cell(ax, ay);
782     all_see_cell(ox, oy);
783     if (!alive(atker))
784       return FALSE;
785     attempt_to_capture_unit(atker, defender);
786     /* If the defender was not captured, it might turn the tables! */
787     /* (Note that we cannot cache the attacker's and defender's types,
788        because the type might have changed due to damage, and we want
789        to know if the new type might countercapture.) */
790     if (alive(defender)
791 	&& alive(atker)
792 	&& defender->side == os
793 	&& uu_countercapture(atker->type, defender->type) > 0) {
794 	attempt_to_capture_unit(defender, atker);
795     }
796     return (alive(atker) && unit_at(ox, oy) == NULL);
797 }
798 
799 /* Implement "combat model 1", which emulates Civ-type games.  Combat
800    is multi-round, ending in the demise of one or the other combatant,
801    plus anything stacked with it. */
802 
803 static void
model_1_attack(Unit * unit,int x,int y)804 model_1_attack(Unit *unit, int x, int y)
805 {
806     int u = unit->type, u2, u3, d, maxdef, def, att, winround, limit, dmg;
807     Obj *choice, *chtype, *chutype, *chside;
808     Unit *unit2, *defender, *occ, *defocc, *victim;
809     char *hitmovietype;
810     Side *side3;
811     SideMask sidemask;
812     int weightstotal = 0;
813 
814     for_all_stack(x, y, unit2) {
815 	u2 = unit2->type;
816 	if (u_encounter_result(u2) != lispnil) {
817 	    /* The encounter result overrides any other outcome. */
818 	    choice = choose_from_weighted_list(u_encounter_result(u2),
819 					       &weightstotal, FALSE);
820 	    if (is_quoted_lisp(choice))
821 	      choice = eval(choice);
822 	    if (consp(choice))
823 	      chtype = car(choice);
824 	    else
825 	      chtype = choice;
826 	    if (match_keyword(chtype, K_UNIT)) {
827 		/* Dig out a unit type spec. */
828 		chutype = cadr(choice);
829 		if (consp(chutype)) {
830 		    chside = cadr(chutype);
831 		    chutype = car(chutype);
832 		} else {
833 		    chside = lispnil;
834 		}
835 		u3 = utype_from_name(c_string(chutype));
836 		/* Pick out a side if one was specified. */
837 		if (numberp(chside)) {
838 		    side3 = side_n(c_number(chside));
839 		} else {
840 		    side3 = unit->side;
841 		}
842 		/* Change the unit's type. */
843 		change_unit_type(unit2, u3, H_UNIT_TYPE_CHANGED, side3);
844 		/* Changing the type will kill the unit if there is no room
845 		for the new type. */
846 		if (alive(unit2)) {
847 			unit2->hp = unit2->hp2 = u_hp(u3);
848 			/* We still need to explicitly change the unit side,
849 			   if the new type is allowed on the same side as
850 			   the old type. The 'newside' argument to
851 			   'change_unit_type' is only used when the new type
852 			   cannot be on the same side as the old type. */
853 			change_unit_side(unit2, side3, -1, unit);
854 			/* The unit is changing side voluntarily, so set the
855 			   original side also. */
856 			set_unit_origside(unit2, unit2->side);
857 		}
858 	    } else if (match_keyword(chtype, K_VANISH)) {
859 		kill_unit(unit2, H_UNIT_VANISHED);
860 	    } else {
861 		run_warning("Unknown encounter type %s", c_string(chtype));
862 	    }
863 	    if (consp(choice) && stringp(caddr(choice))) {
864 		notify(unit->side, "%s", c_string(caddr(choice)));
865 	    }
866 	    return;
867 	}
868     }
869     /* Non-combat units can't do anything. Note: this means that unarmed
870     units (settlers etc) cannot capture empty cities, since this happens by
871     overrun action. Should perhaps allow to proceed if attacking an empty
872     advanced type? However, in that case capture_chance must be changed,
873     since it right now disallows capture by unarmed units. */
874     if (u_attack(u) == 0)
875       return;
876     /* Choose the defender of a stack. */
877     maxdef = -1;
878     defender = NULL;
879     for_all_stack(x, y, unit2) {
880 	/* Don't attack any of our buddies. */
881 	if (unit_trusts_unit(unit, unit2))
882 	  continue;
883 	/* Identify the best defender. */
884 	def = real_defense_value(unit2);
885 	if (def > maxdef) {
886 	    maxdef = def;
887 	    defender = unit2;
888 	}
889     }
890     /* If the location is empty for some reason, escape quietly. */
891     if (defender == NULL)
892       return;
893     /* For cities, find a defender. */
894     if (u_advanced(defender->type)) {
895         /* We don't want defenseless occs (facilities) to count as defenders,
896          * so initialize maxdefs to 0 instead of -1. */
897 	maxdef = 0;
898 	defocc = NULL;
899 	for_all_occupants(defender, occ) {
900 	    u2 = occ->type;
901 	    def = u_defend(u2);
902 	    if (def > maxdef) {
903 		maxdef = def;
904 		defocc = occ;
905 	    }
906 	}
907 	/* Cities with no defenders can be captured directly. */
908 	if (defocc == NULL) {
909 	    attempt_to_capture_unit(unit, defender);
910 	    return;
911 	}
912 	defender = defocc;
913     }
914     d = defender->type;
915     limit = 100;
916     while (alive(unit) && alive(defender) && limit-- > 0) {
917 	att = real_attack_value(unit);
918 	def = real_defense_value(defender);
919 	winround = probability((att * 100) / (att + def));
920 	if (winround) {
921 	    dmg = roll_dice(uu_damage(u, d));
922 	    victim = defender;
923 	    defender->hp2 -= dmg;
924 	} else {
925 	    dmg = roll_dice(uu_damage(d, u));
926 	    victim = unit;
927 	    unit->hp2 -= dmg;
928 	}
929 	if (defender->hp2 <= 0) {
930 	    report_combat(unit, defender, "destroy");
931 	} else if (unit->hp2 <= 0) {
932 	    report_combat(defender, unit, "destroy");
933 	}
934 	/* Pick the hit movie to show. */
935 	hitmovietype = (char *)((victim->hp2 <= 0) ? "death" : "hit-short");
936 	/* Make up the list of sides that will see it. */
937 	sidemask = NOSIDES;
938 	for_all_sides(side3) {
939 	    /* Let all sides that can see the attacker's cell see it. */
940 	    if (units_visible(side3, victim->x, victim->y))
941 	      sidemask = add_side_to_set(side3, sidemask);
942 	}
943 	/* Show the movie. */
944 	for_all_sides(side3) {
945 	    if (side_in_set(side3, sidemask))
946 	      schedule_movie(side3, hitmovietype, victim->id);
947 	}
948 	play_movies(ALLSIDES);
949 	damage_unit(unit, combat_dmg, defender);
950 	damage_unit(defender, combat_dmg, unit);
951     }
952     /* The whole stack dies if its defender dies. */
953     if (!alive(defender) && defender->transport == NULL) {
954 	for_all_stack(x, y, unit2) {
955 	    if (!u_advanced(unit2->type)) {
956 		/* (should except spies etc?) */
957 		unit2->hp2 = 0;
958 		report_combat(unit, unit2, "destroy");
959 	    }
960 	}
961 	reckon_damage_here(x, y);
962 	/* But capture cities instead of destroying them. */
963 	for_all_stack(x, y, unit2) {
964 	    if (u_advanced(unit2->type)) {
965 		attempt_to_capture_unit(unit, unit2);
966 	    }
967 	}
968 	/* Occupants of city may be damaged. */
969 	reckon_damage_here(x, y);
970     }
971 }
972 
973 /* The real attack value of a unit after adjustments for combat exp,
974 terrain effects, occupants etc. */
975 
976 int
real_attack_value(Unit * unit)977 real_attack_value(Unit *unit)
978 {
979 	Unit *unit2;
980 	int t, u, att, effect;
981 
982 	u = unit->type;
983 	att = u_attack(u);
984 	/* First factor in combat experience. */
985 	if (u_cxp_max(u) > 0 && unit->cxp > 0) {
986 	    effect = u_full_cxp_affects_attack(u);
987 	    if (effect != 100) {
988 		att *= (100 + (effect - 100) * unit->cxp / u_cxp_max(u)) / 100;
989 	    }
990 	}
991 	/* Then factor in terrain effects. */
992 	t = terrain_at(unit->x, unit->y);
993 	effect = ut_terrain_affects_attack(u, t);
994 	if (effect != 100) {
995 	    att *= effect / 100;
996 	}
997 	/* Then factor in effect of transport. */
998 	if (unit->transport) {
999 	    if (is_active(unit->transport)) {
1000 		effect = uu_transport_affects_attack(unit->transport->type, u);
1001 		if (effect != 100) {
1002 		    att *= effect / 100;
1003 		}
1004 	    }
1005 	}
1006 	/* Then factor in effect of occupants. */
1007 	for_all_occupants(unit, unit2) {
1008 		if (is_active(unit2)) {
1009 		    effect = uu_occ_affects_attack(unit2->type, u);
1010 		    if (effect != 100) {
1011 			att *= effect / 100;
1012 		    }
1013 		}
1014 	}
1015 	/* Then factor in effect of friendly units in the same cell. */
1016 	for_all_stack_with_occs(unit->x, unit->y, unit2) {
1017 	    if (is_active(unit2)
1018 		&& trusted_side(unit2->side, unit->side)) {
1019 		effect = uu_neighbour_affects_attack(unit2->type, u);
1020 		if (effect != 100) {
1021 			att *= effect / 100;
1022 		}
1023 	    }
1024 	}
1025 	return att;
1026 }
1027 
1028 
1029 /* The real defense value of a unit after adjustments for combat exp,
1030 terrain effects, occupants etc. */
1031 
1032 int
real_defense_value(Unit * unit)1033 real_defense_value(Unit *unit)
1034 {
1035 	Unit *unit2;
1036 	int t, u, def, effect;
1037 
1038 	u = unit->type;
1039 	def = u_defend(u);
1040 	/* First factor in combat experience. */
1041 	if (u_cxp_max(u) > 0 && unit->cxp > 0) {
1042 	    effect = u_full_cxp_affects_defense(u);
1043 	    if (effect != 100) {
1044 		def *= (100 + (effect - 100) * unit->cxp / u_cxp_max(u)) / 100;
1045 	    }
1046 	}
1047 	/* Then factor in terrain effects. */
1048 	t = terrain_at(unit->x, unit->y);
1049 	effect = ut_terrain_affects_defense(u, t);
1050 	if (effect != 100) {
1051 	    def *= effect / 100;
1052 	}
1053 	/* Then factor in effect of transport. */
1054 	if (unit->transport) {
1055 	    if (is_active(unit->transport)) {
1056 		effect = uu_transport_affects_defense(unit->transport->type, u);
1057 		if (effect != 100) {
1058 		    def *= effect / 100;
1059 		}
1060 	    }
1061 	}
1062 	/* Then factor in effect of occupants. */
1063 	for_all_occupants(unit, unit2) {
1064 	    if (is_active(unit2)) {
1065 		effect = uu_occ_affects_defense(unit2->type, u);
1066 		if (effect != 100) {
1067 		    def *= effect / 100;
1068 		}
1069 	    }
1070 	}
1071 	/* Then factor in effect of friendly units in the same cell. */
1072 	for_all_stack_with_occs(unit->x, unit->y, unit2) {
1073 	    if (is_active(unit2)
1074 		&& trusted_side(unit2->side, unit->side)) {
1075 		effect = uu_neighbour_affects_defense(unit2->type, u);
1076 		if (effect != 100) {
1077 		    def *= effect / 100;
1078 		}
1079 	    }
1080 	}
1081 	return def;
1082 }
1083 
1084 
1085 /* Fire-at action. */
1086 
1087 /* Shooting at a given unit. */
1088 
1089 int
prep_fire_at_action(Unit * unit,Unit * unit2,Unit * unit3,int m)1090 prep_fire_at_action(Unit *unit, Unit *unit2, Unit *unit3, int m)
1091 {
1092     if (unit == NULL || unit->act == NULL || unit2 == NULL || unit3 == NULL)
1093       return FALSE;
1094     unit->act->nextaction.type = ACTION_FIRE_AT;
1095     unit->act->nextaction.args[0] = unit3->id;
1096     unit->act->nextaction.args[1] = m;
1097     unit->act->nextaction.actee = unit2->id;
1098     return TRUE;
1099 }
1100 
1101 int
do_fire_at_action(Unit * unit,Unit * unit2,Unit * unit3,int m)1102 do_fire_at_action(Unit *unit, Unit *unit2, Unit *unit3, int m)
1103 {
1104     int ux = unit->x, uy = unit->y, ox, oy, oz;
1105     SideMask sidemask;
1106     Side *side;
1107 
1108     action_point(unit2->side, unit3->x, unit3->y);
1109     action_point(unit3->side, unit3->x, unit3->y);
1110     /* Make up the list of sides that will see the fire. */
1111     sidemask = NOSIDES;
1112     for_all_sides(side) {
1113 	/* Let all sides that can see the attacker's cell see it. */
1114 	if (units_visible(side, unit2->x, unit2->y))
1115 	  sidemask = add_side_to_set(side, sidemask);
1116 	/* Let all sides that can see the unit3's cell see it. */
1117 	if (units_visible(side, unit3->x, unit3->y))
1118 	  sidemask = add_side_to_set(side, sidemask);
1119     }
1120     /* Show the fire. */
1121     for_all_sides(side) {
1122 	if (side_in_set(side, sidemask))
1123 	  update_fire_at_display(side, unit, unit3, m, TRUE);
1124     }
1125     ox = unit3->x;  oy = unit3->y;  oz = unit3->z;
1126     amain = unit;  omain = unit3;
1127     fire_on_unit(unit, unit3);
1128     reckon_damage(TRUE);
1129     if (alive(unit))
1130       use_up_acp(unit, u_acp_to_fire(unit2->type));
1131     /*	if (alive(unit3)) use_up_acp(unit3, 1); */
1132     /* Each side sees what happened to its own unit. */
1133     update_unit_display(unit2->side, unit2, TRUE);
1134     if (unit != unit2)
1135       update_unit_display(unit->side, unit, TRUE);
1136     update_unit_display(unit3->side, unit3, TRUE);
1137     /* The attacking side also sees the remote cell. */
1138     update_cell_display(unit2->side, ox, oy, UPDATE_ALWAYS);
1139     update_cell_display(unit3->side, ox, oy, UPDATE_ALWAYS);
1140     /* Victim might see something in attacker's cell. */
1141     update_cell_display(unit3->side, ux, uy, UPDATE_ALWAYS);
1142     /* Actually, everybody might be seeing the combat. */
1143     all_see_cell(ux, uy);
1144     all_see_cell(ox, oy);
1145     /* Permit attempts to capture after fire, but only from adjacent
1146        or same cell. */
1147     if (distance(unit2->x, unit2->y, unit3->x, unit3->y) < 2) {
1148 	Side *os = unit3->side;
1149 
1150 	attempt_to_capture_unit(unit2, unit3);
1151 	/* If the unit3 was not captured, it might turn the tables! */
1152 	/* (Note that we cannot cache the attacker's and unit3's
1153 	   types, because the type might have changed due to damage,
1154 	   and we want to know if the new type might countercapture.)  */
1155 	if (alive(unit3)
1156 	    && alive(unit2)
1157 	    && unit3->side == os
1158 	    && uu_countercapture(unit2->type, unit3->type) > 0) {
1159 	    attempt_to_capture_unit(unit3, unit2);
1160 	}
1161     }
1162     /* Always expend the ammo (but only if m is a valid mtype). */
1163     return A_ANY_DONE;
1164 }
1165 
1166 /* Test a fire action for plausibility. */
1167 
1168 int
check_fire_at_action(Unit * unit,Unit * unit2,Unit * unit3,int m)1169 check_fire_at_action(Unit *unit, Unit *unit2, Unit *unit3, int m)
1170 {
1171     int u, u2, u3, ux, uy, uz, dist;
1172     int rslt = A_ANY_OK;
1173 
1174     if (!valid(rslt = can_fire(unit, unit2)))
1175       return rslt;
1176     if (!in_play(unit3))
1177       return A_ANY_ERROR;
1178     /* We can't attack ourselves. */
1179     if (unit2 == unit3)
1180       return A_ANY_ERROR;
1181     u = unit->type; u2 = unit2->type;  u3 = unit3->type;
1182     ux = unit->x;  uy = unit->y;  uz = unit->z;
1183     /* Check that target is in range. */
1184     dist = distance(ux, uy, unit3->x, unit3->y);
1185     if (dist > u_range(u2))
1186       return A_ANY_TOO_FAR;
1187     if (dist < u_range_min(u2))
1188       return A_ANY_TOO_NEAR;
1189     if (!indep(unit2) && unit2->side == unit3->side)
1190       return A_ANY_ERROR;
1191     /* Attackers won't fire at anything they know they can't hit. */
1192     if (fire_hit_chance(u2, u3) <= 0)
1193       return A_FIRE_CANNOT_HIT;
1194     /* Check intervening elevations. */
1195     if (found_blocking_elevation(u2, ux, uy, uz, u3,
1196 				 unit3->x, unit3->y, unit3->z))
1197       return A_FIRE_BLOCKED;
1198     /* Check for enough of right kind of ammo
1199 	(this feature is not used anywhere in the code.
1200 	(-1) is always passed as m). */
1201     if (is_material_type(m)) {
1202     	if (unit->supply[m] == 0) {
1203 		return A_ANY_NO_AMMO;
1204     	}
1205     } else {
1206 	if (!enough_ammo_to_fire_at_unit(unit2, unit3))
1207 	    return A_ANY_NO_AMMO;
1208     }
1209     return A_ANY_OK;
1210 }
1211 
1212 /* Fire-into action. */
1213 
1214 /* Shooting at a given location. */
1215 
1216 int
prep_fire_into_action(Unit * unit,Unit * unit2,int x,int y,int z,int m)1217 prep_fire_into_action(Unit *unit, Unit *unit2, int x, int y, int z, int m)
1218 {
1219     if (unit == NULL || unit->act == NULL || unit2 == NULL)
1220       return FALSE;
1221     unit->act->nextaction.type = ACTION_FIRE_INTO;
1222     unit->act->nextaction.args[0] = x;
1223     unit->act->nextaction.args[1] = y;
1224     unit->act->nextaction.args[2] = z;
1225     unit->act->nextaction.args[3] = m;
1226     unit->act->nextaction.actee = unit2->id;
1227     return TRUE;
1228 }
1229 
1230 /* One can always shoot, if the cell is visible, but there might not
1231    not be anything to hit!  No counterattacks when shooting, and the
1232    results might not be visible to the shooter. */
1233 
1234 int
do_fire_into_action(Unit * unit,Unit * unit2,int x,int y,int z,int m)1235 do_fire_into_action(Unit *unit, Unit *unit2, int x, int y, int z, int m)
1236 {
1237     int ux = unit->x, uy = unit->y, ox, oy, oz;
1238     SideMask sidemask;
1239     Unit *other;
1240     Side *side;
1241 
1242     /* Make up the list of sides that will see the fire. */
1243     sidemask = NOSIDES;
1244     for_all_sides(side) {
1245 	/* Let all sides that can see the attacker's cell see it. */
1246 	if (units_visible(side, unit2->x, unit2->y))
1247 	  sidemask = add_side_to_set(side, sidemask);
1248 	/* Let all sides that can see the fired-into cell see it. */
1249 	if (units_visible(side, x, y))
1250 	  sidemask = add_side_to_set(side, sidemask);
1251     }
1252     /* Show the fire. */
1253     for_all_sides(side) {
1254 	if (side_in_set(side, sidemask))
1255 		update_fire_into_display(side, unit2, x, y, z, m, TRUE);
1256     }
1257     /* If any units at target, hit them. */
1258     for_all_stack(x, y, other) {
1259 	ox = other->x;  oy = other->y;  oz = other->z;
1260 	amain = unit;  omain = other;
1261 	fire_on_unit(unit2, other);
1262 	reckon_damage(TRUE);
1263 	/* Each side sees what happened to its unit that is being hit. */
1264 	update_unit_display(other->side, other, TRUE);
1265 	/* The attacking side also sees the remote cell. */
1266 	update_cell_display(unit->side, ox, oy, UPDATE_ALWAYS);
1267 	update_cell_display(other->side, ox, oy, UPDATE_ALWAYS);
1268 	/* Victim might see something in attacker's cell. */
1269 	update_cell_display(other->side, ux, uy, UPDATE_ALWAYS);
1270 	/* Actually, everybody might be seeing the combat. */
1271 	all_see_cell(ux, uy);
1272 	all_see_cell(ox, oy);
1273 	/* don't take moves though! */
1274     }
1275     /* Firing side gets just one update. */
1276     update_unit_display(unit2->side, unit2, TRUE);
1277     if (unit != unit2)
1278       update_unit_display(unit->side, unit, TRUE);
1279     if (alive(unit))
1280       use_up_acp(unit, u_acp_to_fire(unit2->type));
1281     /* Always expend the ammo (but only if m is a valid material). */
1282     /* We're always "successful", even though the bombardment may have
1283        had little or no actual effect. */
1284     return A_ANY_DONE;
1285 }
1286 
1287 /* Test a shoot action for plausibility. */
1288 
1289 int
check_fire_into_action(Unit * unit,Unit * unit2,int x,int y,int z,int m)1290 check_fire_into_action(Unit *unit, Unit *unit2, int x, int y, int z, int m)
1291 {
1292     int u, u2, u2x, u2y, u2z, dist;
1293     int rslt = A_ANY_OK;
1294 
1295     if (!valid(rslt = can_fire(unit, unit2)))
1296       return rslt;
1297     u2x = unit2->x;  u2y = unit2->y;  u2z = unit2->z;
1298     /* Check that target location is meaningful. */
1299     if (!inside_area(x, y))
1300       return A_FIRE_INTO_OUTSIDE_WORLD;
1301     u = unit->type;
1302     u2 = unit2->type;
1303     /* Check that target is in range. */
1304     dist = distance(u2x, u2y, x, y);
1305     if (dist > u_range(u2))
1306       return A_ANY_TOO_FAR;
1307     if (dist < u_range_min(u2))
1308       return A_ANY_TOO_NEAR;
1309     /* Check intervening elevations and terrain. */
1310     if (found_blocking_elevation(u2, u2x, u2y, u2z, NONUTYPE, x, y, z))
1311       return A_FIRE_BLOCKED;
1312     /* Check for enough of right kind of ammo. */
1313     if (is_material_type(m)) {
1314     	if (unit->supply[m] == 0)
1315     	  return A_ANY_NO_AMMO;
1316     } else {
1317 	if (!enough_ammo_to_fire_one_round(unit2))
1318 	    return A_ANY_NO_AMMO;
1319     }
1320     return A_ANY_OK;
1321 }
1322 
1323 static int tmpx0, tmpy0, tmpe0, tmpe1, tmpdist01, cellwid, fangle;
1324 
1325 static int elevation_blocks(int x, int y);
1326 
1327 static int
elevation_blocks(int x,int y)1328 elevation_blocks(int x, int y)
1329 {
1330     int interpol, celldist0, dist0, el;
1331 
1332     celldist0 = distance(tmpx0, tmpy0, x, y);
1333     dist0 = celldist0 * cellwid;
1334     interpol = (tmpe1 - tmpe0) - (fangle * tmpdist01) / 100;
1335     /* The following is * dist0^2 / tmpdist01^2, but arranged to avoid
1336        overflow. */
1337     interpol *= dist0;
1338     interpol /= tmpdist01;
1339     interpol *= dist0;
1340     interpol /= tmpdist01;
1341     interpol += (fangle * dist0) / 100;
1342     interpol += tmpe0;
1343     el = (elevations_defined() ? elev_at(x, y) : 0);
1344     el += t_thickness(terrain_at(x, y));
1345     Dprintf("Arc at %d: %d, elev %d\n", celldist0, interpol, el);
1346     return (el > interpol);
1347 }
1348 
1349 int
found_blocking_elevation(int u,int ux,int uy,int uz,int u2,int u2x,int u2y,int u2z)1350 found_blocking_elevation(int u, int ux, int uy, int uz,
1351 			 int u2, int u2x, int u2y, int u2z)
1352 {
1353     int t, weaponheight, bodyheight, rslt, x1, y1;
1354 
1355     /* Note that a flat world with no elevation defined could
1356        still have thick terrain that screens. */
1357     /* (should detect absence of thick terrain and return immed) */
1358     /* Adjacent cells can't be screened by elevation. */
1359     /* (should accommodate possibility that target is at top of
1360        cliff in adj and back away from its edge, thus screened;
1361        need to recog cliffs vs slopes in terrain) */
1362     if (distance(ux, uy, u2x, u2y) <= 1)
1363       return FALSE;
1364     tmpx0 = ux;  tmpy0 = uy;
1365     t = terrain_at(ux, uy);
1366     tmpe0 = (elevations_defined() ? elev_at(ux, uy) : 0);
1367     weaponheight = ut_weapon_height(u, t);
1368     tmpe0 += weaponheight;
1369     tmpe1 = (elevations_defined() ? elev_at(u2x, u2y) : 0);
1370     bodyheight = ut_body_height(u, t);
1371     tmpe1 += bodyheight;
1372     cellwid = area.cellwidth;
1373     if (cellwid <= 0)
1374       cellwid = 1;
1375     fangle = u_fire_angle_max(u);
1376     tmpdist01 = distance(ux, uy, u2x, u2y) * cellwid;
1377     Dprintf("Checking arc: %d,%d el %d -> %d,%d el %d\n", ux, uy, tmpe0, u2x, u2y, tmpe1);
1378     rslt = search_straight_line(ux, uy, u2x, u2y, elevation_blocks, &x1, &y1);
1379     if (rslt)
1380       Dprintf("blocked at %d,%d\n", x1, y1);
1381     return rslt;
1382 }
1383 
1384 static void
fire_on_unit(Unit * atker,Unit * other)1385 fire_on_unit(Unit *atker, Unit *other)
1386 {
1387     int m, dist = distance(atker->x, atker->y, other->x, other->y), consump;
1388     int a = NONUTYPE, o = NONUTYPE;
1389 
1390     if (alive(atker) && alive(other)) {
1391 	a = atker->type;  o = other->type;
1392 	if (enough_ammo_to_fire_at_unit(atker, other)) {
1393 	    maybe_hit_unit(atker, other, TRUE, (dist > u_hit_falloff_range(a)));
1394 	    if (alive(atker)) {
1395 		for_all_material_types(m) {
1396 		    consump = um_hit_by(o, m);
1397 		    if (consump > 0) {
1398 			consump *= um_consumption_per_fire(a, m);
1399 			if (consump < 0)
1400 			  consump =
1401 			    um_hit_by(o, m) * um_consumption_per_attack(a, m);
1402 			atker->supply[m] -= consump;
1403 		    }
1404 		}
1405 	    }
1406 	    /* The *victim* can lose acp. */
1407 	    if (alive(other))
1408 	      use_up_acp(other, uu_acp_to_be_fired_on(o, atker->type));
1409 	}
1410     }
1411     /* (should ping victim to see if it wants to respond to the attack?) */
1412 }
1413 
1414 /* Test to see if enough ammo is available to make the attack.  Need
1415    enough of *all* types - semi-bogus but too complicated otherwise?  */
1416 
1417 int
enough_ammo_to_attack_unit(Unit * unit,Unit * other)1418 enough_ammo_to_attack_unit(Unit *unit, Unit *other)
1419 {
1420     int m, hitby;
1421 
1422     for_all_material_types(m) {
1423         hitby = um_hit_by(other->type, m);
1424         if (0 < hitby)
1425             if (unit->supply[m] < \
1426               hitby * um_consumption_per_attack(unit->type, m))
1427                 return FALSE;
1428     }
1429     return TRUE;
1430 }
1431 
1432 int
enough_ammo_to_fire_at_unit(Unit * unit,Unit * other)1433 enough_ammo_to_fire_at_unit(Unit *unit, Unit *other)
1434 {
1435     int m, hitby, consump;
1436 
1437     for_all_material_types(m) {
1438         hitby = um_hit_by(other->type, m);
1439         if (0 < hitby) {
1440             consump = hitby * um_consumption_per_fire(unit->type, m);
1441             if (0 > consump)
1442                 consump = hitby * um_consumption_per_attack(unit->type, m);
1443             if (unit->supply[m] < consump)
1444                 return FALSE;
1445         }
1446     }
1447     return TRUE;
1448 }
1449 
1450 /* Since we don't know what we are firing at, we test if we have enough of
1451 all ammo types required to fire at any target that we can hit. */
1452 
1453 int
enough_ammo_to_fire_one_round(Unit * unit)1454 enough_ammo_to_fire_one_round(Unit *unit)
1455 {
1456     int m;
1457 
1458     for_all_material_types(m) {
1459 	if (unit->supply[m] < um_consumption_per_fire(unit->type, m))
1460 	  return FALSE;
1461     }
1462     return TRUE;
1463 }
1464 
1465 /* Single attack, no counterattack.  Check and use ammo - usage
1466    independent of outcome, but types used depend on unit types
1467    involved. */
1468 
1469 static void
attack_unit(Unit * atker,Unit * other)1470 attack_unit(Unit *atker, Unit *other)
1471 {
1472     int m, hitby;
1473     int a = NONUTYPE, o = NONUTYPE;
1474 
1475     if (alive(atker) && alive(other)) {
1476 	a = atker->type;  o = other->type;
1477 	if (enough_ammo_to_attack_unit(atker, other)) {
1478 	    maybe_hit_unit(atker, other, FALSE, FALSE);
1479 	    if (alive(atker)) {
1480 		for_all_material_types(m) {
1481 		    hitby = um_hit_by(o, m);
1482 		    if (hitby > 0) {
1483 		      atker->supply[m] -=
1484 			um_consumption_per_attack(a, m) * hitby;
1485 		    }
1486 		}
1487 	    }
1488 	}
1489     }
1490     /* (should ping victim to see if it wants to respond to the attack?) */
1491 }
1492 
1493 /* Make a single hit and maybe hit some passengers also.  Power of hit
1494    is constant, but chance is affected by terrain, quality, and
1495    occupants' protective abilities.  If a hit is successful, it may
1496    have consequences on the defender's occupants, but limited by the
1497    protection that the transport provides. */
1498 
1499 static void
maybe_hit_unit(Unit * atker,Unit * other,int fire,int fallsoff)1500 maybe_hit_unit(Unit *atker, Unit *other, int fire, int fallsoff)
1501 {
1502     int chance, t, hit = 0, a = atker->type, o = other->type;
1503     int teffect, cxpeffect, cxpmax, effect, prot;
1504     int dist = 0, distdiff = 0, rangefoff = 0, rangemax = 0, hitrdist = 0,
1505         hitrfoff = 0, hitrmax = 0;
1506     int retrchance = 0;
1507     int dmgspec;
1508     char *hitmovietype;
1509     Unit *occ, *unit2;
1510     Side *side3;
1511     SideMask sidemask;
1512 
1513     Dprintf("%s tries to hit %s", unit_desig(atker), unit_desig(other));
1514     if (fire)
1515       chance = fire_hit_chance(a, o);
1516     else
1517       chance = uu_hit(a, o);
1518     /* Combat experience tends to raise the hit chance, so do that
1519        first, reduces roundoff weirdnesses later. */
1520     cxpmax = u_cxp_max(a);
1521     if (cxpmax > 0 && atker->cxp > 0) {
1522 	cxpeffect = uu_hit_cxp(a, o);
1523 	if (cxpeffect != 100) {
1524 	    effect = 100 + (atker->cxp * (cxpeffect - 100)) / cxpmax;
1525 	    chance = (chance * effect) / 100;
1526 	}
1527     }
1528     /* (should modify due to cxp of defender too) */
1529     /* Account for terrain effects. */
1530     t = terrain_at(atker->x, atker->y);
1531     if (fire && ut_fire_attack_terrain_effect(a, t) != -1)
1532       teffect = ut_fire_attack_terrain_effect(a, t);
1533     else
1534       teffect = ut_attack_terrain_effect(a, t);
1535     chance = (chance * teffect) / 100;
1536     t = terrain_at(other->x, other->y);
1537     if (fire && ut_fire_defend_terrain_effect(o, t) != -1)
1538       teffect = ut_fire_defend_terrain_effect(o, t);
1539     else
1540       teffect = ut_defend_terrain_effect(o, t);
1541     chance = (chance * teffect) / 100;
1542     /* Also account for aux terrain effects. */
1543     /* (should also account for direction of attack in the case of
1544         borders, and possibly connectors as well) */
1545     if (any_aux_terrain_defined()) {
1546         for_all_aux_terrain_types(t) {
1547             if (aux_terrain_defined(t)) {
1548                 if (aux_terrain_at(atker->x, atker->y, t)) {
1549                     if (fire && ut_fire_attack_terrain_effect(a, t) != -1)
1550                       teffect = ut_fire_attack_terrain_effect(a, t);
1551                     else
1552                       teffect = ut_attack_terrain_effect(a, t);
1553                     chance = (chance * teffect) / 100;
1554                 }
1555                 if (aux_terrain_at(other->x, other->y, t)) {
1556                     if (fire && ut_fire_defend_terrain_effect(o, t) != -1)
1557                       teffect = ut_fire_defend_terrain_effect(o, t);
1558                     else
1559                       teffect = ut_defend_terrain_effect(o, t);
1560                     chance = (chance * teffect) / 100;
1561                 }
1562             }
1563         }
1564     }
1565     /* Account for protection by occupants. */
1566     for_all_occupants(other, occ) {
1567 	if (in_play(occ) && completed(occ)) {
1568 	    prot = uu_protection(occ->type, o);
1569 	    if (prot != 100)
1570 	      chance = (chance * prot) / 100;
1571 	}
1572     }
1573     /* Account for protection by neighbours. */
1574     for_all_stack(other->x, other->y, unit2) {
1575 	if (unit2 != other
1576 	    && in_play(unit2)
1577 	    && completed(unit2)
1578 	    && unit2->side == other->side) {
1579 	    prot = uu_stack_protection(unit2->type, o);
1580 	    if (prot != 100)
1581 	      chance = (chance * prot) / 100;
1582 	}
1583     }
1584     /* Note that this code differs from that above in that it treats
1585        all units in the same cell equally, whether occs, suboccs or
1586        cellmates. This also means that one occ can protect another occ
1587        in the same transport. Moreover, the protective unit also
1588        protects itself. These rules simulate real situations such as
1589        when triple-A protects all nearby units (including itself)
1590        against bombers, or when a city wall protects all other
1591        occupants against ground attack. */
1592     for_all_stack_with_occs(other->x, other->y, unit2) {
1593 	if (is_active(unit2)
1594 	    /* We also extend protection to our buddies! */
1595 	    && trusted_side(unit2->side, other->side)) {
1596 	    /* This is when a unit, such as triple-A, extends unique
1597 	       protection against a specific attacker, such as
1598 	       bombers, to all other units in the cell. */
1599 	    prot = uu_cellwide_protection_against(unit2->type, a);
1600 	    if (prot != 100)
1601 	      chance = (chance * prot) / 100;
1602 	    /* This is when a unit (such as a garrison) specifically
1603 	       protects a second unit, such as a fort (but not other
1604 	       nearby units), against all forms of attack. It thus
1605 	       works the same way as uu_protection and
1606 	       uu_stack_protection. */
1607 	    prot = uu_cellwide_protection_for(unit2->type, o);
1608 	    if (prot != 100)
1609 	      chance = (chance * prot) / 100;
1610 	}
1611     }
1612     /* Determine how distance affects ranged fire.
1613        First, perform a [sanity] check to make sure that we are only
1614        executing this segment if the unit is firing and the effect of
1615        that fire falls off over distance.
1616        Second, calculate distance to target, and the difference,
1617        distdiff, between this and the falloff range.
1618        Third, calculate linear interpolant (slope of falloff effect) by
1619        determining the difference between rangemax and rangefoff and
1620        the difference between hitrmax and hitrfoff.
1621        Finally, interpolate the falloff effect, provided distdiff. */
1622     if (fire && fallsoff) {
1623         dist = distance(atker->x, atker->y, other->x, other->y);
1624         rangefoff = u_hit_falloff_range(a);
1625         distdiff = dist - rangefoff;
1626         if (0 < distdiff) {
1627             rangemax = u_range(a);
1628             hitrfoff = fire_hit_chance(a, o);
1629             hitrmax = (uu_hit_max_range_effect(a, o) * hitrfoff) / 100;
1630             hitrdist =
1631                 hitrfoff +
1632                 (distdiff * (hitrmax - hitrfoff)) / (rangemax - rangefoff);
1633             Dprintf(", fire distance is %d", dist);
1634             Dprintf(", fire falloff modifier is %d%%", hitrdist);
1635             chance = (chance * hitrdist) / 100;
1636         }
1637         /* else no falloff */
1638     }
1639     Dprintf(", probability of hit is %d%%", chance);
1640     /* Compute the hit itself. */
1641     if (probability(chance)) {
1642 	if (fire)
1643           dmgspec = fire_damage(a, o);
1644 	else
1645 	  dmgspec = uu_damage(a, o);
1646     	/* Account for attacker's experience. */
1647 	if (cxpmax > 0 && atker->cxp > 0) {
1648 	    cxpeffect = uu_damage_cxp(a, o);
1649 	    if (cxpeffect != 100) {
1650 		effect = 100 + (atker->cxp * (cxpeffect - 100)) / cxpmax;
1651 		dmgspec = multiply_dice(dmgspec, effect);
1652 	    }
1653 	}
1654 	hit = roll_dice(dmgspec);
1655     }
1656     if (hit > 0) {
1657     	Dprintf(", damage will be %d hp", hit);
1658     } else {
1659     	Dprintf(", missed");
1660     }
1661     /* (should record a raw statistic?) */
1662     /* Ablation is a chance for occupants or stack to take part of a
1663        hit themselves. */
1664     if (hit > 0) {
1665 	/* (should decide how ablation computed) */
1666     }
1667     /* Affect the hitting unit's morale.  Note that morale is still reduced
1668        even if the hit becomes 0 because of a successful retreat. */
1669     if (hit > 0) {
1670 	change_morale(atker, 1, uu_morale_hit(a, o));
1671     }
1672     if (hit > 0) {
1673 	retrchance = uu_retreat_chance(a, o);
1674 	/* Chance of a retreat rises to 100% as morale goes to 0. */
1675 	if (u_morale_max(o) > 0 && retrchance < 100)
1676 	  retrchance = 100 - ((100 - retrchance) * other->morale) /
1677 		       u_morale_max(o);
1678 	if (probability(retrchance)) {
1679 	    if (retreat_unit(other, atker)) {
1680 	    	/* It is possible that the unit died while trying to retreat
1681 		   into terrain where it vanishes. If so, we don't want to
1682 		   continue, since calling maybe_hit_unit recursively for an
1683 		   occupant will crash the game due to stack iteration for
1684 		   (-1,-1).  Nor do we want to report its retreat since its
1685 		   demise already has been reported. */
1686 	    	if (!alive(other)) {
1687 		    return;
1688 	    	}
1689 		report_combat(atker, other, "retreat");
1690 		hit = 0; /* should only be reduced hit, may still be > 0 */
1691 	    }
1692 	}
1693     }
1694     hit_unit(other, hit, atker);
1695     /* Pick the hit movie to show. */
1696     hitmovietype =
1697       (char *)((hit >= other->hp) ? "death" : ((hit > 0) ? "hit" : "miss"));
1698     /* Make up the list of sides that will see it. */
1699     sidemask = NOSIDES;
1700     for_all_sides(side3) {
1701 	/* Let all sides that can see the attacker's cell see it. */
1702 	if (units_visible(side3, atker->x, atker->y))
1703 	  sidemask = add_side_to_set(side3, sidemask);
1704 	/* Let all sides that can see the defender's cell see it. */
1705 	if (units_visible(side3, other->x, other->y))
1706 	  sidemask = add_side_to_set(side3, sidemask);
1707     }
1708     /* Show the movie. */
1709     for_all_sides(side3) {
1710 	if (side_in_set(side3, sidemask))
1711 	  schedule_movie(side3, hitmovietype, other->id);
1712     }
1713     Dprintf("\n");
1714     /* Recurse into occupants, maybe hit them too.  */
1715     /* It would really make sense to check for hit > 0 here and only
1716     hit occupants if the transport was hit. However, this will not
1717     work since some games require that occupants can be hit even
1718     if we miss the transport. */
1719     for_all_occupants(other, occ) {
1720 	if (is_active(other)) {
1721 	    if (probability(uu_protection(o, occ->type)))
1722 	      maybe_hit_unit(atker, occ, fire, fallsoff);
1723     	} else {
1724 	    /* No protection by incomplete transport. */
1725 	    maybe_hit_unit(atker, occ, fire, fallsoff);
1726 	}
1727     }
1728     /* Some units might detonate automatically upon scoring a melee hit. */
1729     if (!fire && (0 < hit)
1730         && in_play(atker)
1731         && probability(u_detonate_with_attack(atker->type))
1732         && !was_detonated(atker)) {
1733     	detonate_unit(atker, atker->x, atker->y, atker->z);
1734     }
1735     /* We get combat experience only if there could have been some damage. */
1736     if (chance > 0) {
1737     	if (in_play(atker) && (atker->cxp < u_cxp_max(a)))
1738     	  atker->cxp += uu_cxp_per_combat(a, o);
1739     	if (in_play(other) && (other->cxp < u_cxp_max(o)))
1740     	  other->cxp += uu_cxp_per_combat(o, a);
1741     	/* Occupants already gained their experience in the recursive call. */
1742     }
1743 }
1744 
1745 /* Do the hit itself. */
1746 
1747 static void
hit_unit(Unit * unit,int hit,Unit * atker)1748 hit_unit(Unit *unit, int hit, Unit *atker)
1749 {
1750     int u = unit->type, u2, hpmin, dmgspec, tpdmg, tp;
1751     Side *aside;
1752     int gain = 0, loss = 0;
1753     int m = NONMTYPE;
1754 
1755     /* Some units might detonate automatically upon being hit. */
1756     if (hit > 0
1757         && atker != NULL
1758         && probability(uu_detonate_on_hit(u, atker->type))
1759         && !was_detonated(unit)) {
1760     	detonate_unit(unit, unit->x, unit->y, unit->z);
1761     	/* If the detonating unit still exists, then continue on to
1762     	   normal damage computation. */
1763     }
1764     if (hit > 0) {
1765 	/* Record the loss of hp. */
1766 	unit->hp2 -= hit;
1767 	if (atker != NULL) {
1768 	    /* Attacker might not be able to do any more damage.  Note
1769 	       that the positioning of this code is such that all the
1770 	       usual side effects of combat happen, but the victim
1771 	       doesn't get any more worse off than it is already. */
1772 	    hpmin = uu_hp_min(atker->type, u);
1773 	    if (hpmin > 0 && hpmin > unit->hp2)
1774 	      unit->hp2 = hpmin;
1775 	    /* Affect the morale of the unit being hit. */
1776 	    change_morale(unit, -1, uu_morale_hit_by(atker->type, u));
1777 	}
1778 	/* Collateral damage may include loss of tooling. */
1779 	if (unit->tooling && 1 /* any_tp_damage */) {
1780 	    for_all_unit_types(u2) {
1781 		dmgspec = uu_tp_damage(u, u2);
1782 		tpdmg = roll_dice(dmgspec);
1783 		if (tpdmg != 0) {
1784 		    tp = unit->tooling[u2] - tpdmg;
1785 		    tp = max(0, min(tp, uu_tp_max(u, u2)));
1786 		    unit->tooling[u2] = tp;
1787 		}
1788 	    }
1789 	}
1790     }
1791     /* Maybe record for statistical analysis. */
1792     /* (this is only useful if code always goes through here - is that true?) */
1793     if (atker != NULL) {
1794 	aside = atker->side;
1795 	u2 = atker->type;
1796 	if (aside->atkstats[u2] == NULL)
1797 	  aside->atkstats[u2] = (long *) xmalloc(numutypes * sizeof(long));
1798 	if (aside->hitstats[u2] == NULL)
1799 	  aside->hitstats[u2] = (long *) xmalloc(numutypes * sizeof(long));
1800 	++((aside->atkstats[u2])[u]);
1801 	(aside->hitstats[u2])[u] += hit;
1802     }
1803     /* Some units may detonate automatically just before dying. */
1804     if (hit > 0 && unit->hp2 <= 0
1805         && probability(u_detonate_on_death(u))
1806         && !was_detonated(unit)) {
1807 	detonate_unit(unit, unit->x, unit->y, unit->z);
1808     }
1809     /* Treasury bonus and penalty due to unit destruction */
1810     if (hit > 0 && unit->hp2 <= 0) {
1811         for_all_material_types(m) {
1812             if (atker && side_has_treasury(atker->side, m)) {
1813 		gain = um_treasury_gain_per_destroy(atker->type, m);
1814 		atker->side->treasury[m] += gain;
1815 		/* Clip treasury to bounds, if necessary. */
1816 		atker->side->treasury[m] =
1817 		    min(atker->side->treasury[m], g_treasury_size());
1818 		atker->side->treasury[m] = max(atker->side->treasury[m], 0);
1819 	    }
1820             if (side_has_treasury(unit->side, m)) {
1821 		loss = um_treasury_loss_per_destroyed(unit->type, m);
1822 		unit->side->treasury[m] -= loss;
1823 		/* Clip treasury to bounds, if necessary. */
1824 		unit->side->treasury[m] =
1825 		    min(unit->side->treasury[m], g_treasury_size());
1826 		unit->side->treasury[m] = max(unit->side->treasury[m], 0);
1827 	    }
1828         }
1829     }
1830     /* CxP reward based on unit destruction */
1831     if (atker && hit > 0 && unit->hp2 <= 0 && (atker->cxp < u_cxp_max(u)))
1832       atker->cxp += uu_cxp_per_destroy(u, u2);
1833     /* Should wake the unit if it receives a tap from enemy. */
1834     /* (Perhaps we should worry about waking occupants according to
1835        recursive waking rules?) */
1836     if ((hit > 0) && is_active(unit))
1837       wake_unit(unit->side, unit, FALSE);
1838 }
1839 
1840 /* Hits on the main units have to be done later, so that mutual
1841    destruction works properly.  This function also does all the notifying. */
1842 
1843 /* (What if occupants change type when killed, but transport vanishes?) */
1844 
1845 static void
reckon_damage(int fire)1846 reckon_damage(int fire)
1847 {
1848     int ax = -1, ay = -1, ox = -1, oy = -1, range = -1;
1849     int o = NONUTYPE, a = NONUTYPE;
1850 
1851     /* Entertain everybody. */
1852     play_movies(ALLSIDES);
1853     /* Report the damage in more detail, now before the actual damage
1854        is taken (which may cause many units to disappear). */
1855     /* Normally we report the defender and then the attacker's damage,
1856        but if the defender dies, we report its counterattack results
1857        first and its death second. */
1858     if (!(omain->hp2 <= 0 && amain->hp2 > 0)) {
1859 	report_damage(omain, amain, omain, fire);
1860 	if (!fire && will_report_damage(amain))
1861 	  report_damage(amain, omain, amain, fire);
1862     } else {
1863 	if (!fire)
1864 	  report_damage(amain, omain, amain, fire);
1865 	report_damage(omain, amain, omain, fire);
1866     }
1867     a = amain->type;
1868     o = omain->type;
1869     ax = amain->x;  ay = amain->y;
1870     ox = omain->x;  oy = omain->y;
1871     damage_unit(omain, combat_dmg, amain);
1872     damage_unit(amain, combat_dmg, omain);
1873     /* If the attacker or defender may have detonated,
1874 	then look around to see what else was damaged. */
1875     range = max(range, max_u_detonate_effect_range);
1876     range = max(range, max_t_detonate_effect_range);
1877     if ((-1 < range) && u_detonate_with_attack(amain->type))
1878       reckon_damage_around(ax, ay, range, amain);
1879     if ((-1 < range)
1880 	&& (uu_detonate_on_capture(o, a) || uu_detonate_on_hit(o, a)
1881 	    || u_detonate_on_death(o)))
1882       reckon_damage_around(ox, oy, range, omain);
1883 }
1884 
1885 /*! \todo Evil var for search. Replace with parambox instead. */
1886 Unit *tmp_unit_detonator = NULL;
1887 
1888 static void
reckon_damage_here(int x,int y)1889 reckon_damage_here(int x, int y)
1890 {
1891     Unit *unit = NULL, *nextunit = NULL;
1892 
1893     /* NOTE: Use special iterator because units may get pulled out from
1894 	under us while we are iterating. */
1895     for (unit = unit_at(x, y); unit; unit = nextunit) {
1896 	nextunit = unit->nexthere;
1897 	damage_unit(unit, combat_dmg, tmp_unit_detonator);
1898     }
1899 }
1900 
1901 void
reckon_damage_around(int x,int y,int r,Unit * detonator)1902 reckon_damage_around(int x, int y, int r, Unit *detonator)
1903 {
1904     tmp_unit_detonator = detonator;
1905     if (r > 0) {
1906 	apply_to_area(x, y, r, reckon_damage_here);
1907     } else {
1908 	reckon_damage_here(x, y);
1909     }
1910     tmp_unit_detonator = NULL;
1911 }
1912 
1913 /* Given the units involved in combat, decide how to report it.  The
1914    strings like "destroy" and "miss" are symbolic, don't normally
1915    appear in the final output. */
1916 
1917 static void
report_damage(Unit * unit,Unit * atker,Unit * mainunit,int fire)1918 report_damage(Unit *unit, Unit *atker, Unit *mainunit, int fire)
1919 {
1920     Unit *occ;
1921 
1922     /* Don't report supposed actions by dead units. */
1923     if (!alive(atker))
1924       return;
1925     if (unit->hp2 <= 0) {
1926 	if (unit == mainunit) {
1927 	    report_combat(atker, unit, "destroy");
1928 	} else {
1929 	    report_combat(atker, unit, "destroy-occupant");
1930 	}
1931     } else if (unit->hp2 < unit->hp) {
1932 	if (unit == mainunit) {
1933 	    report_combat(atker, unit, "hit");
1934 	} else {
1935 	    report_combat(atker, unit, "hit-occupant");
1936 	}
1937     } else {
1938 	if (unit == mainunit) {
1939 	    if (fire) {
1940 	    	report_combat(atker, unit, "miss-fire");
1941 	    } else {
1942 	    	report_combat(atker, unit, "miss-attack");
1943 	    }
1944 	} else {
1945 	    report_combat(atker, unit, "miss-occupant");
1946 	}
1947     }
1948     for_all_occupants(unit, occ) {
1949 	report_damage(occ, atker, mainunit, fire);
1950     }
1951 }
1952 
1953 /* Return true if the given unit or one of its occupants has been
1954    damaged. */
1955 
1956 static int
will_report_damage(Unit * unit)1957 will_report_damage(Unit *unit)
1958 {
1959     Unit *occ;
1960 
1961     if (unit->hp2 < unit->hp)
1962       return TRUE;
1963     for_all_occupants(unit, occ) {
1964 	if (will_report_damage(occ))
1965 	  return TRUE;
1966     }
1967     return FALSE;
1968 }
1969 
1970 /* Make the intended damage become real, and do any consequences. */
1971 /* (should include agent unit with hevts if appropriate) */
1972 void
damage_unit(Unit * unit,enum damage_reasons dmgreason,Unit * agent)1973 damage_unit(Unit *unit, enum damage_reasons dmgreason, Unit *agent)
1974 {
1975     int newacp;
1976     HistEventType hevttype;
1977     Obj *dameff;
1978     Unit *occ;
1979     DestructionResult drslt = DESTRUCT_ORDINARY;
1980     int fkillunit = FALSE;
1981     int u = NONUTYPE, u2 = NONUTYPE, t = NONTTYPE, m = NONMTYPE, ms = NONMTYPE;
1982 
1983     assert_error(unit, "Tried to damage a null unit.");
1984     /* Prepare table lookups. */
1985     u = unit->type;
1986     /* (At this point, detonation damage still counts as combat damage.) */
1987 #if (0)
1988     if (dmgreason == combat_dmg) {
1989 	assert_error(agent, "Receiving damage from a null unit?!");
1990 	u2 = agent->type;
1991     }
1992 #endif
1993     if (agent)
1994       u2 = agent->type;
1995     t = terrain_at(unit->x, unit->y);
1996     for_all_material_types(m) {
1997 	if ((unit->supply[m] <= 0) && (um_hp_per_starve(u, m) > 0)) {
1998 	    ms = m;
1999 	    break;
2000 	}
2001     }
2002     /* Process all the occupants first. */
2003     for_all_occupants(unit, occ) {
2004 	damage_unit(occ, dmgreason, agent);
2005     }
2006     /* If no damage was recorded, just return. */
2007     if (unit->hp2 == unit->hp) {
2008 	set_was_detonated(unit, FALSE);
2009 	return;
2010     }
2011     /* If unit is to die, do the consequences. */
2012     if (unit->hp2 <= 0) {
2013 	/* Decide whether the unit should vanish or wreck. */
2014 	drslt = determine_destruction_result(unit);
2015 	switch (drslt) {
2016 	  case DESTRUCT_VANISH:
2017 	    fkillunit = TRUE;
2018 	    break;
2019 	  case DESTRUCT_ORDINARY:
2020 	    fkillunit = (u_wrecked_type(unit->type) == NONUTYPE);
2021 	    if ((dmgreason == starvation_dmg) && is_material_type(ms))
2022 	      fkillunit = fkillunit
2023 			  && (um_wrecked_type_if_starved(u, ms) == NONUTYPE);
2024 	    else if ((dmgreason == combat_dmg) && is_unit_type(u2))
2025 	      fkillunit = fkillunit
2026 			  && (uu_wrecked_type_if_killed(u, u2) == NONUTYPE);
2027 	    else if ((dmgreason == attrition_dmg) && is_terrain_type(t))
2028 	      fkillunit = fkillunit
2029 			  && (ut_wrecked_type_if_attrited(u, t) == NONUTYPE);
2030 	    /* (Could add a case for dying in accidents.) */
2031 	    break;
2032 	  default:
2033 	    fkillunit = TRUE;
2034 	    run_warning("Unknown unit destruction result encountered.");
2035 	} /* switch (drslt) */
2036 	/* Make the unit vanish forthwith. */
2037 	if (fkillunit) {
2038 	    rescue_occupants(unit);
2039 	    switch (dmgreason) {
2040 	      case combat_dmg:
2041 		hevttype = H_UNIT_KILLED;
2042 		break;
2043 	      case accident_dmg:
2044 		hevttype = H_UNIT_DIED_IN_ACCIDENT;
2045 		break;
2046 	      case attrition_dmg:
2047 		hevttype = H_UNIT_DIED_FROM_ATTRITION;
2048 		break;
2049 	      case starvation_dmg:
2050 		hevttype = H_UNIT_STARVED;
2051 		break;
2052 	      default:
2053 		hevttype = (HistEventType)0;
2054 	    }
2055 	    kill_unit(unit, hevttype);
2056 	/* Wreck the unit. */
2057 	} else {
2058 	    switch (dmgreason) {
2059 	      case combat_dmg:
2060 		hevttype = H_UNIT_WRECKED;
2061 		wreck_unit(unit, hevttype, WRECK_TYPE_KILLED, u2, agent);
2062 		break;
2063 	      case accident_dmg:
2064 		hevttype = H_UNIT_WRECKED_IN_ACCIDENT;
2065 		wreck_unit(unit, hevttype, WRECK_TYPE_UNSPECIFIED, -1, NULL);
2066 		break;
2067 	      case attrition_dmg:
2068 		hevttype = H_UNIT_WRECKED_FROM_ATTRITION;
2069 		wreck_unit(unit, hevttype, WRECK_TYPE_ATTRITED, t, NULL);
2070 		break;
2071 	      case starvation_dmg:
2072 		hevttype = H_UNIT_STARVED;
2073 		wreck_unit(unit, hevttype, WRECK_TYPE_STARVED, ms, NULL);
2074 		break;
2075 	      default:
2076 		hevttype = (HistEventType)0;
2077 		wreck_unit(unit, hevttype, WRECK_TYPE_UNSPECIFIED, -1, NULL);
2078 	    }
2079 	}
2080     } else {
2081 	record_event(H_UNIT_DAMAGED, add_side_to_set(unit->side, NOSIDES),
2082 		     unit->id, unit->hp, unit->hp2);
2083 	/* Change the unit's hp. */
2084 	unit->hp = unit->hp2;
2085 	/* Perhaps adjust the acp down. */
2086 	if (unit->act != NULL
2087 	    && unit->act->acp > 0
2088 	    && (dameff = u_acp_damage_effect(unit->type)) != lispnil) {
2089 	    newacp = damaged_acp(unit, dameff);
2090 	    /* The damaged acp limits the remaining acp, rather than trying
2091 	       to do some sort of proportional adjustment, which would be
2092 	       hard to get right. */
2093 	    /* (should account for occupant effects on acp) */
2094 	    unit->act->acp = min(unit->act->acp, newacp);
2095 	}
2096     }
2097     /* Clear any detonation flag that might have been set. */
2098     if (alive(unit))
2099       set_was_detonated(unit, FALSE);
2100     /* Let the unit's owner know about all this. */
2101     update_unit_display(unit->side, unit, TRUE);
2102 }
2103 
2104 /* Figure out what the result of destroying the unit is. */
2105 
2106 static DestructionResult
determine_destruction_result(Unit * unit)2107 determine_destruction_result (Unit *unit)
2108 {
2109     DestructionResult drslt = DESTRUCT_ORDINARY;
2110     int u = NONUTYPE;
2111     Obj *choice = NULL, *chtype = NULL;
2112     int weightstotal = 0;
2113 
2114     assert_error(unit, "Tried to manipulate a null unit.");
2115     u = unit->type;
2116     if (!completed(unit))
2117       return DESTRUCT_VANISH;
2118     if (lispnil != u_destruction_result(u)) {
2119 	choice = choose_from_weighted_list(u_destruction_result(u),
2120 					   &weightstotal, FALSE);
2121 	chtype = consp(choice) ? car(choice) : choice;
2122 	/* Make the unit unconditionally vanish. */
2123 	if (match_keyword(chtype, K_VANISH)) {
2124 	    drslt = DESTRUCT_VANISH;
2125 	}
2126 	/* Lookup the result in the appropriate table. */
2127 	else if ((lispnil == chtype) || match_keyword(chtype, K_TABLE)) {
2128 	    /* Use the ordinary result. */
2129 	}
2130 	else
2131 	  run_warning("Unknown destruction result encountered.");
2132     }
2133     return drslt;
2134 }
2135 
2136 /* Occupants may be able to avoid the fate of their transport. */
2137 
2138 void
rescue_occupants(Unit * unit)2139 rescue_occupants(Unit *unit)
2140 {
2141     Unit *occ;
2142 
2143     for_all_occupants(unit, occ) {
2144 	if (probability(uu_occ_escape(unit->type, occ->type))) {
2145 	    rescue_one_occupant(occ);
2146 	}
2147     }
2148 }
2149 
2150 static void
rescue_one_occupant(Unit * occ)2151 rescue_one_occupant(Unit *occ)
2152 {
2153     int rslt, dir, tmp, nx, ny;
2154     Unit *other;
2155 
2156     /* Try to escape into another unit in this cell. */
2157     for_all_stack(occ->x, occ->y, other) {
2158 	if (other != occ->transport) {
2159 	    rslt = check_enter_action(occ, occ, other);
2160 	    if (valid(rslt)) {
2161 		do_enter_action(occ, occ, other);
2162 		return;
2163 	    }
2164 	}
2165     }
2166     /* Try to move into an adjacent cell. */
2167     for_all_directions_randomly(dir, tmp) {
2168 	if (interior_point_in_dir(occ->x, occ->y, dir, &nx, &ny)) {
2169 	    if (retreat_in_dir(occ, dir))
2170 	      return;
2171 	}
2172     }
2173 }
2174 
2175 /* Retreat is a special kind of movement that a unit uses to avoid
2176    damage during combat. It bypasses some of the normal move rules. */
2177 
2178 static int
retreat_unit(Unit * unit,Unit * atker)2179 retreat_unit(Unit *unit, Unit *atker)
2180 {
2181     int dir;
2182     extern int retreating_from;
2183 
2184     /* First check that this type is able to retreat. */
2185     if (unit->act == NULL || !mobile(unit->type))
2186       return FALSE;
2187     retreating_from = atker->type;
2188     if (unit->x == atker->x && unit->y == atker->y) {
2189     	dir = random_dir();
2190     } else {
2191     	dir = approx_dir(unit->x - atker->x, unit->y - atker->y);
2192     }
2193     if (retreat_in_dir(unit, dir))
2194       return TRUE;
2195     if (flip_coin()) {
2196     	if (retreat_in_dir(unit, left_dir(dir)))
2197     	  return TRUE;
2198     	if (retreat_in_dir(unit, right_dir(dir)))
2199     	  return TRUE;
2200     } else {
2201     	if (retreat_in_dir(unit, right_dir(dir)))
2202     	  return TRUE;
2203     	if (retreat_in_dir(unit, left_dir(dir)))
2204     	  return TRUE;
2205     }
2206     retreating_from = NONUTYPE;
2207     return FALSE;
2208 }
2209 
2210 /* Try to beat a retreat in the given direction. */
2211 
2212 static int
retreat_in_dir(Unit * unit,int dir)2213 retreat_in_dir(Unit *unit, int dir)
2214 {
2215     int nx, ny, rslt;
2216     Unit *other;
2217     extern int retreating;
2218     extern int retreating_from;
2219 
2220     /* (should it be possible for a unit to retreat out of the world?) */
2221     if (!interior_point_in_dir(unit->x, unit->y, dir, &nx, &ny))
2222       return FALSE;
2223     retreating = TRUE;
2224     rslt = check_move_action(unit, unit, nx, ny, unit->z);
2225     if (valid(rslt)) {
2226 	unit->act->acp += uu_acp_retreat(unit->type, retreating_from);
2227 	do_move_action(unit, unit, nx, ny, unit->z);
2228 	retreating = FALSE;
2229 	retreating_from = NONUTYPE;
2230 	return TRUE;
2231     }
2232     /* No luck moving; see if there's a friendly unit to enter. */
2233     for_all_stack(nx, ny, other) {
2234 	rslt = check_enter_action(unit, unit, other);
2235 	if (valid(rslt)) {
2236 	    unit->act->acp += uu_acp_retreat(unit->type, retreating_from);
2237 	    do_enter_action(unit, unit, other);
2238 	    retreating = FALSE;
2239 	    retreating_from = NONUTYPE;
2240 	    return TRUE;
2241 	}
2242     }
2243     return FALSE;
2244 }
2245 
2246 /* Capture action. */
2247 
2248 /* Prepare a capture action to be executed later. */
2249 
2250 int
prep_capture_action(Unit * unit,Unit * unit2,Unit * unit3)2251 prep_capture_action(Unit *unit, Unit *unit2, Unit *unit3)
2252 {
2253     if (unit == NULL || unit->act == NULL || unit2 == NULL)
2254       return FALSE;
2255     unit->act->nextaction.type = ACTION_CAPTURE;
2256     unit->act->nextaction.args[0] = unit3->id;
2257     unit->act->nextaction.actee = unit2->id;
2258     return TRUE;
2259 }
2260 
2261 /* Execute a capture action. */
2262 
2263 int
do_capture_action(Unit * unit,Unit * unit2,Unit * unit3)2264 do_capture_action(Unit *unit, Unit *unit2, Unit *unit3)
2265 {
2266     int rslt;
2267 
2268     attempt_to_capture_unit(unit2, unit3);
2269     use_up_acp(unit, uu_acp_to_capture(unit2->type, unit3->type));
2270     if (unit3->side == unit2->side)
2271       rslt = A_CAPTURE_SUCCEEDED;
2272     else
2273       rslt = A_CAPTURE_FAILED;
2274     return rslt;
2275 }
2276 
2277 /* Check the validity of a capture action. */
2278 
2279 int
check_capture_action(Unit * unit,Unit * unit2,Unit * unit3)2280 check_capture_action(Unit *unit, Unit *unit2, Unit *unit3)
2281 {
2282     int rslt = A_ANY_OK;
2283 
2284     /* In combat model 1, we can't capture units directly. */
2285     if (g_combat_model() == 1)
2286       return A_ANY_ERROR;
2287     if (!in_play(unit3))
2288       return A_ANY_ERROR;
2289     if (!valid(rslt = can_capture(unit, unit2, unit3->type, unit3->side)))
2290       return rslt;
2291     /* We can't capture ourselves. */
2292     if (unit2 == unit3)
2293       return A_ANY_ERROR;
2294     if (distance(unit2->x, unit2->y, unit3->x, unit3->y) > 1)
2295       return A_ANY_TOO_FAR;
2296     return A_ANY_OK;
2297 }
2298 
2299 /* Handle capture possibility and repulse/slaughter. */
2300 
2301 /* The chance to capture an enemy is modified by several factors.
2302    Neutrals have a different chance to be captured, and presence of
2303    occupants should also has an effect.  Can't capture anything that is
2304    on a kind of terrain that the capturer can't go on, unless victim has
2305    "bridge effect". */
2306 
2307 /* (Need a little better treatment of committed assaults, where lack of
2308    success == death.) */
2309 
2310 static void
attempt_to_capture_unit(Unit * atker,Unit * other)2311 attempt_to_capture_unit(Unit *atker, Unit *other)
2312 {
2313     int a = atker->type, o = other->type, chance, prot;
2314     int ox = other->x, oy = other->y;
2315     Unit *occ, *unit2;
2316     Side *as = atker->side, *os = other->side;
2317 
2318     /* Low-tech sides are not going to succeed at even touching high-tech
2319        types, let alone capturing them. */
2320     if (atker->side
2321 	&& atker->side->tech[o] < u_tech_to_own(o))
2322       return;
2323     chance = capture_chance(a, o, other->side);
2324     if (alive(atker) && alive(other) && chance > 0) {
2325 	if (impassable(atker, ox, oy) && !uu_bridge(o, a))
2326 	  return;
2327 	/* Can possibly detonate on *any* attempt to capture! */
2328 	if (probability(uu_detonate_on_capture(o, a))
2329 	    && !was_detonated(other)) {
2330 	    detonate_unit(other, other->x, other->y, other->z);
2331 	    /* Might not be possible to capture anything anymore. */
2332 	    if (!alive(atker) || !alive(other))
2333 	      return;
2334 	    /* Types of units might have changed, recalc things. */
2335 	    a = atker->type;  o = other->type;
2336 	    as = atker->side;  os = other->side;
2337 	    chance = capture_chance(a, o, other->side);
2338 	}
2339 	/* Occupants can protect the transport. */
2340 	for_all_occupants(other, occ) {
2341 	    if (is_active(occ)) {
2342 		if (g_prot_resists_capture()) {
2343 	    	    prot = uu_protection(occ->type, o);
2344 		    if (prot != 100)
2345 		      chance = (chance * prot) / 100;
2346 		}
2347 		prot = uu_occ_allows_capture_by(occ->type, a);
2348 	    	if (prot != 100)
2349 		  chance = (chance * prot) / 100;
2350 		prot = uu_occ_allows_capture_of(occ->type, o);
2351 	    	if (prot != 100)
2352 		  chance = (chance * prot) / 100;
2353 	    }
2354 	}
2355 	/* Neighbors can protect neighbors. */
2356 	for_all_stack(other->x, other->y, unit2) {
2357 	    if (unit2 != other
2358 		&& in_play(unit2)
2359 		&& completed(unit2)
2360 		&& unit2->side == other->side) {
2361 		if (g_prot_resists_capture()) {
2362 		    prot = uu_stack_protection(unit2->type, o);
2363 		    if (prot != 100)
2364 		      chance = (chance * prot) / 100;
2365 		}
2366 		prot = uu_stack_neighbor_allows_capture_by(unit2->type, a);
2367 		if (prot != 100)
2368 		  chance = (chance * prot) / 100;
2369 		prot = uu_stack_neighbor_allows_capture_of(unit2->type, o);
2370 		if (prot != 100)
2371 		  chance = (chance * prot) / 100;
2372 	    }
2373 	}
2374 	/* Note that this code differs from that above in that it
2375 	   treats all units in the same cell equally, whether occs,
2376 	   suboccs or part of the stack. This also means that one occ
2377 	   can protect another occ in the same transport. Moreover,
2378 	   the protective unit also protects itself. These rules
2379 	   simulate real situations such as when triple-A protects all
2380 	   nearby units (including itself) against bombers, or when a
2381 	   city wall protects all other occupants against ground
2382 	   attack. */
2383 	for_all_stack_with_occs(other->x, other->y, unit2) {
2384 	    if (is_active(unit2)
2385 		/* We also extend protection to our buddies! */
2386 		&& trusted_side(unit2->side, other->side)) {
2387 		/* This is when a unit, such as triple-A, provides
2388 		   unique protection against a specific attacker, such
2389 		   as bombers, to all other units in the cell. */
2390 		if (g_prot_resists_capture()) {
2391 		    prot = uu_cellwide_protection_against(unit2->type, a);
2392 		    if (prot != 100)
2393 		      chance = (chance * prot) / 100;
2394 		}
2395 		prot = uu_any_neighbor_allows_capture_by(unit2->type, a);
2396 		if (prot != 100)
2397 		  chance = (chance * prot) / 100;
2398 		/* This is when a unit (such as a garrison)
2399 		   specifically protects a second unit, such as a fort
2400 		   (but not other nearby units), against all forms of
2401 		   attack. It thus works the same way as uu_protection
2402 		   and uu_stack_protection. */
2403 		if (g_prot_resists_capture()) {
2404 		    prot = uu_cellwide_protection_for(unit2->type, o);
2405 		    if (prot != 100)
2406 		      chance = (chance * prot) / 100;
2407 		}
2408 		prot = uu_any_neighbor_allows_capture_of(unit2->type, o);
2409 		if (prot != 100)
2410 		  chance = (chance * prot) / 100;
2411 	    }
2412 	}
2413 	/* Test whether the capture actually happens. */
2414 	if (probability(chance)) {
2415 	    capture_unit(atker, other, H_UNIT_CAPTURED);
2416 	} else if (atker->transport != NULL &&
2417 		   (impassable(atker, ox, oy) ||
2418 		    impassable(atker, atker->x, atker->y))) {
2419 	    /* was the capture attempt a one-way trip? */
2420 	    /* (should fix the test above - needs to be more accurate) */
2421 	    report_combat(atker, other, "resist/slaughter");
2422 	    kill_unit(atker,
2423 		      H_UNIT_KILLED /* should be something appropriate */);
2424 	} else {
2425 	    report_combat(atker, other, "resist");
2426 	    /* (should record failed attempt to capture?) */
2427 	}
2428 	if (chance > 0) {
2429 	    if (atker->cxp < u_cxp_max(a))
2430 	      atker->cxp += uu_cxp_per_capture(a, o);
2431 	    /* (should not increment if side just changed?) */
2432 	    if (other->cxp < u_cxp_max(o))
2433 	      other->cxp += uu_cxp_per_capture(o, a);
2434 
2435 	}
2436     }
2437 }
2438 
2439 /* There are many consequences of a unit being captured. */
2440 
2441 void
capture_unit(Unit * unit,Unit * pris,int captype)2442 capture_unit(Unit *unit, Unit *pris, int captype)
2443 {
2444     int u = unit->type, px = pris->x, py = pris->y;
2445     Unit *occ;
2446     Side *ps = pris->side, *us = unit->side, *newside;
2447     int newtype = NONUTYPE;
2448     int m = NONMTYPE;
2449     int gain = 0, loss = 0;
2450 
2451     newside = unit->side;
2452     /* Return a unit to its original side if we are buds with that side. */
2453     if (pris->origside != newside && trusted_side(us, pris->origside))
2454       newside = pris->origside;
2455     /* Attempt to scuttle. */
2456     if (probability(uu_scuttle(pris->type, u))) {
2457 	/* (should add terrain effect on success too) */
2458 	/* (should characterize as a scuttle) */
2459 	kill_unit(pris, H_UNIT_DISBANDED);
2460     }
2461     /* Attempt to change type if we are supposed to do so on capture. */
2462     /* If new type cannot be on new side, then the unit must die. */
2463     newtype = uu_changed_type_if_captured(pris->type, u);
2464     if (NONUTYPE != newtype) {
2465 	if (!type_allowed_on_side(newtype, newside))
2466 	  kill_unit(pris, H_UNIT_KILLED);
2467 	else
2468 	  change_unit_type(pris, newtype, H_UNIT_TYPE_CHANGED, newside);
2469     }
2470     /* If prisoner is not allowed on side, then make it go away. */
2471     if (!unit_allowed_on_side(pris, newside)) {
2472 	kill_unit(pris, H_UNIT_KILLED);
2473     }
2474     /* Properly report capture outcome. */
2475     if (alive(pris)) {
2476 	if (newside == pris->origside) {
2477 	    report_combat(unit, pris, "liberate");
2478 	} else {
2479 	    report_combat(unit, pris, "capture");
2480 	}
2481 	/* Decide the fate of each occupant of our prisoner. */
2482 	for_all_occupants(pris, occ) {
2483 	    /* Don't try to capture occs from trusted sides. */
2484 	    if (trusted_side(us, occ->side))
2485 	      continue;
2486 	    capture_occupant(unit, pris, occ, newside);
2487 	}
2488 	/* Treasury bonus and penalty due to unit capture */
2489 	for_all_material_types(m) {
2490 	    if (side_has_treasury(unit->side, m)) {
2491 		gain = um_treasury_gain_per_capture(unit->type, m);
2492 		unit->side->treasury[m] += gain;
2493 		/* Clip treasury to bounds, if necessary. */
2494 		unit->side->treasury[m] =
2495 		    min(unit->side->treasury[m], g_treasury_size());
2496 		unit->side->treasury[m] = max(unit->side->treasury[m], 0);
2497 	    }
2498 	    if (side_has_treasury(pris->side, m)) {
2499 		loss = um_treasury_loss_per_captured(pris->type, m);
2500 		pris->side->treasury[m] -= loss;
2501 		/* Clip treasury to bounds, if necessary. */
2502 		pris->side->treasury[m] =
2503 		    min(pris->side->treasury[m], g_treasury_size());
2504 		pris->side->treasury[m] = max(pris->side->treasury[m], 0);
2505 	    }
2506 	}
2507 	/* The change of side itself.  This happens recursively to any
2508 	   remaining occupants as well. */
2509 	change_unit_side(pris, newside, captype, unit);
2510 	/* Garrison the newly-captured unit with hp from the capturing unit. */
2511 	garrison_unit(unit, pris);
2512         update_unit_display(unit->side, unit, TRUE);
2513 	capture_unit_2(unit, pris, ps);
2514 	/* The people at the new location may change sides immediately. */
2515 	if (people_sides_defined()
2516 	    && any_people_side_changes
2517 	    && probability(people_surrender_chance(pris->type, px, py))) {
2518 	    change_people_side_around(px, py, pris->type, unit->side);
2519 	}
2520 	if (control_sides_defined()) {
2521 	    if (ut_control_range(pris->type, terrain_at(px, py)) >= 0) {
2522 		change_control_side_around(px, py, pris->type, unit->side);
2523 	    }
2524 	}
2525          kick_out_enemy_users(unit->side, px, py);
2526 	/* Occupy the captured unit if possible. */
2527 	if(valid(check_enter_action(unit, unit, pris))) {
2528 	    do_enter_action(unit, unit, pris);
2529 	/* Else move into the same cell to guard it. */
2530     	} else if (valid(check_move_action(unit, unit, px, py, 0))) {
2531 	    do_move_action(unit, unit, px, py, 0);
2532 	}
2533     }
2534 
2535     /* Update everybody's view of the situation. */
2536     see_exact(ps, px, py);
2537     update_cell_display(ps, px, py, UPDATE_ALWAYS);
2538     all_see_cell(px, py);
2539 }
2540 
2541 /* Given that the main unit is going to be captured, decide what each occupant
2542    will do. */
2543 
2544 static void
capture_occupant(Unit * unit,Unit * pris,Unit * occ,Side * newside)2545 capture_occupant(Unit *unit, Unit *pris, Unit *occ, Side *newside)
2546 {
2547     int u = unit->type, newtype = NONUTYPE;
2548     Unit *subocc;
2549 
2550     /* Side change will actually happen later. */
2551     if (probability(uu_occ_escape(u, occ->type))) {
2552 	/* The occupant escapes, along with all its suboccupants. */
2553 	/* Retreat is not a perfect model, but close enough for now. */
2554 	if (retreat_unit(occ, unit)) {
2555 		/* Only report an escape if successful. */
2556 		report_combat(unit, occ, "escape");
2557     	}
2558     } else if (probability(uu_scuttle(occ->type, u))) {
2559 	/* (should add terrain effect on success too) */
2560 	/* (should characterize as a scuttle) */
2561 	kill_unit(occ, H_UNIT_DISBANDED);
2562     /* Some occs may gracefully switch to their transport's new side. */
2563     } else if (u_match_transport_side(occ->type)) {
2564 	newtype = uu_changed_type_if_captured(occ->type, u);
2565 	if (NONUTYPE != newtype) {
2566 	    if (type_allowed_on_side(newtype, newside))
2567 	      change_unit_type(occ, newtype, H_UNIT_TYPE_CHANGED, newside);
2568 	}
2569 	for_all_occupants(occ, subocc) {
2570 	    capture_occupant(unit, occ, subocc, newside);
2571 	}
2572 	if ((NONUTYPE != newtype) && !type_allowed_on_side(newtype, newside))
2573 	  kill_unit(pris, H_UNIT_KILLED);
2574     /* Other occs may need to be forcefully captured. */
2575     } else if (capture_chance(u, occ->type, occ->side) > 0) {
2576 	/* (TODO: Should use up ACP during capture of occs.) */
2577 	for_all_occupants(occ, subocc) {
2578 	    capture_occupant(unit, occ, subocc, newside);
2579 	}
2580     } else {
2581 	/* Occupant can't live as a prisoner, but suboccs might, so recurse
2582 	   through them. */
2583 	for_all_occupants(occ, subocc) {
2584 	    capture_occupant(unit, occ, subocc, newside);
2585 	}
2586 	/* Any suboccupants that didn't escape will die. */
2587 	/* (what if subocc captured tho? should move elsewhere) */
2588 	kill_unit(occ, H_UNIT_KILLED);
2589     }
2590 }
2591 
2592 /* Do additional consequences of capture. */
2593 
2594 static void
capture_unit_2(Unit * unit,Unit * pris,Side * prevside)2595 capture_unit_2(Unit *unit, Unit *pris, Side *prevside)
2596 {
2597     int chance, x, y, notesee;
2598     Unit *occ, *unit2;
2599     Side *newside;
2600     Unit *checkalways;
2601 
2602     /* Our new unit's experience might be higher or lower, depending on what
2603        capture really means (change of crew perhaps). */
2604     pris->cxp = (pris->cxp * u_cxp_on_capture(pris->type)) / 100;
2605     pris->cxp = min(unit->cxp, u_cxp_max(pris->type));
2606     /* Getting captured is always bad for morale, but getting
2607        liberated is good. */
2608     if (pris->side == pris->origside)
2609       change_morale(pris, 1, ((pris->morale + 1) * 50) + 50);
2610     else
2611       pris->morale = pris->morale / 2;
2612     /* Clear any actions and plans. */
2613     /* Don't use init_unit_actorstate!  We just want to cancel any pending
2614        action, but leave all the acp values untouched. */
2615     if (pris->act)
2616       pris->act->nextaction.type = ACTION_NONE;
2617     /* (should probably adjust side's acp sums by new unit's amounts) */
2618     init_unit_plan(pris);
2619     /* Maybe get a pile of interesting information. */
2620     /* Independent units won't know anything about other independents
2621        though (they're independent, eh?). */
2622     newside = unit->side;
2623     if (newside && !newside->see_all && prevside != indepside) {
2624 	notesee = FALSE;
2625 	chance = u_see_terrain_captured(pris->type);
2626 	if (!g_terrain_seen() && probability(chance)) {
2627 	    for_all_cells(x, y) {
2628 		if (terrain_view(prevside, x, y) != UNSEEN
2629 		    && terrain_view(newside, x, y) == UNSEEN) {
2630 		    set_terrain_view(newside, x, y,
2631 				     terrain_view(prevside, x, y));
2632 
2633 		    /* Now view see-always units. */
2634 		    for_all_stack_with_occs(x, y, checkalways) {
2635 			if (u_see_always(checkalways->type)) {
2636 			    see_exact(newside, x, y);
2637 			    add_cover(newside, x, y, 1);
2638 			}
2639 		    }
2640 
2641 		    update_cell_display(newside, x, y, UPDATE_ALWAYS);
2642 		    notesee = TRUE;
2643 		}
2644 	    }
2645 	}
2646 	if (1 /* any see others chance for this type */) {
2647 	    for_all_side_units(prevside, unit2) {
2648 		if (in_play(unit2)) {
2649 		    chance = uu_see_others_captured(pris->type, unit2->type);
2650 		    if (probability(chance)) {
2651 			x = unit2->x; y = unit2->y;
2652 			see_exact(newside, unit2->x, unit2->y);
2653 			update_cell_display(newside, unit2->x, unit2->y,
2654 					    UPDATE_ALWAYS);
2655 			for_all_stack_with_occs(x, y, checkalways) {
2656 			    if (u_see_always(checkalways->type)) {
2657 				add_cover(newside, x, y, 1);
2658 			    }
2659 			}
2660 			notesee = TRUE;
2661 		    }
2662 		}
2663 	    }
2664 	}
2665 	/* Only say something to the capturing side if we actually got
2666 	   any new information - after several captures, may not be
2667 	   anything new to find out. */
2668 	if (notesee) {
2669 	    notify(newside, "Enemy information fell into your hands!");
2670 	}
2671     }
2672     /* Likewise for occupants. */
2673     for_all_occupants(pris, occ) {
2674 	capture_unit_2(unit, occ, prevside);
2675     }
2676 }
2677 
2678 /* A detonate action just blasts the vicinity indiscriminately. */
2679 
2680 int
prep_detonate_action(Unit * unit,Unit * unit2,int x,int y,int z)2681 prep_detonate_action(Unit *unit, Unit *unit2, int x, int y, int z)
2682 {
2683     if (unit == NULL || unit->act == NULL || unit2 == NULL)
2684       return FALSE;
2685     unit->act->nextaction.type = ACTION_DETONATE;
2686     unit->act->nextaction.args[0] = x;
2687     unit->act->nextaction.args[1] = y;
2688     unit->act->nextaction.args[2] = z;
2689     unit->act->nextaction.actee = unit2->id;
2690     return TRUE;
2691 }
2692 
2693 int
do_detonate_action(Unit * unit,Unit * unit2,int x,int y,int z)2694 do_detonate_action(Unit *unit, Unit *unit2, int x, int y, int z)
2695 {
2696     int u2 = unit2->type;
2697 
2698     detonate_unit(unit2, x, y, z);
2699     /* Note that if the maxrange is further than the actual range of this
2700        detonation, only just-damaged units will be looked at. */
2701     reckon_damage_around(x, y, max_u_detonate_effect_range, unit2);
2702     /* Unit might have detonated outside its range of effect, so need
2703        this to make its own damage is accounted for. */
2704     if (alive(unit2))
2705       reckon_damage_around(unit2->x, unit2->y, 0, unit2);
2706     use_up_acp(unit, u_acp_to_detonate(u2));
2707     return A_ANY_DONE;
2708 }
2709 
2710 int
check_detonate_action(Unit * unit,Unit * unit2,int x,int y,int z)2711 check_detonate_action(Unit *unit, Unit *unit2, int x, int y, int z)
2712 {
2713     int u, u2;
2714     int rslt = A_ANY_OK;
2715 
2716     if (!valid(rslt = can_detonate(unit, unit2)))
2717       return rslt;
2718     if (!inside_area(x, y))
2719       return A_ANY_ERROR;
2720     u = unit->type;
2721     u2 = unit2->type;
2722     /* Can only detonate in our own or an adjacent cell. */
2723     /* (In other words, the detonating unit doesn't get to teleport
2724        its detonation effects to any desired faraway location.) */
2725     if (distance(unit2->x, unit2->y, x, y) > 1)
2726       return A_ANY_TOO_FAR;
2727     return A_ANY_OK;
2728 }
2729 
2730 static int tmpdetx, tmpdety;
2731 
2732 /* Actual detonation may occur by explicit action or automatically; this
2733    routine makes the detonation effects happen, pyrotechnics and all. */
2734 
2735 int
detonate_unit(Unit * unit,int x,int y,int z)2736 detonate_unit(Unit *unit, int x, int y, int z)
2737 {
2738     int u = unit->type, dir, x1, y1, dmg, maxrange;
2739     Unit *unit2;
2740     Side *side;
2741 
2742     if (max_u_detonate_effect_range < 0) {
2743 	int u2, u3, range;
2744 
2745 	for_all_unit_types(u2) {
2746 	    for_all_unit_types(u3) {
2747 		range = uu_detonation_range(u2, u3);
2748 		max_u_detonate_effect_range =
2749 		  max(range, max_u_detonate_effect_range);
2750 	    }
2751 	}
2752     }
2753     if (max_t_detonate_effect_range < 0) {
2754 	int u2, t, range;
2755 
2756 	for_all_unit_types(u2) {
2757 	    for_all_terrain_types(t) {
2758 		range = ut_detonation_range(u2, t);
2759 		max_t_detonate_effect_range =
2760 		  max(range, max_t_detonate_effect_range);
2761 	    }
2762 	}
2763     }
2764     report_combat(unit, NULL, "detonate");
2765     for_all_sides(side) {
2766     	if (active_display(side)
2767 	    && (side_sees_unit(side, unit)
2768 		|| units_visible(side, unit->x, unit->y))) {
2769 	    schedule_movie(side, "flash", unit->x, unit->y);
2770 	    /* a hack */
2771 	    if (strstr(u_type_name(u), "nuclear")
2772 		|| strstr(u_type_name(u), "nuke"))
2773 	      schedule_movie(side, "nuke", x, y);
2774     	}
2775     }
2776     set_was_detonated(unit, TRUE);
2777     /* Hit the detonating unit first. */
2778     hit_unit_with_detonation(unit, u_hp_per_detonation(u), NULL);
2779     /* Hit units at ground zero. */
2780     for_all_stack(x, y, unit2) {
2781     	if (unit2 != unit) {
2782 	    hit_unit_with_detonation(unit2,
2783 				     uu_detonation_damage_at(u, unit2->type),
2784 				     unit);
2785 	}
2786     }
2787     damage_terrain(u, x, y);
2788     /* Hit units and/or terrain in adjacent cells, if this is defined. */
2789     if (max_u_detonate_effect_range >= 1) {
2790         for_all_directions(dir) {
2791 	    if (interior_point_in_dir(x, y, dir, &x1, &y1)) {
2792 		for_all_stack(x1, y1, unit2) {
2793 		    if (0 >= uu_detonation_range(u, unit2->type))
2794 		      continue;
2795 		    dmg = uu_detonation_damage_adj(u, unit2->type);
2796 		    hit_unit_with_detonation(unit2, dmg, unit);
2797 		}
2798 	    }
2799 	}
2800     }
2801     if (max_t_detonate_effect_range >= 1) {
2802         for_all_directions(dir) {
2803 	    if (point_in_dir(x, y, dir, &x1, &y1)) {
2804 		if (0 >= ut_detonation_range(u, terrain_at(x1, y1)))
2805 		  continue;
2806 		damage_terrain(u, x1, y1);
2807 	    }
2808 	}
2809     }
2810     /* Hit units that are further away. */
2811     maxrange = max(max_u_detonate_effect_range, max_t_detonate_effect_range);
2812     if (maxrange >= 2) {
2813 	tmpunit = unit;
2814 	tmpdetx = x;  tmpdety = y;
2815 	apply_to_area(x, y, maxrange, detonate_on_cell);
2816     }
2817     /* (should test compatibility of any new terrain types with each other;
2818         only after changes over with) */
2819     /* Entertain everybody. */
2820     play_movies(ALLSIDES);
2821     return TRUE;
2822 }
2823 
2824 static void
detonate_on_cell(int x,int y)2825 detonate_on_cell(int x, int y)
2826 {
2827     int dist, dmg, sdmg;
2828     Unit *unit2;
2829 
2830     dist = distance(tmpdetx, tmpdety, x, y);
2831     if (dist > 1 && dist <= max_u_detonate_effect_range) {
2832 	/* Since this code bypasses the occ recursion in
2833 	   maybe_hit_unit, we should also hit all occupants directly
2834 	   with the blast. */
2835 	for_all_stack_with_occs(x, y, unit2) {
2836 	    if (dist <= uu_detonation_range(tmpunit->type, unit2->type)) {
2837 		dmg = uu_detonation_damage_adj(tmpunit->type, unit2->type);
2838 		/* Reduce by inverse square of the distance. */
2839 		sdmg = (dmg * 100) / (dist * dist);
2840 		dmg = prob_fraction(sdmg);
2841 		hit_unit_with_detonation(unit2, dmg, tmpunit);
2842 	    }
2843 	}
2844     }
2845     if (dist > 1
2846 	&& dist <= ut_detonation_range(tmpunit->type, terrain_at(x, y))) {
2847 	damage_terrain(tmpunit->type, x, y);
2848     }
2849 }
2850 
2851 static void
hit_unit_with_detonation(Unit * unit,int hit,Unit * atker)2852 hit_unit_with_detonation(Unit *unit, int hit, Unit *atker)
2853 {
2854     char *hitmovietype;
2855     Side *side;
2856 
2857     hit_unit(unit, hit, atker);
2858     for_all_sides(side) {
2859     	if (active_display(side)
2860 	    /* (should figure out visibility rules) */
2861 	    && (g_see_all()
2862 	        || side == unit->side
2863 	        || 0 /* visible to other sides */)) {
2864 	    hitmovietype = (char *)((hit >= unit->hp) ? "death" :
2865 			    ((hit > 0) ? "hit" : "miss"));
2866 	    schedule_movie(side, hitmovietype, unit->id);
2867     	}
2868     }
2869 }
2870 
2871 /* Do the effect of detonation on the terrain at the given location. */
2872 
2873 void
damage_terrain(int u,int x,int y)2874 damage_terrain(int u, int x, int y)
2875 {
2876     int t, t2, dir;
2877 
2878     /* Damage the cell's terrain. */
2879     t = terrain_at(x, y);
2880     if (probability(ut_detonation_damage(u, t))) {
2881 	t2 = damaged_terrain_type(t);
2882 	if (t2 == NONTTYPE) {
2883 	    run_warning(
2884 "Possibly invalid damaged terrain type from undamaged terrain type '%s'.",
2885 			t_type_name(t));
2886 	    return;
2887 	} else if (t2 != t) {
2888 	    change_terrain_type(x, y, t2);
2889 	}
2890     }
2891     /* Apply to auxiliary terrain also. */
2892     if (1 /* if any aux terrain */) {
2893 	for_all_terrain_types(t) {
2894 	    switch (t_subtype(t)) {
2895 	      case cellsubtype:
2896 		/* We already did this one. */
2897 	        break;
2898 	      case bordersubtype:
2899 		if (1 /* any damage possible */) {
2900 		    for_all_directions(dir) {
2901 			if (border_at(x, y, dir, t)
2902 			    && probability(ut_detonation_damage(u, t))) {
2903 			    t2 = damaged_terrain_type(t);
2904 			    if (t2 == NONTTYPE) {
2905 				set_border_at(x, y, dir, t, FALSE);
2906 			    } else if (t2 != t) {
2907 				set_border_at(x, y, dir, t, FALSE);
2908 				set_border_at(x, y, dir, t2, TRUE);
2909 				/* There is potentially a problem with
2910 				   some game designs here; if the new
2911 				   type t2 can also be damaged by the
2912 				   detonation, then the loop here will
2913 				   damage it in turn, at least if t2
2914 				   *follows* t in the list of terrain
2915 				   types.  Preventing this would
2916 				   require a lot of buffering, so it's
2917 				   left as a limitation for now. */
2918 			    }
2919 			}
2920 		    }
2921 		}
2922 	        break;
2923 	      case connectionsubtype:
2924 		if (1 /* any damage possible */) {
2925 		    for_all_directions(dir) {
2926 			if (connection_at(x, y, dir, t)
2927 			    && probability(ut_detonation_damage(u, t))) {
2928 			    t2 = damaged_terrain_type(t);
2929 			    if (t2 == NONTTYPE) {
2930 				set_connection_at(x, y, dir, t, FALSE);
2931 			    } else if (t2 != t) {
2932 				set_connection_at(x, y, dir, t, FALSE);
2933 				set_connection_at(x, y, dir, t2, TRUE);
2934 				/* Same issue here as with border
2935                                    damage. */
2936 			    }
2937 			}
2938 		    }
2939 		}
2940 	        break;
2941 	      case coatingsubtype:
2942 		/* don't know how to damage coatings yet */
2943 	        break;
2944 	    }
2945 	}
2946     }
2947 }
2948 
2949 int
damaged_terrain_type(int t)2950 damaged_terrain_type(int t)
2951 {
2952     int t2, tot, othertot, test, sum, rslt;
2953 
2954     tot = othertot = 0;
2955     for_all_terrain_types(t2) {
2956 	if (t_subtype(t2) == t_subtype(t)) {
2957 	    tot += tt_damaged_type(t, t2);
2958 	} else if (t_subtype(t) != cellsubtype) {
2959 	    othertot += tt_damaged_type(t, t2);
2960 	}
2961     }
2962     rslt = NONTTYPE;
2963     if ((tot + othertot) > 0) {
2964     	test = xrandom(tot + othertot);
2965     	sum = 0;
2966     	for_all_terrain_types(t2) {
2967 	    if (t_subtype(t2) == t_subtype(t)) {
2968 	    	sum += tt_damaged_type(t, t2);
2969 		if (test < sum) {
2970 		    rslt = t2;
2971 		    break;
2972 		}
2973 	    }
2974     	}
2975     }
2976     /* Random values between tot and othertot will have
2977        fallen through the loop, and the rslt is NONTTYPE,
2978        which indicates that the terrain must be removed
2979        if possible. */
2980     /* Paranoia check */
2981     if (rslt != NONTTYPE && t_subtype(rslt) != t_subtype(t))
2982       run_error("badness in damaged_terrain_type");
2983     return rslt;
2984 }
2985 
2986 /* True if unit has enough occupants assigned to its defense. */
2987 
2988 int
defended_by_occupants(Unit * unit)2989 defended_by_occupants(Unit *unit)
2990 {
2991     Unit *unit2;
2992     int defenders = 0;
2993 
2994     for_all_occupants(unit, unit2) {
2995 	if (is_active(unit2)
2996 	    && unit2->plan
2997 	    && unit2->plan->maingoal
2998 	    && unit2->plan->maingoal->type == GOAL_UNIT_OCCUPIED
2999 	    && unit2->plan->maingoal->args[0] == unit->id
3000 	    /* Occs that cannot defend the transport should not be
3001 	       assigned to occupy it, but check anyway for ability to
3002 	       protect. */
3003 	    && occ_can_defend_transport(unit2->type, unit->type)) {
3004 	    ++defenders;
3005 	}
3006     }
3007     if (enough_to_garrison(unit, defenders))
3008       return TRUE;
3009     else
3010       return FALSE;
3011 }
3012 
3013 /* True if first type can both occupy and protect second type. */
3014 
3015 int
occ_can_defend_transport(int o,int t)3016 occ_can_defend_transport(int o, int t)
3017 {
3018 	/* Never true if transport cannot carry occupant. */
3019 	if (!could_carry(t, o))
3020 	    return FALSE;
3021 	if (g_combat_model() == 0) {
3022 		/* Specific protection of transport by its occupant.
3023 		Note: zero protection is 100, full protection is 0! */
3024 		if (uu_protection(o, t) < 100)
3025 		    return TRUE;
3026 		/* Cellwide protection of all units by occupant. */
3027 		if (uu_cellwide_protection_for(o, t) < 100)
3028 		    return TRUE;
3029 	} else if (g_combat_model() == 1) {
3030 		/* Advanced units are protected by any kind of occupant
3031 		that has a positive defense value. */
3032 		 if (u_advanced(t) && u_defend(o) > 0) {
3033 			return TRUE;
3034 		/* Non-advanced units are protected by this table. */
3035 		} else if (!u_advanced(t)
3036 			    /*	Note: More than 100 is protection. */
3037 			     && uu_occ_affects_defense(o, t) > 100) {
3038 			return TRUE;
3039 		}
3040 	}
3041 	return FALSE;
3042 }
3043 
3044 /* True if the specified number of defenders is sufficient to defend
3045    the unit. Note that this garrison does not have to exist! */
3046 
3047 int
enough_to_garrison(Unit * unit,int defenders)3048 enough_to_garrison(Unit *unit, int defenders)
3049 {
3050     int u = unit->type;
3051     Unit *unit2;
3052 
3053     /* We only worry about enemies within our tactical range. */
3054     unit2 = mobile_enemy_threat(unit, u_ai_enemy_alert_range(u));
3055     /* We are threatened by the enemy! */
3056     if (unit2 && defenders < u_ai_war_garrison(u))
3057       return FALSE;
3058     else if (defenders < u_ai_peace_garrison(u))
3059       /* No enemy in sight. */
3060       return FALSE;
3061     else
3062       return TRUE;
3063 }
3064 
3065 /* Returns the first mobile enemy unit found within the specified
3066    range that can hit or capture our unit. */
3067 
3068 Unit *
mobile_enemy_threat(Unit * unit,int range)3069 mobile_enemy_threat(Unit *unit, int range)
3070 {
3071     int x, y;
3072     Unit *unit2;
3073 
3074     /* Go through all cells within the specified range. */
3075     for_all_cells_within_range(unit->x, unit->y, range, x, y) {
3076 	if (!inside_area(x, y))
3077 	  continue;
3078 	if (!terrain_visible(unit->side, x, y))
3079 	  continue;
3080 	/* Important to count also occupants here. */
3081 	for_all_stack_with_occs(x, y, unit2) {
3082 	    /* Only count visible mobile enemy units that actually
3083 	       threaten us. */
3084 	    if (is_active(unit2)
3085 		/* The NULL side rarely attacks anybody :-) */
3086 		&& unit2->side
3087 		&& mobile(unit2->type)
3088 		&& side_sees_image(unit->side, unit2)
3089 		&& !trusted_side(unit->side, unit2->side)
3090 		&& (could_hit(unit2->type, unit->type)
3091 		    || capture_chance(unit2->type, unit->type, unit->side) > 0)) {
3092 		return unit2;
3093 	    }
3094 	}
3095     }
3096     return NULL;
3097 }
3098 
3099