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