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