1 /* Unit and Unit Type Analysis and Status Functions for AIs
2    Copyright (C) 2005 Eric A. McDonald.
3 
4 Xconq is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.  See the file COPYING.  */
8 
9 /*! \file
10     \brief Unit and Unit Type Analysis and Status Function for AIs
11 
12     Part of the AI API, Level 1.
13 
14     Provides useful functions that an AI implementation may use to analyze
15     and to learn the status of units and unit types.
16 
17     The functions in this file provide information regarding units and
18     unit types that is not directly available from the kernel functions,
19     but is useful for decision-making.
20 
21     There are various kinds of functions in this file.
22     'can_*' functions test an unit's inclusive-or side's current state to
23     see if a given type of action or meta-action can be performed.
24     'could_*' functions disregard current state, and ask hypothetical
25     questions based on type. These functions can be regarded as lower level
26     than the 'can_*' functions.
27 
28     \note Nothing in this file should be required for AI implementation.
29     \todo Import most of the functions in 'aiutil.c' into this file.
30     \todo Make use of caching, where applicable.
31 
32 */
33 
34 #include "conq.h"
35 #include "kernel.h"
36 #include "aiunit.h"
37 
38 //! Could u see?
39 
40 int
could_see(int u)41 could_see(int u)
42 {
43     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
44     if (0 > u_vision_range(u))
45       return FALSE;
46     return TRUE;
47 }
48 
49 int
can_be_on(int u,Side * side,int x,int y,int * p_without)50 can_be_on(int u, Side *side, int x, int y, int *p_without)
51 {
52     static int *p_ucapx;
53 
54     int tv = UNSEEN;
55     int t = NONTTYPE;
56     UnitView *uvstack = NULL, *uview = NULL;
57     int sztot = 0;
58     int u2 = NONUTYPE;
59 
60     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
61     assert_error(side, "Attempted to access a NULL side");
62     /* Cannot be outside playing area. */
63     if (!inside_area(x, y))
64       return A_MOVE_CANNOT_LEAVE_WORLD;
65     /* Acquire side's terrain view. */
66     tv = terrain_view(side, x, y);
67     /* If cell is unseen, we assume we can be there. */
68     if (UNSEEN == tv)
69       return A_ANY_OK;
70     /* Convert view to ttype. */
71     t = vterrain(tv);
72     /* Could cell ever hold utype? */
73     if (!could_be_on(u, t))
74       /* (Should return A_ANY_TOO_LARGE.) */
75       return A_ANY_CANNOT_DO;
76     // Initialize extra-capcity array, if necessary.
77     if (!p_ucapx)
78 	p_ucapx = (int *)xmalloc(numutypes * sizeof(int));
79     for_all_unit_types(u2)
80 	p_ucapx[u2] = ut_capacity_x(u2, t);
81     // Fake capacities for exclusions.
82     if (p_without) {
83 	for_all_unit_types(u2) {
84 	    if (0 < ut_capacity_x(u2, t)) {
85 		p_ucapx[u2] += min(p_without[u2], ut_capacity_x(u2, t));
86 		p_without[u2] = max(0, p_without[u2] - ut_capacity_x(u2, t));
87 	    }
88 	    sztot -= min(p_without[u2] * ut_size(u2, t), t_capacity(t));
89 	}
90     }
91     /* Can cell hold utype given the uvstack there? */
92     if (g_see_all() || side->see_all)
93       uvstack = query_uvstack_at(x, y);
94     else
95       uvstack = unit_view_at(side, x, y);
96     for_all_uvstack(uvstack, uview) {
97 	u2 = uview->type;
98 	if (0 < p_ucapx[u2])
99 	  --p_ucapx[u2];
100 	else {
101 	    sztot += ut_size(u2, t);
102 	    if (sztot >= t_capacity(t))
103 	      return A_MOVE_DEST_FULL;
104 	}
105     }
106     sztot += ut_size(u, t);
107     if (!p_ucapx[u] && (sztot > t_capacity(t)))
108       return A_MOVE_DEST_FULL;
109     // TODO: Consider all known blocking ZOCs?
110     return A_ANY_OK;
111 }
112 
113 int
can_be_on_known(int u,Side * side,int x,int y,int * p_without)114 can_be_on_known(int u, Side *side, int x, int y, int *p_without)
115 {
116     int rslt = A_ANY_OK;
117     int tv = UNSEEN;
118 
119     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
120     assert_error(side, "Attempted to access a NULL side");
121     /* Can be on given cell? */
122     if (!valid(rslt = can_be_on(u, side, x, y, p_without)))
123       return rslt;
124     /* Acquire side's terrain view. */
125     tv = terrain_view(side, x, y);
126     /* Cell cannot be unknown to side. */
127     if (UNSEEN == tv)
128       return A_ANY_ERROR;
129     return A_ANY_OK;
130 }
131 
132 /*! \todo Consider whether u could ever get in u2 to start with. */
133 
134 int
could_be_occupant_of(int u,int u2)135 could_be_occupant_of(int u, int u2)
136 {
137     int vol = 0;
138 
139     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
140     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
141     if (0 == u_occ_total_max(u2))
142 	return FALSE;
143     if (0 == uu_occ_max(u2, u))
144 	return FALSE;
145     vol = uu_size(u, u2);
146     if (vol < u_capacity(u2))
147       return TRUE;
148     if (vol < uu_capacity_x(u2, u))
149       return TRUE;
150     return FALSE;
151 }
152 
153 int
could_be_occupant(int u)154 could_be_occupant(int u)
155 {
156     int u2 = NONUTYPE;
157 
158     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
159     for_all_unit_types(u2) {
160 	if (could_be_occupant_of(u, u2))
161 	  return TRUE;
162     }
163     return FALSE;
164 }
165 
166 int
can_be_in(int u2,Side * side,UnitView * uvtspt)167 can_be_in(int u2, Side *side, UnitView *uvtspt)
168 {
169     static int *p_ucapx;
170 
171     UnitView *uview = NULL;
172     int u = NONUTYPE, u3 = NONUTYPE;
173     int sztot = 0, numoccs = 0, numsame = 0;
174 
175     assert_error(is_unit_type(u2),
176 		 "AI Volume Check: Encountered invalid unit type");
177     assert_error(side,
178 		 "AI Volume Check: Attempted to access a NULL side");
179     assert_error(uvtspt,
180 		 "AI Volume Check: Attempted to access a NULL unit view");
181     u = uvtspt->type;
182     // Check permissions.
183     if (!trusted_side(side, side_n(uvtspt->siden)))
184 	return A_ANY_CANNOT_DO;
185     if (!uvtspt->complete) {
186 	// If unit cannot occupy incomplete transport...
187 	if (!uu_can_occupy_incomplete(u2, u))
188 	    return A_MOVE_DEST_FULL;
189     }
190     // Initialize extra-capcity array, if necessary.
191     if (!p_ucapx)
192 	p_ucapx = (int *)xmalloc(numutypes * sizeof(int));
193     for_all_unit_types(u3)
194 	p_ucapx[u3] = uu_capacity_x(u, u3);
195     // Determine if there appears to be space for new unit.
196     for_all_occupant_views(uvtspt, uview) {
197 	u3 = uview->type;
198 	++numoccs;
199 	if (0 < p_ucapx[u3])
200 	    --p_ucapx[u3];
201 	else {
202 	    sztot += uu_size(u3, u);
203 	    if (sztot >= u_capacity(u))
204 		return A_MOVE_DEST_FULL;
205 	    if (u3 == u2)
206 		++numsame;
207 	}
208     }
209     if ((0 <= u_occ_total_max(u)) && (numoccs >= u_occ_total_max(u)))
210 	return A_MOVE_DEST_FULL;
211     if ((0 <= uu_occ_max(u, u2)) && (numsame >= uu_occ_max(u, u2)))
212 	return A_MOVE_DEST_FULL;
213     sztot += uu_size(u2, u);
214     if (!p_ucapx[u2] && (sztot > u_capacity(u)))
215 	return A_MOVE_DEST_FULL;
216     return A_ANY_OK;
217 }
218 
219 int
longest_economic_input(int u,int u2,int m)220 longest_economic_input(int u, int u2, int m)
221 {
222     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
223     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
224     assert_error(is_material_type(m),
225 		 "Expected a material type but did not get one");
226     /* Check if the receiver can hold the material. */
227     if (!um_storage_x(u, m))
228       return INT_MAX;
229     /* Check if the sender can hold the materials. */
230     if (!um_storage_x(u2, m))
231       return -1;
232     /* Check if input is possible. */
233     if ((0 > um_inlength(u, m)) || (0 > um_outlength(u2, m)))
234       return -1;
235     /* Return reciever's in-length, if it is <= than sender's outlength. */
236     if (um_outlength(u2, m) >= um_inlength(u, m))
237       return um_inlength(u, m);
238     /* Else, return sender's out-length. */
239     return um_outlength(u2, m);
240 }
241 
242 //! Longest direct economic input from u2 to u.
243 
244 int
longest_economic_input(int u,int u2)245 longest_economic_input(int u, int u2)
246 {
247     int ll = INT_MAX;
248     int m = NONMTYPE;
249 
250     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
251     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
252     for_all_material_types(m)
253       ll = min(ll, longest_economic_input(u, u2, m));
254     return ll;
255 }
256 
257 //! Cache of longest direct economic inputs.
258 int *cv__longest_economic_inputs = NULL;
259 
260 //! Longest direct economic input from any utype to u.
261 
262 int
longest_economic_input(int u)263 longest_economic_input(int u)
264 {
265     int ll = -1;
266     int u2 = NONUTYPE, u3 = NONUTYPE;
267 
268     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
269     /* Calculate everything if value is not cached. */
270     if (!cv__longest_economic_inputs) {
271 	cv__longest_economic_inputs = (int *)xmalloc(numutypes * sizeof(int));
272 	/* Calculate for each utype. */
273 	for_all_unit_types(u2) {
274 	    ll = -1;
275 	    /* Calculate against each utype. */
276 	    for_all_unit_types(u3)
277 	      ll = max(ll, longest_economic_input(u2, u3));
278 	    cv__longest_economic_inputs[u] = ll;
279 	}
280     }
281     /* Return cached value. */
282     return cv__longest_economic_inputs[u];
283 }
284 
285 //! Materials productivity on given known cell for given utype and side.
286 
287 void
productivity_on_known(int * p_mtypes,int u,Side * side,int x,int y)288 productivity_on_known(int *p_mtypes, int u, Side *side, int x, int y)
289 {
290     int x1 = -1, y1 = -1, dir = -1, ptivity = 0, ptivityadj = 0;
291     int tv = UNSEEN;
292     int t = NONTTYPE;
293     int m = NONMTYPE;
294 
295     assert_error(p_mtypes, "Attempted to access a NULL materials array");
296     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
297     assert_error(side, "Attempted to access a NULL side");
298     for_all_material_types(m)
299       p_mtypes[m] = 0;
300     /* Cannot produce anything outside the playing area. */
301     if (!inside_area(x, y))
302       return;
303     /* Return 0 if cell is not known. */
304     tv = terrain_view(side, x, y);
305     if (tv == terrain_view(side, x, y))
306       return;
307     t = vterrain(tv);
308     /* Determine productivity for each material. */
309     for_all_material_types(m) {
310 	ptivity = ut_productivity(u, t);
311 	ptivity = max(ptivity, um_productivity_min(u, m));
312 	ptivity = min(ptivity, um_productivity_max(u, m));
313 	ptivityadj = 0;
314 	for_all_directions(dir) {
315             if (point_in_dir(x, y, dir, &x1, &y1)) {
316                 tv = terrain_view(side, x1, y1);
317                 if (UNSEEN == tv)
318                   continue;
319                 ptivityadj =
320                     max(ptivityadj, ut_productivity_adj(u, vterrain(tv)));
321             }
322         }
323 	p_mtypes[m] = ptivity + ptivityadj;
324     }
325 }
326 
327 //! Can u on a given side survive on a given known cell?
328 
329 int
can_survive_on_known(int u,Side * side,int x,int y,int * p_without)330 can_survive_on_known(int u, Side *side, int x, int y, int *p_without)
331 {
332     int rslt = A_ANY_OK;
333     int tv = UNSEEN;
334     int t = NONTTYPE;
335     int m = NONMTYPE;
336     int amtprod = 0;
337 
338     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
339     assert_error(side, "Attempted to access a NULL side");
340     /* Cannot survive in a place where we simply cannot be. */
341     if (!valid(rslt = can_be_on_known(u, side, x, y, p_without)))
342       return rslt;
343     /* Acquire side's terrain view. */
344     tv = terrain_view(side, x, y);
345     /* Convert view to ttype. */
346     t = vterrain(tv);
347     /* If u can have accidents on, vanish on, or wreck on,
348 	then we say that it cannot survive on. */
349     if (ut_accident_vanish(u, t)
350 	|| ut_vanishes_on(u, t) || ut_wrecks_on(u, t))
351       return A_ANY_CANNOT_DO;
352     /* If consumption > production, and u can starve,
353 	then we have also have trouble. */
354     productivity_on_known(tmp_m_array, u, side, x, y);
355     for_all_material_types(m) {
356 	if (0 >= um_hp_per_starve(u, m))
357 	  continue;
358 	amtprod = (um_base_production(u, m) * tmp_m_array[m]) / 100;
359 	if (um_base_consumption(u, m) > amtprod) {
360 	    if (!mobile(u))
361 		return A_ANY_NO_MATERIAL;
362 	    // TODO: Consider immobile in-length suppliers for immobile unit.
363 	    // TODO: Consider cell in-length suppliers for immobile unit.
364 	    // TODO: Consider treasury for any unit.
365 	}
366     }
367     return A_ANY_OK;
368 }
369 
370 //! Can a given unit survive a given known cell?
371 
372 int
can_survive_on_known(Unit * survivor,int x,int y,int * p_without)373 can_survive_on_known(Unit *survivor, int x, int y, int *p_without)
374 {
375     assert_error(in_play(survivor), "Attempted to access an out-of-play unit");
376     return
377 	can_survive_on_known(survivor->type, survivor->side, x, y, p_without);
378 }
379 
380 //! Can a given unit refuel another given unit with a given fuel?
381 
382 int
can_refuel(Unit * supplier,Unit * demander,int m)383 can_refuel(Unit *supplier, Unit *demander, int m)
384 {
385     int rslt = A_ANY_CANNOT_DO;
386     int ud = NONUTYPE, us = NONUTYPE;
387 
388     assert_error(in_play(supplier), "Attempted to access an out-of-play unit");
389     assert_error(in_play(demander), "Attempted to access an out-of-play unit");
390     assert_error(is_material_type(m),
391 		 "Attempted to reference an invalid mtype");
392     ud = demander->type;
393     us = supplier->type;
394     if (0 >= um_consumption_per_move(ud, m))
395       return A_ANY_OK;
396     if (0 < supplier->supply[m])
397       return A_ANY_OK;
398     else {
399 	if (!um_storage_x(us, m))
400 	  return A_ANY_CANNOT_DO;
401 	else
402 	  return A_ANY_NO_MATERIAL;
403     }
404     return rslt;
405 }
406 
407 int
can_create_completed_unit(Unit * actor,Unit * creator,int u3)408 can_create_completed_unit(Unit *actor, Unit *creator, int u3)
409 {
410     int rslt = A_ANY_CANNOT_DO;
411 
412     assert_error(is_active(actor),
413 		 "AI: Attempted to access an inactive actor");
414     assert_error(in_play(creator),
415 		 "AI: Attempted to access an inactive creator");
416     assert_error(is_unit_type(u3),
417 		 "AI: Encountered an invalid unit type");
418     rslt = can_create_common(actor, creator, u3, creator->x, creator->y);
419     if (valid(rslt) || (A_CONSTRUCT_NO_TOOLING == rslt)) {
420 	if (uu_creation_cp(creator->type, u3) >= u_cp(u3))
421 	  return A_ANY_OK;
422     }
423     return rslt;
424 }
425 
426 int
can_construct_any(int u,Side * side)427 can_construct_any(int u, Side *side)
428 {
429     int u2 = NONUTYPE;
430 
431     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
432     assert_error(side, "Attempted to access a NULL side");
433     for_all_unit_types(u2) {
434 	if (side_can_build(side, u2)
435 	    && (could_create(u, u2) || could_build(u, u2)))
436 	  return A_ANY_OK;
437     }
438     return A_ANY_CANNOT_DO;
439 }
440 
441 int
can_construct(Unit * actor,Unit * constructor,int u3)442 can_construct(Unit *actor, Unit *constructor, int u3)
443 {
444     int rslt = A_ANY_CANNOT_DO;
445 
446     assert_error(is_active(actor),
447 		 "AI: Attempted to access an inactive actor");
448     assert_error(is_active(constructor),
449 		 "AI: Attempted to access an inactive constructor");
450     assert_error(is_unit_type(u3),
451 		 "AI: Encountered an invalid unit type");
452     rslt =
453 	can_create_common(
454 	    actor, constructor, u3, constructor->x, constructor->y);
455     if (valid(rslt) || (A_CONSTRUCT_NO_TOOLING == rslt)) {
456 	rslt = can_create_completed_unit(actor, constructor, u3);
457 	if (valid(rslt) || (A_CONSTRUCT_NO_TOOLING == rslt))
458 	  return A_ANY_OK;
459 	else {
460 	    rslt = can_build(actor, constructor, u3);
461 	    if (valid(rslt) || (A_CONSTRUCT_NO_TOOLING == rslt))
462 	      return A_ANY_OK;
463 	}
464     }
465     return rslt;
466 }
467 
468 int
can_construct_any(Unit * actor,Unit * constructor)469 can_construct_any(Unit *actor, Unit *constructor)
470 {
471     int rslt = A_ANY_CANNOT_DO;
472     int u3 = NONUTYPE;
473     int noacp = FALSE, nomat = FALSE;
474 
475     assert_error(in_play(actor),
476 		 "AI: Attempted to access an inactive actor");
477     assert_error(in_play(constructor),
478 		 "AI: Attempted to access an inactive constructor");
479     for_all_unit_types(u3) {
480 	if (valid(rslt = can_construct(actor, constructor, u3)))
481 	  return rslt;
482 	else if (A_ANY_NO_ACP == rslt)
483 	  noacp = TRUE;
484 	else if (A_ANY_NO_MATERIAL == rslt)
485 	  nomat = TRUE;
486     }
487     if (noacp)
488       return A_ANY_NO_ACP;
489     if (nomat)
490       return A_ANY_NO_MATERIAL;
491     return rslt;
492 }
493 
494 int
can_repair_any(Unit * actor,Unit * repairer)495 can_repair_any(Unit *actor, Unit *repairer)
496 {
497     int rslt = A_ANY_CANNOT_DO;
498     int u3 = NONUTYPE;
499     int noacp = FALSE, nomat = FALSE;
500 
501     assert_error(in_play(actor),
502 		 "AI: Attempted to access an inactive actor");
503     assert_error(in_play(repairer),
504 		 "AI: Attempted to access an inactive repairer");
505     for_all_unit_types(u3) {
506 	if (valid(rslt = can_repair(actor, repairer, u3)))
507 	  return rslt;
508 	else if (A_ANY_NO_ACP == rslt)
509 	  noacp = TRUE;
510 	else if (A_ANY_NO_MATERIAL == rslt)
511 	  nomat = TRUE;
512     }
513     if (noacp)
514       return A_ANY_NO_ACP;
515     if (nomat)
516       return A_ANY_NO_MATERIAL;
517     return rslt;
518 }
519 
520 //! Could u counterattack u2?
521 
522 int
could_counterattack(int u,int u2)523 could_counterattack(int u, int u2)
524 {
525     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
526     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
527     return (could_attack(u, u2) && (0 < uu_counterattack(u2, u)));
528 }
529 
530 //! Could u countercapture u2 on a given side?
531 
532 int
could_countercapture(int u,int u2,Side * side)533 could_countercapture(int u, int u2, Side *side)
534 {
535     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
536     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
537     assert_error(side, "Attempted to access a NULL side");
538     return (could_capture(u, u2, side) && (0 < uu_countercapture(u2, u)));
539 }
540 
541 //! Could u prevent capture of u2?
542 
543 int
could_prevent_capture_of(int u,int u2)544 could_prevent_capture_of(int u, int u2)
545 {
546     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
547     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
548     /* Could u, as an occ of u2, prevent u2's capture? */
549     if (could_be_occupant_of(u, u2)) {
550 	if (g_prot_resists_capture()) {
551 	    if (!uu_protection(u, u2))
552 	      return TRUE;
553 	}
554 	if (!uu_occ_allows_capture_of(u, u2))
555 	  return TRUE;
556     }
557     /* Could u, as a neighbor of u2, prevent u2's capture? */
558     if (g_prot_resists_capture()) {
559 	if (!uu_stack_protection(u, u2))
560 	  return TRUE;
561 	if (!uu_cellwide_protection_for(u, u2))
562 	  return TRUE;
563     }
564     if (!uu_stack_neighbor_allows_capture_of(u, u2))
565       return TRUE;
566     if (!uu_any_neighbor_allows_capture_of(u, u2))
567       return TRUE;
568     return FALSE;
569 }
570 
571 //! Could u prevent capture by u2?
572 
573 int
could_prevent_capture_by(int u,int u2)574 could_prevent_capture_by(int u, int u2)
575 {
576     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
577     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
578     /* Could u as an occ of some utype prevent capture by u2? */
579     if (!uu_occ_allows_capture_by(u, u2))
580       return TRUE;
581     /* Could u, as a neighbor of u2, prevent u2's capture? */
582     if (!uu_stack_neighbor_allows_capture_by(u, u2))
583       return TRUE;
584     if (g_prot_resists_capture()) {
585 	if (!uu_cellwide_protection_against(u, u2))
586 	  return TRUE;
587     }
588     if (!uu_any_neighbor_allows_capture_by(u, u2))
589       return TRUE;
590     return FALSE;
591 }
592 
593 //! Could u damage u2 by firing?
594 
595 int
could_damage_by_fire(int u,int u2)596 could_damage_by_fire(int u, int u2)
597 {
598     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
599     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
600     return (could_fire_at(u, u2) && (0 < fire_damage(u, u2)));
601 }
602 
603 //! Could u damage u2 by attacks?
604 
605 int
could_damage_by_attacks(int u,int u2)606 could_damage_by_attacks(int u, int u2)
607 {
608     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
609     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
610     return (could_attack(u, u2) && (0 < uu_damage(u, u2)));
611 }
612 
613 //! Could u destroy u2 by firing?
614 
615 int
could_destroy_by_fire(int u,int u2)616 could_destroy_by_fire(int u, int u2)
617 {
618     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
619     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
620     return (could_damage_by_fire(u, u2) && !uu_hp_min(u, u2));
621 }
622 
623 //! Can a given unit destroy a given utype by firing?
624 
625 int
can_destroy_by_fire(Unit * actor,Unit * destroyer,int u)626 can_destroy_by_fire(Unit *actor, Unit *destroyer, int u)
627 {
628     int rslt = A_ANY_CANNOT_DO;
629 
630     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
631     assert_error(in_play(destroyer),
632 		 "Attempted to access an out-of-play unit");
633     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
634     if (could_destroy_by_fire(destroyer->type, u)
635 	&& can_fire_at(actor, destroyer, u))
636       return A_ANY_OK;
637     return rslt;
638 }
639 
640 //! Can a given unit destroy >= 1 enemy utypes by firing?
641 
642 int
can_destroy_any_by_fire(Unit * actor,Unit * destroyer)643 can_destroy_any_by_fire(Unit *actor, Unit *destroyer)
644 {
645     int rslt = A_ANY_CANNOT_DO;
646     int u = NONUTYPE;
647     int noacp = FALSE, nomat = FALSE;
648 
649     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
650     assert_error(in_play(destroyer),
651 		 "Attempted to access an out-of-play unit");
652     for_all_unit_types(u) {
653 	if (valid(rslt = can_destroy_by_fire(actor, destroyer, u)))
654 	  return A_ANY_OK;
655 	else if (A_ANY_NO_ACP == rslt)
656 	  noacp = TRUE;
657 	else if (A_ANY_NO_MATERIAL == rslt)
658 	  nomat = TRUE;
659     }
660     if (noacp)
661       return A_ANY_NO_ACP;
662     if (nomat)
663       return A_ANY_NO_MATERIAL;
664     return rslt;
665 }
666 
667 //! Could u destroy u2 by attacking?
668 
669 int
could_destroy_by_attacks(int u,int u2)670 could_destroy_by_attacks(int u, int u2)
671 {
672     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
673     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
674     return (could_damage_by_attacks(u, u2) && !uu_hp_min(u, u2));
675 }
676 
677 //! Can a given unit destroy a given utype by attacks?
678 
679 int
can_destroy_by_attacks(Unit * actor,Unit * destroyer,int u)680 can_destroy_by_attacks(Unit *actor, Unit *destroyer, int u)
681 {
682     int rslt = A_ANY_CANNOT_DO;
683 
684     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
685     assert_error(in_play(destroyer), "Attempted to access an out-of-play unit");
686     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
687     if (could_destroy_by_attacks(destroyer->type, u)
688 	&& can_attack(actor, destroyer, u))
689       return A_ANY_OK;
690     return rslt;
691 }
692 
693 //! Can a given unit destroy >= 1 enemy utypes by attacks?
694 
695 int
can_destroy_any_by_attacks(Unit * actor,Unit * destroyer)696 can_destroy_any_by_attacks(Unit *actor, Unit *destroyer)
697 {
698     int rslt = A_ANY_CANNOT_DO;
699     int u = NONUTYPE;
700     int noacp = FALSE, nomat = FALSE;
701 
702     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
703     assert_error(in_play(destroyer), "Attempted to access an out-of-play unit");
704     for_all_unit_types(u) {
705 	if (valid(rslt = can_destroy_by_attacks(actor, destroyer, u)))
706 	  return A_ANY_OK;
707 	else if (A_ANY_NO_ACP == rslt)
708 	  noacp = TRUE;
709 	else if (A_ANY_NO_MATERIAL == rslt)
710 	  nomat = TRUE;
711     }
712     if (noacp)
713       return A_ANY_NO_ACP;
714     if (nomat)
715       return A_ANY_NO_MATERIAL;
716     return A_ANY_CANNOT_DO;
717 }
718 
719 //! Could u damage u2 by combat?
720 
721 int
could_damage_by_combat(int u,int u2)722 could_damage_by_combat(int u, int u2)
723 {
724     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
725     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
726     return (could_damage_by_fire(u, u2) || could_damage_by_attacks(u, u2));
727 }
728 
729 //! Can a given unit destroy >= 1 enemy utypes through combat?
730 
731 int
can_destroy_any_by_combat(Unit * acpsrc,Unit * destroyer)732 can_destroy_any_by_combat(Unit *acpsrc, Unit *destroyer)
733 {
734     int rslt = A_ANY_CANNOT_DO;
735     int noacp = FALSE, nomat = FALSE;
736 
737     assert_error(in_play(acpsrc), "Attempted to access an out-of-play unit");
738     assert_error(in_play(destroyer),
739 		 "Attempted to access an out-of-play unit");
740     if (valid(rslt = can_destroy_any_by_fire(acpsrc, destroyer)))
741       return A_ANY_OK;
742     else if (A_ANY_NO_ACP == rslt)
743       noacp = TRUE;
744     else if (A_ANY_NO_MATERIAL == rslt)
745       nomat = TRUE;
746     if (valid(rslt = can_destroy_any_by_attacks(acpsrc, destroyer)))
747       return A_ANY_OK;
748     else if (A_ANY_NO_ACP == rslt)
749       noacp = TRUE;
750     else if (A_ANY_NO_MATERIAL == rslt)
751       nomat = TRUE;
752     if (noacp)
753       return A_ANY_NO_ACP;
754     if (nomat)
755       return A_ANY_NO_MATERIAL;
756     return rslt;
757 }
758 
759 //! Could u damage u2 through explosions?
760 
761 int
could_damage_by_explosions(int u,int u2)762 could_damage_by_explosions(int u, int u2)
763 {
764     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
765     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
766     return (uu_detonation_damage_at(u, u2)
767 	    || uu_detonation_damage_adj(u, u2));
768 }
769 
770 //! Could u destroy u2 through explosions?
771 
772 int
could_destroy_by_explosions(int u,int u2)773 could_destroy_by_explosions(int u, int u2)
774 {
775     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
776     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
777     return (could_damage_by_explosions(u, u2) && !uu_hp_min(u, u2));
778 }
779 
780 //! Can an utype on a given side destroy >= 1 enemy utypes through explosions?
781 
782 int
can_destroy_any_by_explosions(int u,Side * side)783 can_destroy_any_by_explosions(int u, Side *side)
784 {
785     int rslt = A_ANY_CANNOT_DO;
786     int u2 = NONUTYPE;
787     int noacp = FALSE, nomat = FALSE;
788 
789     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
790     assert_error(side, "Attempted to access a NULL side");
791     for_all_unit_types(u2) {
792 	if (could_destroy_by_explosions(u, u2))
793 	  return A_ANY_OK;
794 	else if (A_ANY_NO_ACP == rslt)
795 	  noacp = TRUE;
796 	else if (A_ANY_NO_MATERIAL == rslt)
797 	  nomat = TRUE;
798     }
799     if (noacp)
800       return A_ANY_NO_ACP;
801     if (nomat)
802       return A_ANY_NO_MATERIAL;
803     return rslt;
804 }
805 
806 //! Can a given unit destroy >= 1 enemy utypes through explosions?
807 
808 int
can_destroy_any_by_explosions(Unit * acpsrc,Unit * exploder)809 can_destroy_any_by_explosions(Unit *acpsrc, Unit *exploder)
810 {
811     int rslt = A_ANY_CANNOT_DO;
812 
813     assert_error(in_play(acpsrc), "Attempted to access an out-of-play unit");
814     assert_error(in_play(exploder),
815 		 "Attempted to access an out-of-play unit");
816     if (!valid(rslt = can_detonate(acpsrc, exploder)))
817       return rslt;
818     return can_destroy_any_by_explosions(exploder->type, exploder->side);
819 }
820 
821 //! Could u damage u2 by any means?
822 
823 int
could_damage(int u,int u2)824 could_damage(int u, int u2)
825 {
826     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
827     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
828     return (could_damage_by_combat(u, u2) || could_damage_by_explosions(u, u2));
829 }
830 
831 //! Could u damage >= 1 enemy utypes by any means?
832 
833 int
could_damage_any(int u)834 could_damage_any(int u)
835 {
836     int u2 = NONUTYPE;
837 
838     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
839     for_all_unit_types(u2) {
840 	if (could_damage(u, u2))
841 	  return TRUE;
842     }
843     return FALSE;
844 }
845 
846 //! Can a given unit destroy >= 1 enemy utypes by any means?
847 
848 int
can_destroy_any(Unit * acpsrc,Unit * destroyer)849 can_destroy_any(Unit *acpsrc, Unit *destroyer)
850 {
851     int rslt = A_ANY_CANNOT_DO;
852     int noacp = FALSE, nomat = FALSE;
853 
854     assert_error(in_play(acpsrc), "Attempted to access an out-of-play unit");
855     assert_error(in_play(destroyer),
856 		 "Attempted to access an out-of-play unit");
857     if (valid(rslt = can_destroy_any_by_combat(acpsrc, destroyer)))
858       return A_ANY_OK;
859     else if (A_ANY_NO_ACP == rslt)
860       noacp = TRUE;
861     else if (A_ANY_NO_MATERIAL == rslt)
862       nomat = TRUE;
863     if (valid(rslt = can_destroy_any_by_explosions(acpsrc, destroyer)))
864       return A_ANY_OK;
865     else if (A_ANY_NO_ACP == rslt)
866       noacp = TRUE;
867     else if (A_ANY_NO_MATERIAL == rslt)
868       nomat = TRUE;
869     if (noacp)
870       return A_ANY_NO_ACP;
871     if (nomat)
872       return A_ANY_NO_MATERIAL;
873     return rslt;
874 }
875 
876 //! Can a given unit capture a given utype by fire?
877 
878 int
can_capture_by_fire(Unit * actor,Unit * captor,int u)879 can_capture_by_fire(Unit *actor, Unit *captor, int u)
880 {
881     int rslt = A_ANY_CANNOT_DO;
882     Side *side = NULL;
883     int noacp = FALSE, nomat = FALSE;
884 
885     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
886     assert_error(in_play(captor), "Attempted to access an out-of-play unit");
887     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
888     if (!could_fire_at(captor->type, u))
889       return A_ANY_CANNOT_DO;
890     for_all_sides(side) {
891 	if (valid(rslt = can_capture(actor, captor, u, side)))
892 	  return A_ANY_OK;
893 	else if (A_ANY_NO_ACP == rslt)
894 	  noacp = TRUE;
895 	else if (A_ANY_NO_MATERIAL == rslt)
896 	  nomat = TRUE;
897     }
898     if (noacp)
899       return A_ANY_NO_ACP;
900     if (nomat)
901       return A_ANY_NO_MATERIAL;
902     return A_ANY_CANNOT_DO;
903 }
904 
905 //! Can a given unit capture a given utype by attacks?
906 
907 int
can_capture_by_attacks(Unit * actor,Unit * captor,int u)908 can_capture_by_attacks(Unit *actor, Unit *captor, int u)
909 {
910     int rslt = A_ANY_CANNOT_DO;
911     Side *side = NULL;
912     int noacp = FALSE, nomat = FALSE;
913 
914     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
915     assert_error(in_play(captor), "Attempted to access an out-of-play unit");
916     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
917     if (!could_attack(captor->type, u))
918       return A_ANY_CANNOT_DO;
919     for_all_sides(side) {
920 	if (valid(rslt = can_capture(actor, captor, u, side)))
921 	  return A_ANY_OK;
922 	else if (A_ANY_NO_ACP == rslt)
923 	  noacp = TRUE;
924 	else if (A_ANY_NO_MATERIAL == rslt)
925 	  nomat = TRUE;
926     }
927     if (noacp)
928       return A_ANY_NO_ACP;
929     if (nomat)
930       return A_ANY_NO_MATERIAL;
931     return A_ANY_CANNOT_DO;
932 }
933 
934 //! Can a given unit capture >= 1 enemy utypes in any way?
935 
936 int
can_capture_any(Unit * actor,Unit * captor)937 can_capture_any(Unit *actor, Unit *captor)
938 {
939     int rslt = A_ANY_CANNOT_DO;
940     Side *side = NULL;
941     int u = NONUTYPE;
942     int noacp = FALSE, nomat = FALSE;
943 
944     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
945     assert_error(in_play(captor), "Attempted to access an out-of-play unit");
946     for_all_unit_types(u) {
947 	for_all_sides(side) {
948 	    if (valid(rslt = can_capture(actor, captor, u, side)))
949 	      return A_ANY_OK;
950 	    else if (A_ANY_NO_ACP == rslt)
951 	      noacp = TRUE;
952 	    else if (A_ANY_NO_MATERIAL == rslt)
953 	      nomat = TRUE;
954 	}
955     }
956     if (noacp)
957       return A_ANY_NO_ACP;
958     if (nomat)
959       return A_ANY_NO_MATERIAL;
960     return A_ANY_CANNOT_DO;
961 }
962 
963 //! Can a given unit countercapture >= 1 enemy utypes in any way?
964 
965 int
can_countercapture_any(Unit * actor,Unit * countercaptor)966 can_countercapture_any(Unit *actor, Unit *countercaptor)
967 {
968     int rslt = A_ANY_CANNOT_DO;
969     Side *side = NULL;
970     int u = NONUTYPE;
971     int noacp = FALSE, nomat = FALSE;
972 
973     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
974     assert_error(in_play(countercaptor),
975 		 "Attempted to access an out-of-play unit");
976     for_all_unit_types(u) {
977 	for_all_sides(side) {
978 	    if (could_countercapture(countercaptor->type, u, side)
979 		&& valid(rslt = can_capture(actor, countercaptor, u, side)))
980 	      return A_ANY_OK;
981 	    else if (A_ANY_NO_ACP == rslt)
982 	      noacp = TRUE;
983 	    else if (A_ANY_NO_MATERIAL == rslt)
984 	      nomat = TRUE;
985 	}
986     }
987     if (noacp)
988       return A_ANY_NO_ACP;
989     if (nomat)
990       return A_ANY_NO_MATERIAL;
991     return A_ANY_CANNOT_DO;
992 }
993 
994 //! Can a given unit prevent capture of >= 1 friendly utypes?
995 /*! \todo Check if our side or ally possesses each utype? */
996 
997 int
can_prevent_capture_of_any(Unit * actor,Unit * anticaptor)998 can_prevent_capture_of_any(Unit *actor, Unit *anticaptor)
999 {
1000     int u = NONUTYPE;
1001 
1002     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
1003     assert_error(in_play(anticaptor),
1004 		 "Attempted to access an out-of-play unit");
1005     for_all_unit_types(u) {
1006 	if (could_prevent_capture_of(anticaptor->type, u))
1007 	  return A_ANY_OK;
1008     }
1009     return A_ANY_CANNOT_DO;
1010 }
1011 
1012 //! Could u defeat u2 by fire?
1013 
1014 int
could_defeat_by_fire(int u,int u2,Side * side)1015 could_defeat_by_fire(int u, int u2, Side *side)
1016 {
1017     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
1018     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
1019     assert_error(side, "Attempted to access a NULL side");
1020     return (could_destroy_by_fire(u, u2) || could_capture_by_fire(u, u2, side));
1021 }
1022 
1023 //! Can a given unit defeat a given utype by fire?
1024 
1025 int
can_defeat_by_fire(Unit * actor,Unit * firer,int u)1026 can_defeat_by_fire(Unit *actor, Unit *firer, int u)
1027 {
1028     int rslt = A_ANY_CANNOT_DO;
1029     int noacp = FALSE, nomat = FALSE;
1030 
1031     /* Sanity checks. */
1032     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
1033     assert_error(in_play(firer), "Attempted to access an out-of-play unit");
1034     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
1035     /* Can destroy enemy utype by fire? */
1036     if (valid(rslt = can_destroy_by_fire(actor, firer, u)))
1037       return A_ANY_OK;
1038     else if (A_ANY_NO_ACP == rslt)
1039       noacp = TRUE;
1040     else if (A_ANY_NO_MATERIAL == rslt)
1041       nomat = TRUE;
1042     /* Can capture enemy utype by fire? */
1043     if (valid(rslt = can_capture_by_fire(actor, firer, u)))
1044       return A_ANY_OK;
1045     else if (A_ANY_NO_ACP == rslt)
1046       noacp = TRUE;
1047     else if (A_ANY_NO_MATERIAL == rslt)
1048       nomat = TRUE;
1049     /* Return proper result. */
1050     if (noacp)
1051       return A_ANY_NO_ACP;
1052     if (nomat)
1053       return A_ANY_NO_MATERIAL;
1054     return A_ANY_CANNOT_DO;
1055 }
1056 
1057 //! Could u defeat u2 by attacks?
1058 
1059 int
could_defeat_by_attacks(int u,int u2,Side * side)1060 could_defeat_by_attacks(int u, int u2, Side *side)
1061 {
1062     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
1063     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
1064     assert_error(side, "Attempted to access a NULL side");
1065     return (could_destroy_by_attacks(u, u2)
1066 	    || could_capture_by_attacks(u, u2, side));
1067 }
1068 
1069 //! Can a given unit defeat a given utype with attacks?
1070 
1071 int
can_defeat_by_attacks(Unit * actor,Unit * attacker,int u)1072 can_defeat_by_attacks(Unit *actor, Unit *attacker, int u)
1073 {
1074     int rslt = A_ANY_CANNOT_DO;
1075     int noacp = FALSE, nomat = FALSE;
1076 
1077     /* Sanity checks. */
1078     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
1079     assert_error(in_play(attacker), "Attempted to access an out-of-play unit");
1080     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
1081     /* Can destroy enemy utype by attacks? */
1082     if (valid(rslt = can_destroy_by_attacks(actor, attacker, u)))
1083       return A_ANY_OK;
1084     else if (A_ANY_NO_ACP == rslt)
1085       noacp = TRUE;
1086     else if (A_ANY_NO_MATERIAL == rslt)
1087       nomat = TRUE;
1088     /* Can capture enemy utype by attacks? */
1089     if (valid(rslt = can_capture_by_attacks(actor, attacker, u)))
1090       return A_ANY_OK;
1091     else if (A_ANY_NO_ACP == rslt)
1092       noacp = TRUE;
1093     else if (A_ANY_NO_MATERIAL == rslt)
1094       nomat = TRUE;
1095     /* Return proper result. */
1096     if (noacp)
1097       return A_ANY_NO_ACP;
1098     if (nomat)
1099       return A_ANY_NO_MATERIAL;
1100     return A_ANY_CANNOT_DO;
1101 }
1102 
1103 //! Could u defeat u2 by counterattacks?
1104 
1105 int
could_defeat_by_counterattacks(int u,int u2,Side * side)1106 could_defeat_by_counterattacks(int u, int u2, Side *side)
1107 {
1108     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
1109     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
1110     assert_error(side, "Attempted to access a NULL side");
1111     return (could_counterattack(u, u2) && could_defeat_by_attacks(u, u2, side));
1112 }
1113 
1114 //! Can a given unit defeat a given utype with counterattacks?
1115 
1116 int
can_defeat_by_counterattacks(Unit * actor,Unit * counterattacker,int u)1117 can_defeat_by_counterattacks(Unit *actor, Unit *counterattacker, int u)
1118 {
1119     int rslt = A_ANY_CANNOT_DO;
1120 
1121     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
1122     assert_error(in_play(counterattacker),
1123 		 "Attempted to access an out-of-play unit");
1124     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
1125     if (could_counterattack(counterattacker->type, u)
1126 	&& valid(rslt = can_defeat_by_attacks(actor, counterattacker, u)))
1127       return A_ANY_OK;
1128     return rslt;
1129 }
1130 
1131 //! Can a given unit defeat >= 1 enemy utypes with counterattacks?
1132 
1133 int
can_defeat_any_by_counterattacks(Unit * actor,Unit * counterattacker)1134 can_defeat_any_by_counterattacks(Unit *actor, Unit *counterattacker)
1135 {
1136     int rslt = A_ANY_CANNOT_DO;
1137     int u = NONUTYPE;
1138     int noacp = FALSE, nomat = FALSE;
1139 
1140     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
1141     assert_error(in_play(counterattacker),
1142 		 "Attempted to access an out-of-play unit");
1143     for_all_unit_types(u) {
1144 	if (valid(
1145 	    rslt = can_defeat_by_counterattacks(actor, counterattacker, u)))
1146 	  return A_ANY_OK;
1147 	else if (A_ANY_NO_ACP == rslt)
1148 	  noacp = TRUE;
1149 	else if (A_ANY_NO_MATERIAL == rslt)
1150 	  nomat = TRUE;
1151     }
1152     if (noacp)
1153       return A_ANY_NO_ACP;
1154     if (nomat)
1155       return A_ANY_NO_MATERIAL;
1156     return A_ANY_CANNOT_DO;
1157 }
1158 
1159 //! Could an utype overwatch against another utype?
1160 
1161 int
could_overwatch_against(int u,int u2)1162 could_overwatch_against(int u, int u2)
1163 {
1164     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
1165     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
1166     return (could_fire_at(u, u2) && (0 < uu_zoo_range(u, u2)));
1167 }
1168 
1169 //! Could u overwatch against and defeat u2?
1170 
1171 int
could_overwatch_against_and_defeat(int u,int u2,Side * side)1172 could_overwatch_against_and_defeat(int u, int u2, Side *side)
1173 {
1174     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
1175     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
1176     return (could_overwatch_against(u, u2)
1177 	    && could_defeat_by_fire(u, u2, side));
1178 }
1179 
1180 //! Can a given unit overwatch against and defeat a given utype?
1181 
1182 int
can_overwatch_against_and_defeat(Unit * acpsrc,Unit * overwatcher,int u)1183 can_overwatch_against_and_defeat(Unit *acpsrc, Unit *overwatcher, int u)
1184 {
1185     int rslt = A_ANY_CANNOT_DO;
1186 
1187     assert_error(in_play(acpsrc), "Attempted to access an out-of-play unit");
1188     assert_error(in_play(overwatcher),
1189 		 "Attempted to access an out-of-play unit");
1190     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
1191     if (could_overwatch_against(overwatcher->type, u)
1192 	&& valid(rslt = can_defeat_by_fire(acpsrc, overwatcher, u)))
1193       return A_ANY_OK;
1194     return rslt;
1195 }
1196 
1197 //! Can a given unit provide defeating overwatch against >= 1 enemy utypes?
1198 
1199 int
can_overwatch_against_and_defeat_any(Unit * acpsrc,Unit * overwatcher)1200 can_overwatch_against_and_defeat_any(Unit *acpsrc, Unit *overwatcher)
1201 {
1202     int rslt = A_ANY_CANNOT_DO;
1203     int u = NONUTYPE;
1204     int noacp = FALSE, nomat = FALSE;
1205 
1206     assert_error(in_play(acpsrc), "Attempted to access an out-of-play unit");
1207     assert_error(in_play(overwatcher),
1208 		 "Attempted to access an out-of-play unit");
1209     for_all_unit_types(u) {
1210 	if (valid(
1211 	    rslt = can_overwatch_against_and_defeat(acpsrc, overwatcher, u)))
1212 	  return A_ANY_OK;
1213 	else if (A_ANY_NO_ACP == rslt)
1214 	  noacp = TRUE;
1215 	else if (A_ANY_NO_MATERIAL == rslt)
1216 	  nomat = TRUE;
1217     }
1218     /* Return proper result. */
1219     if (noacp)
1220       return A_ANY_NO_ACP;
1221     if (nomat)
1222       return A_ANY_NO_MATERIAL;
1223     return A_ANY_CANNOT_DO;
1224 }
1225 
1226 //! Could u defend against u2 in any way?
1227 /*! \todo Support counterfire. */
1228 
1229 int
could_defend_against(int u,int u2,Side * side)1230 could_defend_against(int u, int u2, Side *side)
1231 {
1232     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
1233     assert_error(is_unit_type(u2), "Expected an unit type but did not get one");
1234     if (could_overwatch_against_and_defeat(u, u2, side))
1235       return TRUE;
1236     /* TODO: Support counterfire. */
1237     if (could_defeat_by_counterattacks(u, u2, side))
1238       return TRUE;
1239     if (could_countercapture(u, u2, side))
1240       return TRUE;
1241     if (could_prevent_capture_by(u, u2))
1242       return TRUE;
1243     return FALSE;
1244 }
1245 
1246 //! Could u defend against >= 1 enemy utypes in any way?
1247 
1248 int
could_defend_against_any(int u)1249 could_defend_against_any(int u)
1250 {
1251     int u2 = NONUTYPE;
1252     Side *side = NULL;
1253 
1254     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
1255     for_all_unit_types(u2) {
1256 	for_all_sides(side) {
1257 	    if (could_defend_against(u, u2, side))
1258 	      return TRUE;
1259 	}
1260     }
1261     return FALSE;
1262 }
1263 
1264 //! Can a given unit defend against >= 1 enemy utypes in any way?
1265 /*! \todo Support counterfire. */
1266 
1267 int
can_defend_against_any(Unit * actor,Unit * defender)1268 can_defend_against_any(Unit *actor, Unit *defender)
1269 {
1270     int rslt = A_ANY_CANNOT_DO;
1271     int noacp = FALSE, nomat = FALSE;
1272 
1273     /* Sanity checks. */
1274     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
1275     assert_error(in_play(defender), "Attempted to access an out-of-play unit");
1276     /* Can overwatch against and defeat any enemies? */
1277     if (valid(rslt = can_overwatch_against_and_defeat_any(actor, defender)))
1278       return A_ANY_OK;
1279     else if (A_ANY_NO_ACP == rslt)
1280       noacp = TRUE;
1281     else if (A_ANY_NO_MATERIAL == rslt)
1282       nomat = TRUE;
1283     /* TODO: Counterfire. */
1284     /* Can defeat any enemies by counterattacking? */
1285     if (valid(rslt = can_defeat_any_by_counterattacks(actor, defender)))
1286       return A_ANY_OK;
1287     else if (A_ANY_NO_ACP == rslt)
1288       noacp = TRUE;
1289     else if (A_ANY_NO_MATERIAL == rslt)
1290       nomat = TRUE;
1291     /* Can countercapture any enemies? */
1292     if (valid(rslt = can_countercapture_any(actor, defender)))
1293       return A_ANY_OK;
1294     else if (A_ANY_NO_ACP == rslt)
1295       noacp = TRUE;
1296     else if (A_ANY_NO_MATERIAL == rslt)
1297       nomat = TRUE;
1298     /* Can prevent capture of any friendly units by any enemy units? */
1299     if (valid(rslt = can_prevent_capture_of_any(actor, defender)))
1300       return A_ANY_OK;
1301     else if (A_ANY_NO_ACP == rslt)
1302       noacp = TRUE;
1303     else if (A_ANY_NO_MATERIAL == rslt)
1304       nomat = TRUE;
1305     /* Return proper result. */
1306     if (noacp)
1307       return A_ANY_NO_ACP;
1308     if (nomat)
1309       return A_ANY_NO_MATERIAL;
1310     return A_ANY_CANNOT_DO;
1311 }
1312 
1313 //! Could u explore?
1314 
1315 int
could_explore(int u)1316 could_explore(int u)
1317 {
1318     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
1319     return ((-1 < u_vision_range(u)) && mobile(u));
1320 }
1321 
1322 //! Can a given unit explore?
1323 
1324 int
can_explore(Unit * actor,Unit * explorer)1325 can_explore(Unit *actor, Unit *explorer)
1326 {
1327     int rslt = A_ANY_CANNOT_DO;
1328 
1329     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
1330     assert_error(in_play(explorer), "Attempted to access an out-of-play unit");
1331     if ((-1 < u_vision_range(explorer->type))
1332 	&& valid(rslt = can_move(actor, explorer)))
1333       return A_ANY_OK;
1334     return rslt;
1335 }
1336 
1337 //! Can a given unit construct explorers?
1338 
1339 int
can_construct_explorers(Unit * actor,Unit * constructor)1340 can_construct_explorers(Unit *actor, Unit *constructor)
1341 {
1342     int rslt = A_ANY_CANNOT_DO;
1343     int u = NONUTYPE;
1344     int noacp = FALSE, nomat = FALSE;
1345 
1346     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
1347     assert_error(in_play(constructor),
1348 		 "Attempted to access an out-of-play unit");
1349     for_all_unit_types(u) {
1350 	if (could_explore(u)
1351 	    && valid(rslt = can_construct(actor, constructor, u)))
1352 	  return A_ANY_OK;
1353 	else if (A_ANY_NO_ACP == rslt)
1354 	  noacp = TRUE;
1355 	else if (A_ANY_NO_MATERIAL == rslt)
1356 	  nomat = TRUE;
1357     }
1358     if (noacp)
1359       return A_ANY_NO_ACP;
1360     if (nomat)
1361       return A_ANY_NO_MATERIAL;
1362     return A_ANY_CANNOT_DO;
1363 }
1364 
1365 //! Could u colonize?
1366 
1367 int
could_colonize(int u)1368 could_colonize(int u)
1369 {
1370     int u2 = NONUTYPE, u3 = NONUTYPE;
1371 
1372     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
1373     for_all_unit_types(u2) {
1374 	if (!could_create(u, u2))
1375 	  continue;
1376 	for_all_unit_types(u3) {
1377 	    if (could_create(u2, u3))
1378 	      return TRUE;
1379 	}
1380     }
1381     return FALSE;
1382 }
1383 
1384 //! Can a given utype on a given side colonize?
1385 
1386 int
can_colonize(int u,Side * side)1387 can_colonize(int u, Side *side)
1388 {
1389     int rslt = A_ANY_CANNOT_DO;
1390     int u2 = NONUTYPE, u3 = NONUTYPE;
1391 
1392     assert_error(is_unit_type(u), "Expected an unit type but did not get one");
1393     assert_error(side, "Attempted to access a NULL side");
1394     for_all_unit_types(u2) {
1395 	if (!side_can_build(side, u2))
1396 	  continue;
1397 	if (!could_create(u, u2))
1398 	  continue;
1399 	for_all_unit_types(u3) {
1400 	    if (could_create(u2, u3))
1401 	      return A_ANY_OK;
1402 	}
1403     }
1404     return rslt;
1405 }
1406 
1407 //! Can a given unit colonize?
1408 
1409 int
can_colonize(Unit * actor,Unit * colonizer)1410 can_colonize(Unit *actor, Unit *colonizer)
1411 {
1412     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
1413     assert_error(in_play(colonizer), "Attempted to access an out-of-play unit");
1414     return can_colonize(colonizer->type, actor->side);
1415 }
1416 
1417 //! Can a given unit construct colonizers?
1418 
1419 int
can_construct_colonizers(Unit * actor,Unit * constructor)1420 can_construct_colonizers(Unit *actor, Unit *constructor)
1421 {
1422     int rslt = A_ANY_CANNOT_DO;
1423     int u = NONUTYPE;
1424     int noacp = FALSE, nomat = FALSE;
1425 
1426     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
1427     assert_error(in_play(constructor),
1428 		 "Attempted to access an out-of-play unit");
1429     for_all_unit_types(u) {
1430 	if (can_colonize(u, actor->side)
1431 	    && valid(rslt = can_construct(actor, constructor, u)))
1432 	  return A_ANY_OK;
1433 	else if (A_ANY_NO_ACP == rslt)
1434 	  noacp = TRUE;
1435 	else if (A_ANY_NO_MATERIAL == rslt)
1436 	  nomat = TRUE;
1437     }
1438     if (noacp)
1439       return A_ANY_NO_ACP;
1440     if (nomat)
1441       return A_ANY_NO_MATERIAL;
1442     return A_ANY_CANNOT_DO;
1443 }
1444 
1445 //! Can a given unit construct any offensive units?
1446 
1447 int
can_construct_offenders(Unit * actor,Unit * constructor)1448 can_construct_offenders(Unit *actor, Unit *constructor)
1449 {
1450     int rslt = A_ANY_CANNOT_DO;
1451     int u = NONUTYPE;
1452     int noacp = FALSE, nomat = FALSE;
1453 
1454     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
1455     assert_error(in_play(constructor),
1456 		 "Attempted to access an out-of-play unit");
1457     for_all_unit_types(u) {
1458 	if (could_damage_any(u)
1459 	    && valid(rslt = can_construct(actor, constructor, u)))
1460 	  return A_ANY_OK;
1461 	else if (A_ANY_NO_ACP == rslt)
1462 	  noacp = TRUE;
1463 	else if (A_ANY_NO_MATERIAL == rslt)
1464 	  nomat = TRUE;
1465     }
1466     if (noacp)
1467       return A_ANY_NO_ACP;
1468     if (nomat)
1469       return A_ANY_NO_MATERIAL;
1470     return A_ANY_CANNOT_DO;
1471 }
1472 
1473 //! Can a given unit construct any defensive units?
1474 
1475 int
can_construct_defenders(Unit * actor,Unit * constructor)1476 can_construct_defenders(Unit *actor, Unit *constructor)
1477 {
1478     int rslt = A_ANY_CANNOT_DO;
1479     int u = NONUTYPE;
1480     int noacp = FALSE, nomat = FALSE;
1481 
1482     assert_error(in_play(actor), "Attempted to access an out-of-play unit");
1483     assert_error(in_play(constructor),
1484 		 "Attempted to access an out-of-play unit");
1485     for_all_unit_types(u) {
1486 	if (could_defend_against_any(u)
1487 	    && valid(rslt = can_construct(actor, constructor, u)))
1488 	  return A_ANY_OK;
1489 	else if (A_ANY_NO_ACP == rslt)
1490 	  noacp = TRUE;
1491 	else if (A_ANY_NO_MATERIAL == rslt)
1492 	  nomat = TRUE;
1493     }
1494     if (noacp)
1495       return A_ANY_NO_ACP;
1496     if (nomat)
1497       return A_ANY_NO_MATERIAL;
1498     return A_ANY_CANNOT_DO;
1499 }
1500