1 /* Unit and Unit Type Analysis and Worth 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 Worth Functions for AIs
11
12 Part of the AI API, Level 2.
13
14 Provides useful functions that an AI implementation may use to analyze
15 and to assign a worth to units and unit types.
16
17 The functions in this file provide evaluations regarding units and
18 unit types that are useful in decision-making.
19
20 \note Nothing in this file should be required for AI implementation.
21
22 */
23
24 #include "conq.h"
25 #include "kernel.h"
26 #include "aiunit.h"
27 #include "aiunit2.h"
28
29 /* Unit Vision and Detection Worths */
30
31 //! Basic worth as a seer.
32
33 int
seer_worth(int u)34 seer_worth(int u)
35 {
36 int worth = 0, nighteffect = 0;
37 int u2 = NONUTYPE;
38 int t = NONTTYPE;
39
40 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
41 /* If utype could see... */
42 if (could_see(u)) {
43 /* Ability to see other utypes is basis. */
44 for_all_unit_types(u2) {
45 worth += min(100, uu_see_at(u, u2));
46 if (0 < u_vision_range(u))
47 worth += 6 * min(100, uu_see_adj(u, u2));
48 if (1 < u_vision_range(u))
49 worth +=
50 ((radius_covers_n_cells(u_vision_range(u)) - 7) *
51 min(100, uu_see(u, u2)));
52 if (0 < uu_see_mistake(u, u2)
53 && (uu_see_mistake_range_min(u, u2) <= u_vision_range(u))) {
54 worth -=
55 ((radius_covers_n_cells(u_vision_range(u)) -
56 radius_covers_n_cells(uu_see_mistake_range_min(u, u2))) *
57 (uu_see_mistake(u, u2) / 200));
58 }
59 }
60 worth = max(0, worth / 100);
61 // Night's effect on vision.
62 for_all_terrain_types(t)
63 nighteffect += min(100, ut_vision_night_effect(u, t));
64 nighteffect /= numttypes;
65 worth -= ((worth / 2) * (100 - nighteffect)) / 100;
66 worth = max(0, worth);
67 }
68 // Else utype could not see, then it is worthless as a seer.
69 else
70 worth = 0;
71 return max(0, worth);
72 }
73
74 //! Set basic worth as a seer.
75
76 void
set_seer_worth(int u,int n)77 set_seer_worth(int u, int n)
78 {
79 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
80 assert_error(between(PROPLO, n, PROPHI),
81 "Attempted to set an uprop out-of-bounds");
82 utypes[u].aiseerworth = n;
83 }
84
85 //! Set basic worths as seers, if necessary.
86
87 void
maybe_set_seer_worths(void)88 maybe_set_seer_worths(void)
89 {
90 int u = NONUTYPE;
91 int worthmax = 0;
92 int mustcalc = FALSE;
93
94 for_all_unit_types(u) {
95 if (uprop_i_default(u_ai_seer_worth) == u_ai_seer_worth(u)) {
96 mustcalc = TRUE;
97 break;
98 }
99 }
100 if (mustcalc) {
101 for_all_unit_types(u) {
102 tmp_u_array[u] = seer_worth(u);
103 worthmax = max(worthmax, tmp_u_array[u]);
104 }
105 for_all_unit_types(u)
106 set_seer_worth(u,
107 normalize_on_pmscale(tmp_u_array[u], worthmax, 10000));
108 }
109 }
110
111 /* Size Estimates */
112
113 int
could_meet_size_goal(int u,int x,int y)114 could_meet_size_goal(int u, int x, int y)
115 {
116 static int *p_materials;
117
118 int ux = -1, uy = -1;
119 int m = NONMTYPE;
120 int szmax = INT_MAX;
121
122 assert_error(is_unit_type(u),
123 "AI Size Assessor: Encountered invalid unit type");
124 assert_error(inside_area(x, y),
125 "AI Size Assessor: Cannot check for out-of-area coords");
126 if (!u_advanced(u))
127 return TRUE;
128 // Allocate the materials storage array, if necessary.
129 if (!p_materials)
130 p_materials = (int *)xmalloc(nummtypes * sizeof(int));
131 // Always reset the array.
132 for_all_material_types(m)
133 p_materials[m] = 0;
134 // For all cells within reach, find out how much material is yielded up.
135 for_all_cells_within_range(x, y, u_reach(u), ux, uy) {
136 if (!inside_area(ux, uy))
137 continue;
138 for_all_material_types(m) {
139 p_materials[m] += production_at(ux, uy, m);
140 }
141 }
142 for_all_material_types(m) {
143 if (0 < um_consumption_per_size(u, m))
144 szmax = min(szmax, p_materials[m] / um_consumption_per_size(u, m));
145 }
146 if (szmax < u_ai_minimal_size_goal(u))
147 return FALSE;
148 return TRUE;
149 }
150
151 /* ACP Estimates */
152
153 namespace Xconq {
154 //! Cache for maximum ACP of utypes without enhancing effects.
155 int *cv__acp_max_wo_effects = NULL;
156 //! Cache for maximum ACP per turn of utypes without enhancing effects.
157 int *cv__acp_per_turn_max_wo_effects = NULL;
158 }
159
160 //! Maximum ACP u can have without enhancing effects.
161
162 int
acp_max_wo_effects(int u)163 acp_max_wo_effects(int u)
164 {
165 int acp = 0;
166 int u2 = NONUTYPE;
167
168 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
169 if (!Xconq::cv__acp_max_wo_effects) {
170 Xconq::cv__acp_max_wo_effects = (int *)xmalloc(numutypes * sizeof(int));
171 for_all_unit_types(u2) {
172 /* ACP-indep u2 has no ACP. */
173 if (u_acp_independent(u2))
174 continue;
175 /* Calculate ACP. */
176 if (uprop_i_default(u_acp_max) != u_acp_max(u2))
177 acp = u_acp_max(u2);
178 else if (uprop_i_default(u_acp_turn_max) != u_acp_turn_max(u2))
179 acp = u_acp_turn_max(u2);
180 else
181 acp = u_acp(u2);
182 acp = max(acp, u_acp_turn_min(u2));
183 acp = max(acp, u_acp_min(u2));
184 Xconq::cv__acp_max_wo_effects[u2] = acp;
185 }
186 }
187 return Xconq::cv__acp_max_wo_effects[u];
188 }
189
190 //! Maximum ACP per turn u can have without enhancing effects.
191
192 int
acp_per_turn_max_wo_effects(int u)193 acp_per_turn_max_wo_effects(int u)
194 {
195 int acp = 0;
196 int u2 = NONUTYPE;
197
198 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
199 if (!Xconq::cv__acp_per_turn_max_wo_effects) {
200 Xconq::cv__acp_per_turn_max_wo_effects =
201 (int *)xmalloc(numutypes * sizeof(int));
202 for_all_unit_types(u2) {
203 /* ACP-indep u2 has no ACP. */
204 if (u_acp_independent(u2))
205 continue;
206 /* Calculate clipped basic ACP. */
207 acp = u_acp(u2);
208 if (uprop_i_default(u_acp_turn_max) != u_acp_turn_max(u2))
209 acp = min(acp, u_acp_turn_max(u2));
210 acp = max(acp, u_acp_turn_min(u2));
211 if (uprop_i_default(u_acp_max) != u_acp_max(u2))
212 acp = min(acp, u_acp_max(u2));
213 acp = max(acp, u_acp_min(u2));
214 Xconq::cv__acp_per_turn_max_wo_effects[u2] = acp;
215 }
216 }
217 return Xconq::cv__acp_per_turn_max_wo_effects[u];
218 }
219
220 /* Speed Estimates */
221
222 namespace Xconq {
223 //! Cache for maximum speed of utypes without enhancing effects.
224 int *cv__speed_max_wo_effects = NULL;
225 }
226
227 //! Maximum speed u can have without enhancing effects.
228
229 int
speed_max_wo_effects(int u)230 speed_max_wo_effects(int u)
231 {
232 int speed = 0;
233 int u2 = NONUTYPE;
234
235 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
236 if (!Xconq::cv__speed_max_wo_effects) {
237 Xconq::cv__speed_max_wo_effects =
238 (int *)xmalloc(numutypes * sizeof(int));
239 for_all_unit_types(u2) {
240 /* Immobile utype has no speed. */
241 if (!mobile(u2))
242 continue;
243 /* Calculate clipped basic speed. */
244 speed = u_speed(u2);
245 speed = min(speed, u_speed_max(u2));
246 speed = max(speed, u_speed_min(u2));
247 Xconq::cv__speed_max_wo_effects[u2] = speed;
248 }
249 }
250 return Xconq::cv__speed_max_wo_effects[u];
251 }
252
253 /* MP Estimates */
254
255 namespace Xconq{
256 //! Cache for maximum MP per turn of utypes.
257 int *cv__mp_per_turn_max = NULL;
258 }
259
260 //! Maximum MP u can get per turn.
261
262 int
mp_per_turn_max(int u)263 mp_per_turn_max(int u)
264 {
265 int acpmax = 0, speedmax = 0;
266 int u2 = NONUTYPE;
267
268 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
269 if (!Xconq::cv__mp_per_turn_max) {
270 Xconq::cv__mp_per_turn_max = (int *)xmalloc(numutypes * sizeof(int));
271 for_all_unit_types(u2) {
272 /* Immobile utypes have 0 MP per turn. */
273 if (!mobile(u2))
274 continue;
275 /* Calculate modest max ACP per turn. */
276 acpmax = acp_per_turn_max_wo_effects(u2);
277 /* If u is ACP-indep, then tell it no (for now). */
278 if (u_acp_independent(u2) || (0 >= acpmax))
279 return 0;
280 /* Calculate modest max speed. */
281 speedmax = speed_max_wo_effects(u2);
282 /* Calculate max MP per turn. */
283 Xconq::cv__mp_per_turn_max[u2] =
284 (((acpmax * speedmax) / 100) + u_free_mp(u2));
285 }
286 }
287 return Xconq::cv__mp_per_turn_max[u];
288 }
289
290 /* Number of Moves Estimates */
291
292 namespace Xconq{
293 //! Cache of maximum moves utypes can make per turn on t.
294 int **cv__moves_per_turn_max_on_t = NULL;
295 }
296
297 //! Maximum moves u can make per turn on t.
298
299 int
moves_per_turn_max(int u,int t)300 moves_per_turn_max(int u, int t)
301 {
302 int moves = 0, mpmax = 0, cost = 0;
303 int u2 = NONUTYPE;
304 int t2 = NONTTYPE;
305
306 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
307 assert_error(is_terrain_type(t),
308 "Attempted to manipulate an invalid ttype");
309 if (!Xconq::cv__moves_per_turn_max_on_t) {
310 Xconq::cv__moves_per_turn_max_on_t =
311 (int **)xmalloc(numutypes * sizeof(int *));
312 for_all_unit_types(u2)
313 moves_per_turn_max(u2, t);
314 }
315 if (!Xconq::cv__moves_per_turn_max_on_t[u]) {
316 Xconq::cv__moves_per_turn_max_on_t[u] =
317 (int *)xmalloc(numttypes * sizeof(int));
318 for_all_terrain_types(t2) {
319 /* Immobile units have 0 moves per turn. */
320 if (!mobile(u))
321 continue;
322 /* Calculate max MP per turn. */
323 mpmax = mp_per_turn_max(u);
324 /* Calculate enter+leave cost.
325 Does not consider border/connector traversal. */
326 cost = ut_mp_to_enter(u, t2) + ut_mp_to_leave(u, t2);
327 /* Calculate moves per turn. */
328 /* If cost is apparently 0 or negative,
329 we still need to charge 1 MP per move. */
330 if (0 >= cost)
331 moves = mpmax;
332 else
333 moves = mpmax / cost;
334 Xconq::cv__moves_per_turn_max_on_t[u][t2] = moves;
335 }
336 }
337 return Xconq::cv__moves_per_turn_max_on_t[u][t];
338 }
339
340 namespace Xconq {
341 //! Cache of max movement range of u if producing m on t.
342 int ***cv__move_range_max_on_t_with_m = NULL;
343 //! Cache of max movement range of u on t.
344 int **cv__move_range_max_on_t = NULL;
345 }
346
347 //! Max movement range of u if producing m on t, and given an amount of m.
348 /*
349 If amount of m is negative,
350 then assume unit storage or side treasury capacity.
351 */
352
353 int
move_range_max_on(int u,int t,int m,int amt)354 move_range_max_on(int u, int t, int m, int amt)
355 {
356 int range = INT_MAX, ptivity = 0, netprod = 0, moves = 0, consump = 0;
357 int amt2 = 0;
358 int u2 = NONUTYPE;
359 int t2 = NONTTYPE;
360 int m2 = NONMTYPE;
361
362 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
363 assert_error(is_terrain_type(t),
364 "Attempted to manipulate an invalid ttype");
365 assert_error(is_material_type(m),
366 "Attempted to manipulate an invalid mtype");
367 /* Prepare per-utype cache, if needed. */
368 if ((0 > amt) && !Xconq::cv__move_range_max_on_t_with_m) {
369 Xconq::cv__move_range_max_on_t_with_m =
370 (int ***)xmalloc(numutypes * sizeof(int **));
371 for_all_unit_types(u2)
372 move_range_max_on(u2, t, m, amt);
373 }
374 /* Prepare per-ttype cache, if needed. */
375 if ((0 > amt) && !Xconq::cv__move_range_max_on_t_with_m[u]) {
376 Xconq::cv__move_range_max_on_t_with_m[u] =
377 (int **)xmalloc(numttypes * sizeof(int *));
378 for_all_terrain_types(t2)
379 move_range_max_on(u, t2, m, amt);
380 }
381 /* Prepare per-mtype cache, if needed. */
382 if ((0 > amt) && !Xconq::cv__move_range_max_on_t_with_m[u][t]) {
383 Xconq::cv__move_range_max_on_t_with_m[u][t] =
384 (int *)xmalloc(numttypes * sizeof(int));
385 for_all_material_types(m2) {
386 if (could_take_from_treasury(u, m2))
387 amt2 = g_treasury_size();
388 else
389 amt2 = um_storage_x(u, m2);
390 Xconq::cv__move_range_max_on_t_with_m[u][t][m2] =
391 move_range_max_on(u, t, m2, amt2);
392 }
393 }
394 /* Return cached result, if available. */
395 if (0 > amt)
396 return Xconq::cv__move_range_max_on_t_with_m[u][t][m];
397 /* If u is immobile, then it has no operating range. */
398 if (!mobile(u))
399 return -1;
400 /* If material is not consumed per turn or by movement,
401 then it does not affect the operating range. */
402 if ((0 >= um_base_consumption(u, m))
403 || (0 >= um_consumption_per_move(u, m)))
404 return INT_MAX;
405 /* If u could never be on t, then it has no operating range on t. */
406 if (!could_be_on(u, t))
407 return -1;
408 /* Net production at each stop on t. */
409 ptivity = ut_productivity(u, t);
410 ptivity = max(ptivity, um_productivity_min(u, m));
411 ptivity = min(ptivity, um_productivity_max(u, m));
412 netprod = (um_base_production(u, m) * ptivity * 2) / 100;
413 netprod -= um_base_consumption(u, m);
414 /* Max moves per turn on t. */
415 moves = moves_per_turn_max(u, t);
416 /* Consumption per turn. */
417 consump = netprod + (moves * um_consumption_per_move(u, m));
418 /* Calculate range. */
419 range = (amt / consump) * moves * u_move_range(u);
420 amt = amt % consump;
421 if (amt)
422 range += (amt / um_consumption_per_move(u, m)) * u_move_range(u);
423 return range;
424 }
425
426 //! Max movement range of u on t, and given amounts of mtypes.
427 /*
428 If amount array is NULL, then pass -1 for each individual material check.
429 */
430
431 int
move_range_max(int u,int t,int * amt)432 move_range_max(int u, int t, int *amt)
433 {
434 int range = INT_MAX;
435 int u2 = NONUTYPE;
436 int t2 = NONTTYPE;
437 int m = NONMTYPE;
438
439 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
440 assert_error(is_terrain_type(t),
441 "Attempted to manipulate an invalid ttype");
442 /* Prepare per-utype cache, if needed. */
443 if (!amt && !Xconq::cv__move_range_max_on_t) {
444 Xconq::cv__move_range_max_on_t =
445 (int **)xmalloc(numutypes * sizeof(int *));
446 for_all_unit_types(u2)
447 move_range_max(u2, t, amt);
448 }
449 /* Prepare per-ttype cache, if needed. */
450 if (!amt && !Xconq::cv__move_range_max_on_t[u]) {
451 Xconq::cv__move_range_max_on_t[u] =
452 (int *)xmalloc(numttypes * sizeof(int));
453 for_all_material_types(m)
454 tmp_m_array[m] = -1;
455 for_all_terrain_types(t2)
456 Xconq::cv__move_range_max_on_t[u][t2] =
457 move_range_max(u, t2, tmp_m_array);
458 }
459 /* Return cached value, if available. */
460 if (!amt)
461 return Xconq::cv__move_range_max_on_t[u][t];
462 /* If u is immobile, then it has no operating range. */
463 if (!mobile(u))
464 return -1;
465 /* If u could never be on t, then it has no operating range on t. */
466 if (!could_be_on(u, t))
467 return -1;
468 /* Determine range by most constrictive material. */
469 for_all_material_types(m)
470 range = min(range, move_range_max_on(u, t, m, amt[m]));
471 return range;
472 }
473
474 //! Best movement range of u, given amounts of mtypes.
475
476 int
move_range_best(int u,int * amt)477 move_range_best(int u, int *amt)
478 {
479 int range = -1;
480 int t = NONTTYPE;
481
482 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
483 for_all_terrain_types(t)
484 range = max(range, move_range_max(u, t, amt));
485 return range;
486 }
487
488 //! Worst movement range of u, given amounts of mtypes.
489
490 int
move_range_worst(int u,int * amt)491 move_range_worst(int u, int *amt)
492 {
493 int range = INT_MAX, range2 = -1;
494 int t = NONTTYPE;
495
496 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
497 for_all_terrain_types(t) {
498 range2 = move_range_max(u, t, amt);
499 if (0 > range2)
500 continue;
501 range = min(range, range2);
502 }
503 return range;
504 }
505
506 //! Basic worth as a mover.
507
508 int
mover_worth(int u)509 mover_worth(int u)
510 {
511 int mp = 0, worth = 0, movesmean = 0, movesmax = INT_MAX;
512 int availtcount = 0, safetcount = 0;
513 int m = NONMTYPE;
514 int t = NONTTYPE;
515
516 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
517 /* If utype could move... */
518 if (could_move(u, u)) {
519 /* For ACP-dependent utypes, we use the basic MP-per-turn as a basis. */
520 if (!u_acp_independent(u)) {
521 if (0 < u_speed(u)) {
522 mp = (u_acp(u) * u_speed(u)) / 100;
523 }
524 else
525 mp = 0;
526 /* Add in free MP. */
527 mp += u_free_mp(u);
528 }
529 /* Determine max material-limited moves per turn. */
530 for_all_material_types(m) {
531 if (0 < um_consumption_per_move(u, m)) {
532 if (0 < um_storage_x(u, m) && !um_takes_from_treasury(u, m))
533 movesmax = min(movesmax,
534 um_storage_x(u, m) /
535 um_consumption_per_move(u, m));
536 }
537 }
538 /* For ACP-dependent utypes,
539 determine mean terrain-limited moves per turn. */
540 /* TODO: Weight by popularity of terrain. */
541 if (!u_acp_independent(u)) {
542 for_all_terrain_types(t) {
543 if (t_is_cell(t) || t_is_coating(t)) {
544 if (0 > ut_mp_to_leave(u, t))
545 tmp_t_array[t] = 0;
546 /* Q: Is this correct? */
547 else if (0 > ut_mp_to_enter(u, t))
548 tmp_t_array[t] = 0;
549 else if ((0 < ut_mp_to_enter(u, t))
550 || (0 < ut_mp_to_leave(u, t)))
551 tmp_t_array[t] =
552 mp / (ut_mp_to_enter(u, t) + ut_mp_to_leave(u, t));
553 else
554 tmp_t_array[t] = mp;
555 }
556 else if (t_is_connection(t) || t_is_border(t)) {
557 if (0 < ut_mp_to_traverse(u, t))
558 tmp_t_array[t] = mp / ut_mp_to_traverse(u, t);
559 else if (0 > ut_mp_to_traverse(u, t))
560 tmp_t_array[t] = 0;
561 else
562 tmp_t_array[t] = mp;
563 }
564 }
565 for_all_terrain_types(t) {
566 movesmean += tmp_t_array[t];
567 if (0 < tmp_t_array[t])
568 ++availtcount;
569 }
570 if (availtcount)
571 movesmean /= availtcount;
572 else
573 movesmean = 0;
574 movesmean = min(movesmax, movesmean);
575 }
576 /* Else, ACP-independent utype. */
577 else
578 movesmean = movesmax;
579 /* Prepare for further worth calcs. */
580 worth = movesmean * 1000;
581 /* Penalize for all ttypes in which
582 accidents, wrecks, or disappearances may occur. */
583 for_all_terrain_types(t) {
584 if ((0 < ut_accident_vanish(u, t))
585 || ((0 < ut_accident_hit(u, t))
586 && (0 < ut_accident_damage(u, t)))
587 || ut_vanishes_on(u, t) || ut_wrecks_on(u, t))
588 tmp_t_array[t] = 1;
589 else
590 tmp_t_array[t] = 0;
591 }
592 for_all_terrain_types(t)
593 safetcount += (1 - tmp_t_array[t]);
594 worth = (worth * safetcount) / numttypes;
595 }
596 /* If utype could not move, then it is worthless as a mover. */
597 else
598 worth = 0;
599 return max(0, worth);
600 }
601
602 //! Set basic worth as a mover.
603
604 void
set_mover_worth(int u,int n)605 set_mover_worth(int u, int n)
606 {
607 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
608 assert_error(between(PROPLO, n, PROPHI),
609 "Attempted to set an uprop out-of-bounds");
610 utypes[u].aimoverworth = n;
611 }
612
613 //! Set basic worths as movers, if necessary.
614
615 void
maybe_set_mover_worths(void)616 maybe_set_mover_worths(void)
617 {
618 int u = NONUTYPE;
619 int worthmax = 0;
620 int mustcalc = FALSE;
621
622 for_all_unit_types(u) {
623 if (uprop_i_default(u_ai_mover_worth) == u_ai_mover_worth(u)) {
624 mustcalc = TRUE;
625 break;
626 }
627 }
628 if (mustcalc) {
629 for_all_unit_types(u) {
630 tmp_u_array[u] = mover_worth(u);
631 worthmax = max(worthmax, tmp_u_array[u]);
632 }
633 for_all_unit_types(u)
634 set_mover_worth(u,
635 normalize_on_pmscale(tmp_u_array[u],
636 worthmax, 10000));
637 }
638 }
639
640 //! Basic worth as a depot.
641
642 int
depot_worth(int u)643 depot_worth(int u)
644 {
645 int worth = 0, penalties = 0;
646 int m = NONMTYPE;
647
648 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
649 for_all_material_types(m) {
650 if (0 < um_storage_x(u, m)) {
651 penalties = 0;
652 /* Storage capacity is basis. */
653 tmp_m_array[m] = um_storage_x(u, m);
654 /* Penalize or reward for receiving range from other units. */
655 if (-1 == um_inlength(u, m))
656 penalties += 2;
657 else if (0 == um_inlength(u, m))
658 ++penalties;
659 else if (1 < um_inlength(u, m))
660 tmp_m_array[m] *= um_inlength(u, m);
661 /* Penalize or reward for receiving range from cells. */
662 if (1 == g_backdrop_model()) {
663 if (-1 == um_tu_in_length(u, m))
664 penalties += 2;
665 else if (0 == um_tu_in_length(u, m))
666 ++penalties;
667 else if (1 < um_tu_in_length(u, m))
668 tmp_m_array[m] *= um_tu_in_length(u, m);
669 }
670 /* Apply penalties. */
671 if (penalties)
672 tmp_m_array[m] /= (penalties + 1);
673 }
674 else
675 tmp_m_array[m] = 0;
676 }
677 /* Sum per-material worths into master worth. */
678 for_all_material_types(m)
679 worth += tmp_m_array[m];
680 return max(0, worth);
681 }
682
683 //! Set basic worth as a depot.
684
685 void
set_depot_worth(int u,int n)686 set_depot_worth(int u, int n)
687 {
688 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
689 assert_error(between(PROPLO, n, PROPHI),
690 "Attempted to set an uprop out-of-bounds");
691 utypes[u].aidepotworth = n;
692 }
693
694 //! Set basic worths as depots, if necessary.
695
696 void
maybe_set_depot_worths(void)697 maybe_set_depot_worths(void)
698 {
699 int u = NONUTYPE;
700 int worthmax = 0;
701 int mustcalc = FALSE;
702
703 for_all_unit_types(u) {
704 if (uprop_i_default(u_ai_depot_worth) == u_ai_depot_worth(u)) {
705 mustcalc = TRUE;
706 break;
707 }
708 }
709 if (mustcalc) {
710 for_all_unit_types(u) {
711 tmp_u_array[u] = depot_worth(u);
712 worthmax = max(worthmax, tmp_u_array[u]);
713 }
714 for_all_unit_types(u)
715 set_depot_worth(u,
716 normalize_on_pmscale(tmp_u_array[u],
717 worthmax, 10000));
718 }
719 }
720
721 //! Basic worth as a distributor.
722
723 int
distributor_worth(int u)724 distributor_worth(int u)
725 {
726 int worth = 0, penalties = 0;
727 int m = NONMTYPE;
728
729 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
730 for_all_material_types(m) {
731 if (0 < um_storage_x(u, m)) {
732 penalties = 0;
733 /* Storage capacity is basis. */
734 tmp_m_array[m] = um_storage_x(u, m);
735 /* Penalize or reward for receiving range from other units. */
736 if (-1 == um_outlength(u, m))
737 penalties += 2;
738 else if (0 == um_outlength(u, m))
739 ++penalties;
740 else if (1 < um_outlength(u, m))
741 tmp_m_array[m] *= um_outlength(u, m);
742 /* Penalize or reward for receiving range from cells. */
743 if (1 == g_backdrop_model()) {
744 if (-1 == um_ut_out_length(u, m))
745 penalties += 2;
746 else if (0 == um_ut_out_length(u, m))
747 ++penalties;
748 else if (1 < um_ut_out_length(u, m))
749 tmp_m_array[m] *= um_ut_out_length(u, m);
750 }
751 /* Apply penalties. */
752 if (penalties)
753 tmp_m_array[m] /= (penalties + 1);
754 }
755 else
756 tmp_m_array[m] = 0;
757 }
758 /* Sum per-material worths into master worth. */
759 for_all_material_types(m)
760 worth += tmp_m_array[m];
761 return max(0, worth);
762 }
763
764 //! Set basic worth as a distributor.
765
766 void
set_distributor_worth(int u,int n)767 set_distributor_worth(int u, int n)
768 {
769 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
770 assert_error(between(PROPLO, n, PROPHI),
771 "Attempted to set an uprop out-of-bounds");
772 utypes[u].aidistributorworth = n;
773 }
774
775 //! Set basic worths as distributors, if necessary.
776
777 void
maybe_set_distributor_worths(void)778 maybe_set_distributor_worths(void)
779 {
780 int u = NONUTYPE;
781 int worthmax = 0;
782 int mustcalc = FALSE;
783
784 for_all_unit_types(u) {
785 if (uprop_i_default(u_ai_distributor_worth) ==
786 u_ai_distributor_worth(u)) {
787 mustcalc = TRUE;
788 break;
789 }
790 }
791 if (mustcalc) {
792 for_all_unit_types(u) {
793 tmp_u_array[u] = distributor_worth(u);
794 worthmax = max(worthmax, tmp_u_array[u]);
795 }
796 for_all_unit_types(u)
797 set_distributor_worth(u,
798 normalize_on_pmscale(tmp_u_array[u],
799 worthmax, 10000));
800 }
801 }
802
803 //! Basic worth as a producer.
804 /*! \todo Consider occupant consumption. */
805
806 int
producer_worth(int u)807 producer_worth(int u)
808 {
809 int worth = 0, ptivityavg = 0, ptivity = 0;
810 int m = NONMTYPE;
811 int t = NONTTYPE;
812
813 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
814 /* Average productivity. */
815 for_all_terrain_types(t) {
816 tmp_t_array[t] = ut_productivity(u, t);
817 tmp_t_array[t] += ut_productivity_adj(u, t);
818 }
819 ptivityavg = 0;
820 for_all_terrain_types(t)
821 ptivityavg += tmp_t_array[t];
822 ptivityavg /= numttypes;
823 /* Account for automatic base production, and explicit production. */
824 for_all_material_types(m) {
825 ptivity = max(ptivityavg, um_productivity_min(u, m));
826 ptivity = min(ptivity, um_productivity_max(u, m));
827 tmp_m_array[m] = (um_base_production(u, m) * ptivity) / 100;
828 tmp_m_array[m] = max(0, tmp_m_array[m] - um_base_consumption(u, m));
829 if (0 < um_acp_to_produce(u, m))
830 tmp_m_array[m] +=
831 (um_material_per_production(u, m) / um_acp_to_produce(u, m));
832 }
833 /* Account for automatic base production as an occupant. */
834 if (could_be_occupant(u)) {
835 for_all_material_types(m) {
836 tmp_m_array[m] += um_occ_production(u, m);
837 tmp_m_array[m] =
838 max(0,
839 tmp_m_array[m] -
840 ((um_base_consumption(u, m) *
841 um_consumption_as_occupant(u, m)) / 100));
842 }
843 }
844 /* Account for advanced unit production from terrain. */
845 if (u_advanced(u)) {
846 for_all_material_types(m) {
847 for_all_terrain_types(t)
848 tmp_m_array[m] += tm_prod_from_terrain(t, m);
849 }
850 }
851 /* Sum all contributions into a worth. */
852 for_all_material_types(m)
853 worth += tmp_m_array[m];
854 return max(0, worth);
855 }
856
857 //! Set basic worth as a producer.
858
859 void
set_producer_worth(int u,int n)860 set_producer_worth(int u, int n)
861 {
862 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
863 assert_error(between(PROPLO, n, PROPHI),
864 "Attempted to set an uprop out-of-bounds");
865 utypes[u].aiproducerworth = n;
866 }
867
868 //! Set basic worths as producers, if necessary.
869
870 void
maybe_set_producer_worths(void)871 maybe_set_producer_worths(void)
872 {
873 int u = NONUTYPE;
874 int worthmax = 0;
875 int mustcalc = FALSE;
876
877 for_all_unit_types(u) {
878 if (uprop_i_default(u_ai_producer_worth) == u_ai_producer_worth(u)) {
879 mustcalc = TRUE;
880 break;
881 }
882 }
883 if (mustcalc) {
884 for_all_unit_types(u) {
885 tmp_u_array[u] = producer_worth(u);
886 worthmax = max(worthmax, tmp_u_array[u]);
887 }
888 for_all_unit_types(u)
889 set_producer_worth(u,
890 normalize_on_pmscale(tmp_u_array[u],
891 worthmax, 10000));
892 }
893 }
894
895 //! Given unit's worth as a producer on a given known cell.
896
897 int
producer_worth_on_known(Unit * producer,int x,int y)898 producer_worth_on_known(Unit *producer, int x, int y)
899 {
900 int worth = 0;
901 int u = NONUTYPE;
902 int m = NONMTYPE;
903 int t = NONTTYPE;
904
905 assert_error(producer, "Attempted to access an out-of-play unit");
906 assert_warning_return(inside_area(x, y),
907 "Attempted to access an out-of-area cell", 0);
908 u = producer->type;
909 /* Can producer survive on given known cell? */
910 if (!valid(can_survive_on_known(producer, x, y)))
911 return 0;
912 /* Production at the given cell. */
913 productivity_on_known(tmp_m_array, u, producer->side, x, y);
914 for_all_material_types(m)
915 tmp_m_array[m] *= um_base_production(u, m);
916 for_all_material_types(m)
917 worth += tmp_m_array[m];
918 /* Account for advanced unit production from terrain. */
919 t = vterrain(terrain_view(producer->side, x, y));
920 if (u_advanced(u)) {
921 for_all_material_types(m)
922 worth += production_at(x, y, m);
923 }
924 /* Subtract off consumption. */
925 for_all_material_types(m)
926 worth -= um_base_consumption(u, m);
927 return max(0, worth);
928 }
929
930 //! Basic worth as a production enhancer.
931
932 int
prod_enhancer_worth(int u)933 prod_enhancer_worth(int u)
934 {
935 int worth = 0, ucount = 0;
936 int m = NONMTYPE;
937 int u2 = NONUTYPE;
938
939 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
940 /* Basis for production enhancement worth. */
941 for_all_material_types(m) {
942 tmp_m_array[m] = 0;
943 if (!um_occ_add_production(u, m)
944 && (100 == um_occ_mult_production(u, m)))
945 continue;
946 tmp_m_array[m] = 100 + (100 * um_occ_add_production(u, m));
947 tmp_m_array[m] =
948 (tmp_m_array[m] * um_occ_mult_production(u, m)) / 100;
949 }
950 for_all_material_types(m)
951 worth += tmp_m_array[m];
952 /* Multiply by number of utypes this could be occupant of. */
953 for_all_unit_types(u2) {
954 if (could_be_occupant_of(u, u2))
955 ++ucount;
956 }
957 worth *= ucount;
958 return max(0, worth);
959 }
960
961 //! Set basic worth as a production enhancer.
962
963 void
set_prod_enhancer_worth(int u,int n)964 set_prod_enhancer_worth(int u, int n)
965 {
966 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
967 assert_error(between(PROPLO, n, PROPHI),
968 "Attempted to set an uprop out-of-bounds");
969 utypes[u].aiprodenhancerworth = n;
970 }
971
972 //! Set basic worths as production enhancers, if necessary.
973
974 void
maybe_set_prod_enhancer_worths(void)975 maybe_set_prod_enhancer_worths(void)
976 {
977 int u = NONUTYPE;
978 int worthmax = 0;
979 int mustcalc = FALSE;
980
981 for_all_unit_types(u) {
982 if (uprop_i_default(u_ai_prod_enhancer_worth) ==
983 u_ai_prod_enhancer_worth(u)) {
984 mustcalc = TRUE;
985 break;
986 }
987 }
988 if (mustcalc) {
989 for_all_unit_types(u) {
990 tmp_u_array[u] = prod_enhancer_worth(u);
991 worthmax = max(worthmax, tmp_u_array[u]);
992 }
993 for_all_unit_types(u)
994 set_prod_enhancer_worth(u,
995 normalize_on_pmscale(tmp_u_array[u],
996 worthmax, 10000));
997 }
998 }
999
1000 int
base_worth_for(int u,int u2)1001 base_worth_for(int u, int u2)
1002 {
1003 int worth = 0;
1004 int m = NONMTYPE;
1005
1006 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
1007 assert_error(is_unit_type(u2), "Attempted to manipulate an invalid utype");
1008 /* If u could neither be a depot nor a producer,
1009 then it cannot be a base either. */
1010 if ((0 >= u_ai_depot_worth(u)) && (0 >= u_ai_producer_worth(u)))
1011 return 0;
1012 /* If u2 could never occupy u, then u cannot be a base for u2. */
1013 if (!could_be_occupant_of(u2, u))
1014 return 0;
1015 /* Determine which materials both u and u2 store. */
1016 /* We assume that if u2 is storing something, then it is for consumption. */
1017 for_all_material_types(m) {
1018 if (um_storage_x(u, m) && um_storage_x(u2, m))
1019 tmp_m_array[m] = um_storage_x(u, m);
1020 else
1021 tmp_m_array[m] = 0;
1022 }
1023 /* Calculate worth. */
1024 for_all_material_types(m)
1025 worth += tmp_m_array[m];
1026 worth = (worth * (u_ai_depot_worth(u) + u_ai_producer_worth(u))) / 10000;
1027 return max(0, worth);
1028 }
1029
1030 void
set_base_worth_for(int u,int u2,int n)1031 set_base_worth_for(int u, int u2, int n)
1032 {
1033 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
1034 assert_error(is_unit_type(u2), "Attempted to manipulate an invalid utype");
1035 assert_error(between(TABLO, n, TABHI),
1036 "Attempted to set a table out-of-bounds");
1037 assert_error(uuaibaseworthfor,
1038 "Attempted to set value in unallocated table");
1039 uuaibaseworthfor[numutypes * u + u2] = n;
1040 }
1041
1042 void
maybe_set_base_worths_for(void)1043 maybe_set_base_worths_for(void)
1044 {
1045 int u = NONUTYPE, u2 = NONUTYPE;
1046 int worthmax = 0;
1047 int mustcalc = FALSE;
1048 int i = 0;
1049
1050 if (!uuaibaseworthfor)
1051 mustcalc = TRUE;
1052 if (mustcalc) {
1053 for (i = 0; tabledefns[i].name; ++i) {
1054 if (!strcmp("ai-base-worth-for", tabledefns[i].name)) {
1055 allocate_table(i, FALSE);
1056 break;
1057 }
1058 }
1059 if (!tabledefns[i].table)
1060 run_error("No 'ai-base-worth-for' table allocated");
1061 for_all_unit_types(u) {
1062 for_all_unit_types(u2) {
1063 (tmp_uu_array[u])[u2] = base_worth_for(u, u2);
1064 worthmax = max(worthmax, (tmp_uu_array[u])[u2]);
1065 }
1066 }
1067 for_all_unit_types(u) {
1068 for_all_unit_types(u2)
1069 set_base_worth_for(u, u2,
1070 normalize_on_pmscale((tmp_uu_array[u])[u2],
1071 worthmax, 10000));
1072 }
1073 }
1074 }
1075
1076 int
base_worth(int u)1077 base_worth(int u)
1078 {
1079 int worth = 0;
1080 int u2 = NONUTYPE;
1081
1082 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
1083 for_all_unit_types(u2)
1084 worth += uu_ai_base_worth_for(u, u2);
1085 return max(0, worth);
1086 }
1087
1088 void
set_base_worth(int u,int n)1089 set_base_worth(int u, int n)
1090 {
1091 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
1092 assert_error(between(PROPLO, n, PROPHI),
1093 "Attempted to set an uprop out-of-bounds");
1094 utypes[u].aibaseworth = n;
1095 }
1096
1097 void
maybe_set_base_worths(void)1098 maybe_set_base_worths(void)
1099 {
1100 int u = NONUTYPE;
1101 int worthmax = 0;
1102 int mustcalc = FALSE;
1103
1104 for_all_unit_types(u) {
1105 if (uprop_i_default(u_ai_base_worth) == u_ai_base_worth(u)) {
1106 mustcalc = TRUE;
1107 break;
1108 }
1109 }
1110 if (mustcalc) {
1111 for_all_unit_types(u) {
1112 tmp_u_array[u] = base_worth(u);
1113 worthmax = max(worthmax, tmp_u_array[u]);
1114 }
1115 for_all_unit_types(u)
1116 set_base_worth(u,
1117 normalize_on_pmscale(tmp_u_array[u],
1118 worthmax, 10000));
1119 }
1120 }
1121
1122 /* Construction Questions */
1123
1124 int
can_create_in(Unit * actor,Unit * creator,int u3,Unit * transport)1125 can_create_in(Unit *actor, Unit *creator, int u3, Unit *transport)
1126 {
1127 int rslt = A_ANY_OK;
1128 int u2 = NONUTYPE;
1129 int x = -1, y = -1;
1130 Side *side = NULL;
1131 UnitView *uvtransport = NULL, *uvubertransport = NULL;
1132
1133 assert_error(in_play(transport),
1134 "AI Create Check: Attempted to access an out-of-play transport");
1135 x = transport->x; y = transport->y;
1136 if (!valid(rslt = can_create_common(actor, creator, u3, x, y)))
1137 return rslt;
1138 u2 = creator->type;
1139 side = actor->side;
1140 uvtransport = find_unit_view(side->see_all ? NULL : side, transport);
1141 // If we cannot see the transport for some reason,
1142 // then we cannot create in it.
1143 if (!uvtransport)
1144 return A_ANY_CANNOT_DO;
1145 // Handle the special case of merging.
1146 // TODO: Make this a separate action?
1147 if (u_advanced(transport->type)
1148 && creator->transport && (creator->transport == transport)
1149 && (transport->type == u3))
1150 return A_ANY_OK;
1151 // Check permissions up the transport chain.
1152 if (uvtransport->transport) {
1153 for (uvubertransport = uvtransport->transport;
1154 uvubertransport->transport;
1155 uvubertransport = uvubertransport->transport) {
1156 if (!trusted_side(side, side_n(uvubertransport->siden)))
1157 return A_ANY_CANNOT_DO;
1158 }
1159 }
1160 // Check against transport's capacity.
1161 if (!valid(rslt = can_be_in(u3, side, uvtransport)))
1162 return rslt;
1163 return A_ANY_OK;
1164 }
1165
1166 int
can_create_at(Unit * actor,Unit * creator,int u3,int x,int y)1167 can_create_at(Unit *actor, Unit *creator, int u3, int x, int y)
1168 {
1169 static int *p_without;
1170
1171 int rslt = A_ANY_OK;
1172 int u2 = NONUTYPE;
1173 Side *side = NULL;
1174 int tv = UNSEEN;
1175 int t = NONTTYPE;
1176
1177 if (!valid(rslt = can_create_common(actor, creator, u3, x, y)))
1178 return rslt;
1179 u2 = creator->type;
1180 side = actor->side;
1181 // Check if cell is seen.
1182 // Do not attempt to create on an unseen cell, even if legal.
1183 tv = terrain_view(side, x, y);
1184 if (UNSEEN == tv)
1185 return A_ANY_CANNOT_DO;
1186 t = vterrain(tv);
1187 // Can new utype survive on cell?
1188 if (!valid(rslt = can_survive_on_known(u3, side, x, y))) {
1189 if (!((x == creator->x) && (y == creator->y)
1190 && (rslt == A_MOVE_DEST_FULL)))
1191 return rslt;
1192 }
1193 // Initialize the without-utypes array, if necessary.
1194 if (!p_without)
1195 p_without = (int *)xmalloc(numutypes * sizeof(int));
1196 // Clean out the without-utypes array, and creator utype to it.
1197 memset(p_without, 0, numutypes * sizeof(int));
1198 p_without[u2] = 1;
1199 // If creator is in same cell as future creation,
1200 // then we have other options.
1201 // Option 1: Creator is allowed to enter creation.
1202 // Option 2: Creator dies upon creation.
1203 if (!valid(rslt = can_survive_on_known(u3, side, x, y, p_without)))
1204 return rslt;
1205 return A_ANY_OK;
1206 }
1207
1208 /* Tooling Point Estimates */
1209
1210 int
tp_per_turn_est(Unit * unit,int u2)1211 tp_per_turn_est(Unit *unit, int u2)
1212 {
1213 int tp = 0, toolups = INT_MAX, copert = 0;
1214 int u = NONUTYPE;
1215 int m = NONMTYPE;
1216 int mlimits = FALSE;
1217 Side *side = NULL;
1218
1219 assert_warning_return(
1220 in_play(unit), "AI: Attempted to access an out-of-play unit", 0);
1221 assert_error(is_unit_type(u2), "AI: Encountered invalid unit type");
1222 u = unit->type;
1223 side = unit->side;
1224 // Quick test to see if we can even toolup for the given utype.
1225 if (0 >= uu_tp_per_toolup(u, u2))
1226 return 0;
1227 // Look at material limits on tooling up.
1228 for_all_material_types(m) {
1229 // Consumption per build.
1230 copert = um_consumption_per_tp(u2, m) * uu_tp_per_toolup(u, u2);
1231 copert += um_consumption_per_tooledup(u2, m);
1232 copert += um_consumption_per_toolup(u, m);
1233 // If this material is not consumed, then skip it.
1234 if (!copert)
1235 continue;
1236 mlimits = TRUE;
1237 // If constructor takes from treasury,
1238 // then estimate treasury limit on tooling up,
1239 // assuming this is the only constructor using the treasury for
1240 // the material in question.
1241 if (could_take_from_treasury(u, side, m))
1242 toolups = min(toolups, side->treasury[m] / copert);
1243 // Else, the builder has only its own stock to use.
1244 // We assume that the builder always has about the amount of
1245 // supply that it currently has on hand.
1246 else
1247 toolups = min(toolups, unit->supply[m] / copert);
1248 } // for all mtypes
1249 // If not ACP-indep and if build action actually costs ACP,
1250 // then ACP may affect number of builds.
1251 if (!u_acp_independent(u) && (0 < uu_acp_to_toolup(u, u2)))
1252 toolups =
1253 min(toolups,
1254 (acp_per_turn_max_wo_effects(u) / uu_acp_to_toolup(u, u2)));
1255 // Estimate TP per turn.
1256 tp = toolups * uu_tp_per_toolup(u, u2);
1257 return tp;
1258 }
1259
1260 /* Construction Point Estimates */
1261
1262 int
cp_per_turn_est(Unit * unit,int u2)1263 cp_per_turn_est(Unit *unit, int u2)
1264 {
1265 int cp = 0, builds = INT_MAX, coperb = 0;
1266 int u = NONUTYPE;
1267 int m = NONMTYPE;
1268 int mlimits = FALSE;
1269 Side *side = NULL;
1270
1271 assert_warning_return(
1272 in_play(unit), "AI: Attempted to access an out-of-play unit", 0);
1273 assert_error(is_unit_type(u2), "AI: Encountered invalid unit type");
1274 u = unit->type;
1275 side = unit->side;
1276 // Quick test to see if we can even build on the given utype.
1277 if (0 >= uu_cp_per_build(u, u2))
1278 return 0;
1279 // Look at material limits on building.
1280 for_all_material_types(m) {
1281 // Consumption per build.
1282 coperb = um_consumption_per_cp(u2, m) * uu_cp_per_build(u, u2);
1283 coperb += um_consumption_per_built(u2, m);
1284 coperb += um_consumption_per_build(u, m);
1285 // If this material is not consumed, then skip it.
1286 if (!coperb)
1287 continue;
1288 mlimits = TRUE;
1289 // If builder takes from treasury,
1290 // then estimate treasury limit on building,
1291 // assuming this is the only builder using the treasury for
1292 // the material in question.
1293 if (could_take_from_treasury(u, side, m))
1294 builds = min(builds, side->treasury[m] / coperb);
1295 // Else, the builder has only its own stock to use.
1296 // We assume that the builder always has about the amount of
1297 // supply that it currently has on hand.
1298 else
1299 builds = min(builds, unit->supply[m] / coperb);
1300 } // for all mtypes
1301 // If not ACP-indep and if build action actually costs ACP,
1302 // then ACP may affect number of builds.
1303 if (!u_acp_independent(u) && (0 < uu_acp_to_build(u, u2)))
1304 builds =
1305 min(builds,
1306 (acp_per_turn_max_wo_effects(u) / uu_acp_to_build(u, u2)));
1307 // Estimate CP per turn.
1308 cp = builds * uu_cp_per_build(u, u2);
1309 return cp;
1310 }
1311
1312 int
cp_gained_per_turn_est(Unit * unit,Side * side)1313 cp_gained_per_turn_est(Unit *unit, Side *side)
1314 {
1315 Unit *unit2 = NULL;
1316 Task *tasks2 = NULL;
1317 int id = -1;
1318 int u = NONUTYPE;
1319 int crate = 0;
1320
1321 assert_error(in_play(unit),
1322 "AI: Attempted to manipulate an out-of-play unit");
1323 // Useful info.
1324 id = unit->id;
1325 u = unit->type;
1326 if (!side)
1327 side = unit->side;
1328 // No construction if the specified side is an enemy.
1329 // Technically, we should not even be able to iterate through the units.
1330 if (enemy_side(side, unit->side))
1331 return 0;
1332 // If this unit can build itself, then count that contribution.
1333 if (unit->cp > u_cp_to_self_build(u))
1334 crate += u_cp_per_self_build(u);
1335 // Find all current builders and tally their contributions.
1336 for_all_side_units(side, unit2) {
1337 if (unit == unit2)
1338 continue;
1339 if (!is_active(unit2))
1340 continue;
1341 tasks2 = (unit2->plan ? unit2->plan->tasks : NULL);
1342 if (!tasks2)
1343 continue;
1344 if ((TASK_BUILD == tasks2->type)
1345 && ((id == unit2->creation_id) || (id == tasks2->args[1])))
1346 crate += cp_per_turn_est(unit2, u);
1347 }
1348 return crate;
1349 }
1350
1351 /* Hitpoint Estimates */
1352
1353 int
hp_per_turn_est(Unit * unit,int u2)1354 hp_per_turn_est(Unit *unit, int u2)
1355 {
1356 int hp = 0, repairs = INT_MAX, coperr = 0;
1357 int u = NONUTYPE;
1358 int m = NONMTYPE;
1359 int mlimits = FALSE;
1360 Side *side = NULL;
1361
1362 assert_warning_return(
1363 in_play(unit), "AI: Attempted to access an out-of-play unit", 0);
1364 assert_error(is_unit_type(u2), "AI: Encountered invalid unit type");
1365 u = unit->type;
1366 side = unit->side;
1367 // Could we even repair the given utype?
1368 if (!could_repair(u, u2) && !could_auto_repair(u, u2))
1369 return 0;
1370 // Look at material limits on repair.
1371 for_all_material_types(m) {
1372 // Consumption per repair.
1373 coperr = um_consumption_per_repaired(u2, m);
1374 coperr += um_consumption_per_repair(u, m);
1375 // If this material is not consumed, then skip it.
1376 if (!coperr)
1377 continue;
1378 mlimits = TRUE;
1379 // If repairer takes from treasury,
1380 // then estimate treasury limit on repairing,
1381 // assuming this is the only repairer using the treasury for
1382 // the material in question.
1383 if (could_take_from_treasury(u, side, m))
1384 repairs = min(repairs, side->treasury[m] / coperr);
1385 // Else, the repairer has only its own stock to use.
1386 // We assume that the repairer always has about the amount of
1387 // supply that it currently has on hand.
1388 else
1389 repairs = min(repairs, unit->supply[m] / coperr);
1390 } // for all mtypes
1391 // If not ACP-indep, explicit repair allowed, and action costs ACP,
1392 // then ACP may affect number of repairs.
1393 if (!u_acp_independent(u) && could_repair(u, u2)
1394 && (0 < uu_acp_to_repair(u, u2)))
1395 repairs =
1396 min(repairs,
1397 (acp_per_turn_max_wo_effects(u) / uu_acp_to_repair(u, u2)));
1398 // Estimate HP per turn.
1399 hp = repairs * (uu_hp_per_repair(u, u2) / 100);
1400 if (0 != (uu_hp_per_repair(u, u2) % 100))
1401 hp += ((repairs * (uu_hp_per_repair(u, u2) % 100)) / 100);
1402 return hp;
1403 }
1404
1405 int
hp_gained_per_turn_est(Unit * unit,Side * side)1406 hp_gained_per_turn_est(Unit *unit, Side *side)
1407 {
1408 Unit *unit2 = NULL;
1409 Task *tasks2 = NULL;
1410 int id = -1;
1411 int u = NONUTYPE, u2 = NONUTYPE;
1412 int rrate = 0, dist = 0;
1413
1414 assert_error(in_play(unit),
1415 "AI: Attempted to manipulate an out-of-play unit");
1416 // Useful info.
1417 id = unit->id;
1418 u = unit->type;
1419 if (!side)
1420 side = unit->side;
1421 // No repair if the specified side is an enemy.
1422 // Technically, we should not even be able to iterate through the units.
1423 if (enemy_side(side, unit->side))
1424 return 0;
1425 // If this unit can repair itself, then count that contribution.
1426 if ((0 < u_hp_recovery(u)) && (unit->hp >= u_hp_to_recover(u))) {
1427 rrate += (u_hp_recovery(u) / 100);
1428 if (49 < (u_hp_recovery(u) % 100))
1429 ++rrate;
1430 }
1431 // Iterate through all side units and sum their contributions.
1432 for_all_side_units(side, unit2) {
1433 if (!is_active(unit2))
1434 continue;
1435 u2 = unit2->type;
1436 tasks2 = (unit2->plan ? unit2->plan->tasks : NULL);
1437 if (!tasks2)
1438 continue;
1439 // Consider repairers dedicated to repairee.
1440 if ((TASK_REPAIR == tasks2->type) && (id == tasks2->args[0])) {
1441 rrate += hp_per_turn_est(unit2, u);
1442 continue;
1443 }
1444 // Consider auto-repairers in range of repairee.
1445 dist = distance(unit2->x, unit2->y, unit->x, unit->y);
1446 if ((dist <= uu_auto_repair_range(u2, u))
1447 && (0 < uu_auto_repair(u2, u)))
1448 rrate += uu_auto_repair(u2, u);
1449 }
1450 return rrate;
1451 }
1452
1453 /*!
1454 \note We could consider range like the old 'exploring_worth' function
1455 does. However, a fast, short-range explorer, such as a Fighter
1456 in the Default game, should not be undervalued against a
1457 slower, longe-range explorer, such as a Bomber.
1458 */
1459
1460 int
explorer_worth(int u)1461 explorer_worth(int u)
1462 {
1463 int worth = 0;
1464
1465 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
1466 worth = (u_ai_seer_worth(u) * u_ai_mover_worth(u)) / 10000;
1467 return max(0, worth);
1468 }
1469
1470 //! Set basic worth as an explorer.
1471
1472 void
set_explorer_worth(int u,int n)1473 set_explorer_worth(int u, int n)
1474 {
1475 assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
1476 assert_error(between(PROPLO, n, PROPHI),
1477 "Attempted to set an uprop out-of-bounds");
1478 utypes[u].aiexplorerworth = n;
1479 }
1480
1481 //! Set basic worths as explorers, if necessary.
1482
1483 void
maybe_set_explorer_worths(void)1484 maybe_set_explorer_worths(void)
1485 {
1486 int u = NONUTYPE;
1487 int worthmax = 0;
1488 int mustcalc = FALSE;
1489
1490 for_all_unit_types(u) {
1491 if (uprop_i_default(u_ai_explorer_worth) == u_ai_explorer_worth(u)) {
1492 mustcalc = TRUE;
1493 break;
1494 }
1495 }
1496 if (mustcalc) {
1497 for_all_unit_types(u) {
1498 tmp_u_array[u] = explorer_worth(u);
1499 worthmax = max(worthmax, tmp_u_array[u]);
1500 }
1501 for_all_unit_types(u)
1502 set_explorer_worth(u,
1503 normalize_on_pmscale(tmp_u_array[u],
1504 worthmax, 10000));
1505 }
1506 }
1507
1508 /* Total Worths */
1509
1510 int
total_worth(int u)1511 total_worth(int u)
1512 {
1513 int worth = 0;
1514
1515 assert_error(is_unit_type(u), "AI: Encountered an invalid unit type");
1516 worth += u_offensive_worth(u);
1517 worth += u_siege_worth(u);
1518 worth += u_defensive_worth(u);
1519 worth += u_ai_explorer_worth(u);
1520 worth += u_ai_prod_enhancer_worth(u);
1521 worth += u_ai_base_worth(u);
1522 worth += u_colonizer_worth(u);
1523 worth += u_colonization_support_worth(u);
1524 worth += u_base_construction_worth(u);
1525 worth += u_exploration_support_worth(u);
1526 worth += u_offensive_support_worth(u);
1527 worth += u_defensive_support_worth(u);
1528 return worth;
1529 }
1530