1 /* Functions common to all AIs.
2 Copyright (C) 1992-1997, 1999-2000 Stanley T. Shebs.
3 Copyright (C) 2005 Eric A. McDonald.
4
5 Xconq is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version. See the file COPYING. */
9
10 /* This file contains code used by all types of AIs, plus generic
11 AI-running code. While AI code is officially outside the kernel,
12 the functions here we need some definitions from kernel.h and so
13 must include it. */
14
15 #include "conq.h"
16 #include "kpublic.h"
17 #include "aiutil.h"
18 #include "ai.h"
19 #include "aiscore.h"
20 #include "aiunit.h"
21 #include "aiunit2.h"
22 #include "aioprt.h"
23
24 extern void register_mplayer(AI_ops *ops);
25 extern void register_iplayer(AI_ops *ops);
26
27 /* Needed in set_side_ai. */
28
29 extern void force_replan(Unit *unit);
30
31 /* Used in plan.c. */
32
33 int ai_go_after_victim(Unit *unit, int range, int broadcast);
34
35 extern int taskexecs;
36 extern int need_ai_init_turn;
37 extern int need_ai_planning;
38 extern int need_ai_action_reaction;
39 extern int need_ai_for_new_side;
40 extern int need_ai_finish_movement;
41 extern int latest_action_x, latest_action_y;
42
43 static int numaitypes;
44
45 /* The array of all possible AI types. */
46
47 static AI_ops *all_ai_ops;
48
49 /* The number of AIs run by this program. */
50
51 static int num_local_ais = -1;
52
53 /* Moved here from mplayer.c etc. */
54
55 GameClass game_class = gc_none;
56 int bhw_max = 0;
57
58 static void ai_init_turn(Side *side);
59 static void ai_decide_plan(Side *side, Unit *unit);
60 static void ai_react_to_task_result(Side *side, Unit *unit, Task *task, TaskOutcome rslt);
61 static int ai_adjust_plan(Side *side, Unit *unit);
62 static void ai_finish_movement(Side *side);
63
64 static int ai_integrate_advance_worth(Side *side, int a, int *numdeps);
65 static void ai_pick_side_research_goal(Side *side);
66 static int advance_leads_to_goal(Side *side, int a);
67 static void ai_plan_research(Side *side);
68
69 static int basic_worth(int u);
70 static int offensive_worth(int u);
71 static int defensive_worth(int u);
72 static int colonizing_worth(int u);
73 static int facility_worth(int u);
74 static int random_worth(int u);
75 static int siege_worth(int u);
76
77 static int basic_hit_worth(int u, int e);
78 static int basic_fire_worth(int u, int e);
79 static int basic_capture_worth(int u, int e);
80 static int basic_transport_worth(int u, int e);
81 static void display_assessment(void);
82
83 static int is_base_for(int u1, int u2);
84 static int is_carrier_for(int u1, int u2);
85
86 static void set_u_is_base(int u, int n);
87 static void set_u_is_transport(int u, int n);
88 static void set_u_is_carrier(int u, int n);
89 static void set_u_is_base_builder(int u, int n);
90 static void set_u_can_make(int u, int n);
91 static void set_u_can_capture(int u, int n);
92 static void set_u_bw(int u, int n);
93
94 static void set_u_offensive_worth(int u, int n);
95 static void set_u_defensive_worth(int u, int n);
96 static void set_u_colonizer_worth(int u, int n);
97 static void set_u_facility_worth(int u, int n);
98 static void set_u_random_worth(int u, int n);
99 static void set_u_siege_worth(int u, int n);
100 static void set_u_colonization_support_worth(int u, int n);
101 static void set_u_base_construction_worth(int u, int n);
102 static void set_u_exploration_support_worth(int u, int n);
103 static void set_u_offensive_support_worth(int u, int n);
104 static void set_u_defensive_support_worth(int u, int n);
105
106 static void set_u_is_ground_mobile(int u, int n);
107 static void set_u_is_naval_mobile(int u, int n);
108 static void set_u_is_air_mobile(int u, int n);
109 static void set_u_is_advanced(int u, int n);
110 static void set_u_is_colonizer(int u, int n);
111 static void set_u_is_facility(int u, int n);
112
113 static void set_uu_bhw(int u1, int u2, int v);
114 static void set_uu_bfw(int u1, int u2, int v);
115 static void set_uu_bcw(int u1, int u2, int v);
116 static void set_uu_btw(int u1, int u2, int v);
117
118 static int cell_unknown(int x, int y);
119 static int enemies_present(int x, int y);
120
121 static int carryable(int u);
122
123 /* New action-reaction code. */
124
125 static void ai_react_to_action(Side *side, Unit *unit);
126 static void check_current_target(Unit *unit);
127 static void defensive_reaction(Unit *unit);
128 static int keep_defensive_goal(Unit *unit, Unit *unit2);
129 static int maybe_defend_own_transport(Unit *unit);
130 static Unit *undefended_neighbour(Unit *unit);
131 static int maybe_defend_other_transport(Unit *unit, Unit *unit2);
132 static void offensive_reaction(Unit *unit);
133 static int ai_go_after_captive(Unit *unit, int range);
134 static int ai_fire_at_opportunity(Unit *unit);
135 static int mp_collect_here(int x, int y);
136 static int compare_weights(const void *w1, const void *w2);
137 static int probably_explorable(Side *side, int x, int y, int u);
138 static int real_capture_chance(Unit *unit, Unit *unit2);
139 static int attack_can_damage_or_capture(Unit *unit, Unit *unit2);
140 static int fire_can_damage_or_capture(Unit *unit, Unit *unit2);
141 static int fire_can_damage(Unit *unit, Unit *unit2);
142
143 void
init_ai_types(void)144 init_ai_types(void)
145 {
146 /* Fill in the table of pointers to AI types. */
147 all_ai_ops = (AI_ops *) xmalloc(MAXAITYPES * sizeof(AI_ops));
148 numaitypes = 0;
149 /* We leave all_ai_ops[0] unassigned so as to catch bad AI refs
150 due to uninitialized side->aitype. */
151 /* Call each AI's registration function. */
152 register_mplayer(&(all_ai_ops[++numaitypes]));
153 register_iplayer(&(all_ai_ops[++numaitypes]));
154 }
155
156 /* Given an AI type name, find its numerical index. */
157
158 int
find_ai_type(char * aitype)159 find_ai_type(char *aitype)
160 {
161 int i;
162
163 for (i = 1; i <= numaitypes; ++i) {
164 if (strcmp(all_ai_ops[i].name, aitype) == 0)
165 return i;
166 }
167 return 0;
168 }
169
170 /* Given a numerical index, return the name. */
171
172 char *
ai_type_name(int n)173 ai_type_name(int n)
174 {
175 if (!between(1, n, numaitypes))
176 return NULL;
177 return all_ai_ops[n].name;
178 }
179
180 /* Given an AI type name, return the next name in the list of types,
181 or NULL if the name is the last in the list. */
182
183 char *
next_ai_type_name(char * aitype)184 next_ai_type_name(char *aitype)
185 {
186 int i;
187 char *name;
188
189 if (aitype == NULL)
190 return all_ai_ops[1].name;
191 for (i = 1; i < numaitypes; ++i) {
192 name = all_ai_ops[i].name;
193 if (strcmp(name, aitype) == 0)
194 return all_ai_ops[i+1].name;
195 }
196 return NULL;
197 }
198
199 /* Given a numerical index, return the name. */
200
201 char *
ai_type_help(int n)202 ai_type_help(int n)
203 {
204 if (!between(1, n, numaitypes))
205 return NULL;
206 return all_ai_ops[n].help;
207 }
208
209 /* Given a side that wants to have an AI running its units, find and
210 record the actual AI type that will be used, and run its
211 initialization method. */
212
213 void
init_ai(Side * side)214 init_ai(Side *side)
215 {
216 int i;
217 char *aitype;
218 int (*test)(void);
219 void (*fn)(Side *side);
220
221 if (side_wants_ai(side)) {
222 /* (should merge with same bit in set_side_ai) */
223 if (strcmp(side->player->aitypename, "ai") == 0) {
224 /* (should use the "best" default for this game and side) */
225 side->player->aitypename = "mplayer";
226 }
227 /* If remote, do nothing beyond recording the name of the AI. */
228 if (numremotes > 0 && side->player->rid != my_rid) {
229 side->rai = (RAI *) xmalloc(sizeof(RAI));
230 return;
231 }
232 /* Scan through the possible AI types. */
233 for (i = 1; i <= numaitypes; ++i) {
234 aitype = all_ai_ops[i].name;
235 if (aitype != NULL
236 && strcmp(aitype, side->player->aitypename) == 0) {
237 test = all_ai_ops[i].to_test_compat;
238 if (test == NULL || (*test)()) {
239 /* Record the index of the AI type. */
240 side->aitype = i;
241 fn = all_ai_ops[i].to_init;
242 if (fn)
243 (*fn)(side);
244 } else {
245 /* desired aitype incompatible - should complain */
246 }
247 }
248 }
249 if (!side_has_ai(side)) {
250 init_warning("could not make an AI (type %s) for %s",
251 side->player->aitypename, side_desig(side));
252 }
253 }
254 }
255
256 /* Change the AI running a side. */
257
258 void
set_side_ai(Side * side,char * aitype)259 set_side_ai(Side *side, char *aitype)
260 {
261 Unit *unit;
262 Side *side2;
263
264 /* Pick the mplayer if we just asked for an ai without name. */
265 if (!empty_string(aitype) && strcmp(aitype, "ai") == 0) {
266 aitype = "mplayer";
267 }
268 /* Set the desired ai by name. */
269 if (empty_string(aitype)) {
270 side->player->aitypename = NULL;
271 } else {
272 side->player->aitypename = copy_string(aitype);
273 }
274 /* This is a remote ai. */
275 if (numremotes > 0 && side->player->rid != my_rid) {
276 /* Dump any existing rai. */
277 if (side->rai != NULL) {
278 free(side->rai);
279 side->rai = NULL;
280 }
281 /* Maybe allocate a new one. */
282 if (!empty_string(aitype))
283 side->rai = (RAI *) xmalloc(sizeof(RAI));
284 /* This is a local ai. */
285 } else {
286 /* Dump any existing ai. */
287 if (side->ai != NULL) {
288 free(side->ai);
289 side->ai = NULL;
290 }
291 /* Switching to human control. */
292 if (empty_string(aitype)) {
293 DMprintf("%s switches to human control.\n", side_desig(side));
294 /* Switching to ai control. */
295 } else {
296 DMprintf("%s switches to %s control.\n",
297 side_desig(side), aitype);
298 /* We need a new ai. */
299 need_ai_for_new_side = TRUE;
300 /* We need to init the strategy code. */
301 need_ai_init_turn = TRUE;
302 }
303 }
304 if (gameinited) {
305 /* Replan everything, whether switching to ai or human control. */
306 DMprintf("%s is replanning all units after ai switch.\n",
307 side_desig(side));
308 for_all_side_units(side, unit) {
309 if (is_active(unit)) {
310 /* We do this locally on each computer to save time. */
311 unit->aihook = NULL;
312 force_replan(unit);
313 }
314 }
315 }
316 /* Stimulate a recalculation later. */
317 num_local_ais = -1;
318 if (!empty_string(side->player->aitypename)) {
319 notify_all("AI %s is running %s.",
320 side->player->aitypename, short_side_title(side));
321 } else {
322 notify_all("No AI is running %s.", short_side_title(side));
323 }
324 /* Make sure the ai player info is updated. */
325 for_all_sides(side2) {
326 if (side_has_display(side2)) {
327 update_side_display(side2, side, TRUE);
328 }
329 }
330 }
331
332 void run_ai_plan_adjust(Side *side);
333
334 /* (should decide on useful return value and use, or make void) */
335
336 int
run_local_ai(int when,int maxplanning)337 run_local_ai(int when, int maxplanning)
338 {
339 Side *side;
340 Unit *unit;
341 char *activity = "run_local_ai";
342
343 /* Make sure we know how many local AIs are present. */
344 if (num_local_ais < 0) {
345 num_local_ais = 0;
346 for_all_sides(side) {
347 if (side_has_local_ai(side))
348 ++num_local_ais;
349 }
350 }
351 /* If no AIs to run, get out quickly. */
352 if (num_local_ais == 0 && !need_ai_for_new_side)
353 return 0;
354 record_activity_start(activity, when);
355 #if 0 /* This caused buzzing by preventing passive units under AI
356 control from getting necessary replanning. */
357 /* Only do this routine at a certain rate. */
358 if (current_play_rate > 0
359 && !n_ms_elapsed(60000 / current_play_rate)
360 ) {
361 record_activity_end(activity, 1);
362 return 0;
363 }
364 #endif
365 if (need_ai_for_new_side) {
366 for_all_sides(side) {
367 if (side_wants_ai(side) && !side_has_ai(side)) {
368 init_ai(side);
369 }
370 }
371 need_ai_for_new_side = FALSE;
372 }
373 /* This code does the following:
374 1) Analyzes the game.
375 2) Reviews goals, theaters and units.
376 3) Updates strategy and unit plans.
377 Executed at the start of each turn. */
378 if (need_ai_init_turn) {
379 for_all_sides(side) {
380 if (side_has_local_ai(side))
381 ai_init_turn(side);
382 }
383 need_ai_init_turn = FALSE;
384 }
385 /* This code finds a new plan for any unit with a passive plan.
386 Before that, however, ai_react_to_action is called to handle any
387 emergencies and also to ensure that peace garrisons are maintained.
388 Executed after each plan execution, during forced replanning
389 and at the start of each turn. */
390 if (need_ai_planning) {
391 for_all_sides(side) {
392 if (side_has_local_ai(side)
393 /* (should) and need planning for this side*/) {
394 for_all_side_units(side, unit) {
395 if (is_active(unit)
396 && ai_controlled(unit)
397 && unit->plan
398 && !unit->plan->asleep
399 /* Don't mess with acp-independent units. */
400 && !acp_indep(unit)) {
401 ai_decide_plan(side, unit);
402 }
403 }
404 }
405 }
406 need_ai_planning = FALSE;
407 }
408 /* This code handles side research. */
409 if (numatypes > 0) {
410 for_all_sides(side) {
411 if (side_has_local_ai(side)
412 && side->research_topic == NOADVANCE) {
413 ai_plan_research(side);
414 }
415 }
416 }
417 /* Run evaluators for operational roles. */
418 for_all_sides(side) {
419 if (side_has_local_ai(side) && Xconq::AI::get_side_ai(side))
420 Xconq::AI::handle_oproles(side);
421 }
422 /* This code does two things:
423 1) Reacts to failed move tasks as approprite.
424 2) Reacts to failed resupply tasks by trying to build a depot.
425 Executed after each task execution. */
426 if (taskexecs > 0) {
427 for_all_sides(side) {
428 if (side_has_local_ai(side)) {
429 for_all_side_units(side, unit) {
430 if (is_active(unit)
431 && ai_controlled(unit)
432 && unit->plan
433 && &(unit->plan->last_task)
434 && ((&(unit->plan->last_task))->type == TASK_MOVE_TO
435 || (&(unit->plan->last_task))->type ==
436 TASK_RESUPPLY)
437 && unit->plan->last_task_outcome == TASK_FAILED) {
438 ai_react_to_task_result(side, unit,
439 &(unit->plan->last_task),
440 unit->plan->last_task_outcome);
441 /* Necessary to enable execution of the new task. */
442 net_clear_task_outcome(side, unit);
443 }
444 }
445 }
446 }
447 }
448 /* This code does two things:
449 1) Reevaluates the defense of cities and assigns or releases defenders.
450 2) Sets (not pushes) hit tasks etc. for enemy units that appear nearby.
451 Executed after certain actions. */
452 if (need_ai_action_reaction) {
453 for_all_sides(side) {
454 if (side_has_local_ai(side)) {
455 for_all_side_units(side, unit) {
456 if (is_active(unit)
457 && ai_controlled(unit)
458 && (distance(unit->x, unit->y,
459 latest_action_x, latest_action_y)
460 <= u_ai_tactical_range(unit->type))) {
461 ai_react_to_action(side, unit);
462 }
463 }
464 }
465 }
466 need_ai_action_reaction = FALSE;
467 }
468 /* This code does four things:
469 1) Sets build tasks for stationary units with no tasks.
470 2) Forces units with PLAN_IMPROVE and no tasks to replan.
471 3) Forces units that are waiting for tasks to replan.
472 4) Forces units with too many plan execs this turn into reserve.
473 Executed each round. */
474 if (1) {
475 for_all_sides(side) {
476 if (side_has_local_ai(side) && !side->finishedturn) {
477 run_ai_plan_adjust(side);
478 }
479 }
480 }
481 /* This code does three things:
482 1) Organizes pickup of any units already known to need transport.
483 2) Checks if any other units need transport (rethink_plan).
484 Executed at each end of turn.
485 The code used to test for !side->finishedturn, but this made execution
486 impossible since need_ai_finish_movement is set only when all sides
487 have finished their turns. */
488 if (need_ai_finish_movement) {
489 for_all_sides(side) {
490 if (side_has_local_ai(side)) {
491 ai_finish_movement(side);
492 }
493 }
494 need_ai_finish_movement = FALSE;
495 }
496 record_activity_end(activity, 1);
497 return 0;
498 }
499
500 void
run_ai_plan_adjust(Side * side)501 run_ai_plan_adjust(Side *side)
502 {
503 int curactor, domore;
504 Unit *unit;
505
506 if (side->actionvector == NULL)
507 return;
508 domore = TRUE;
509 for (curactor = 0; curactor < side->actionvector->numunits; ++curactor) {
510 unit = unit_in_vector(side->actionvector, curactor);
511 if (ai_controlled(unit)
512 /* Don't mess with acp-independent units. */
513 && !acp_indep(unit)) {
514 /* Domore is now always true. Skip this test? */
515 domore = ai_adjust_plan(side, unit);
516 if (!domore)
517 return;
518 }
519 }
520 }
521
522 /* The following functions dispatch on AI type. */
523
524 void
ai_init_turn(Side * side)525 ai_init_turn(Side *side)
526 {
527 void (*fn)(Side *side);
528
529 fn = all_ai_ops[side->aitype].to_init_turn;
530 if (fn)
531 (*fn)(side);
532 }
533
534 void
ai_decide_plan(Side * side,Unit * unit)535 ai_decide_plan(Side *side, Unit *unit)
536 {
537 void (*fn)(Side *side, Unit *unit);
538
539 /* This is the replanning code from ai_react_to_action.
540 It needs to be called at least once each turn even in the absence of any
541 hostile actions, to make sure that peace garrisons are maintained. Not
542 sure if this is the best place, though. */
543
544 /* Note: executing this code at the start of each turn also makes the
545 "attack nearby enemy unit" code in mplayer_rethink_plan etc (called
546 by ai_finish_movement) unnecessary. */
547
548 /* ai_react_to_action(side, unit); */
549
550 fn = all_ai_ops[side->aitype].to_decide_plan;
551 if (fn) {
552 (*fn)(side, unit);
553 }
554 /* Code moved here to make the ai more responsive, particularly
555 when turned on in the middle of a game, where the to_decide_plan
556 call would erase any tasks set up by the first ai_react_to_action
557 call. */
558 ai_react_to_action(side, unit);
559 }
560
561 /* Forward a task result to the appropriate AI routine. */
562 /* (should make task and rslt args implicit) */
563
564 void
ai_react_to_task_result(Side * side,Unit * unit,Task * task,TaskOutcome rslt)565 ai_react_to_task_result(Side *side, Unit *unit, Task *task, TaskOutcome rslt)
566 {
567 void (*fn)(Side *side, Unit *unit, Task *task, TaskOutcome rslt);
568
569 fn = all_ai_ops[side->aitype].to_react_to_task_result;
570 if (fn)
571 (*fn)(side, unit, task, rslt);
572 }
573
574 void
ai_react_to_new_side(Side * side,Side * side2)575 ai_react_to_new_side(Side *side, Side *side2)
576 {
577 void (*fn)(Side *side, Side *side2);
578
579 fn = all_ai_ops[side->aitype].to_react_to_new_side;
580 if (fn)
581 (*fn)(side, side2);
582 }
583
584 int
ai_adjust_plan(Side * side,Unit * unit)585 ai_adjust_plan(Side *side, Unit *unit)
586 {
587 int (*fn)(Side *side, Unit *unit);
588
589 fn = all_ai_ops[side->aitype].to_adjust_plan;
590 if (fn)
591 return (*fn)(side, unit);
592 else
593 return FALSE;
594 }
595
596 void
ai_finish_movement(Side * side)597 ai_finish_movement(Side *side)
598 {
599 void (*fn)(Side *side);
600
601 fn = all_ai_ops[side->aitype].to_finish_movement;
602 if (fn)
603 (*fn)(side);
604 }
605
606 /* Push a new goal onto the side's list of goals. */
607
608 /* (this should only add goals that are not already present) */
609
610 void
add_goal(Side * side,Goal * goal)611 add_goal(Side *side, Goal *goal)
612 {
613 if (ai(side)->numgoals < MAXGOALS) {
614 ai(side)->goals[(ai(side)->numgoals)++] = goal;
615 DMprintf("%s added %s\n", side_desig(side), goal_desig(goal));
616 } else {
617 DMprintf("%s has no room for %s\n",
618 side_desig(side), goal_desig(goal));
619 }
620 }
621
622 /* Return any goal of the given type. */
623
624 Goal *
has_goal(Side * side,GoalType goaltype)625 has_goal(Side *side, GoalType goaltype)
626 {
627 int i;
628 Goal *goal;
629
630 for (i = 0; i < ai(side)->numgoals; ++i) {
631 goal = ai(side)->goals[i];
632 if (goal != NULL && goal->type == goaltype) {
633 return goal;
634 }
635 }
636 return NULL;
637 }
638
639 /* Return an unfulfilled goal of the given type. */
640
641 Goal *
has_unsatisfied_goal(Side * side,GoalType goaltype)642 has_unsatisfied_goal(Side *side, GoalType goaltype)
643 {
644 int i;
645 Goal *goal;
646
647 for (i = 0; i < ai(side)->numgoals; ++i) {
648 goal = ai(side)->goals[i];
649 if (goal != NULL && goal->type == goaltype
650 && goal_truth(side, goal) < 100) {
651 return goal;
652 }
653 }
654 return NULL;
655 }
656
657 void
ai_receive_message(Side * side,Side * sender,char * str)658 ai_receive_message(Side *side, Side *sender, char *str)
659 {
660 /* First detect standard messages. */
661 if (strcmp(str, "Eh?") == 0) {
662 /* Don't respond, otherwise we might infinitely recurse. */
663 } else if (allied_side(side, sender)) {
664 /* (should say something) */
665 } else {
666 /* Detect insults and respond appropriately. */
667 /* (should be case-insensitive) */
668 if (strstr(str, "idiot")) {
669 net_send_message(side, add_side_to_set(sender, NOSIDES), "Loser!");
670 } else if (strstr(str, "loser")) {
671 net_send_message(side, add_side_to_set(sender, NOSIDES), "Idiot!");
672 } else {
673 /* No idea what the message was, be puzzled. */
674 net_send_message(side, add_side_to_set(sender, NOSIDES), "Eh?");
675 }
676 }
677 }
678
679 void
ai_save_state(Side * side)680 ai_save_state(Side *side)
681 {
682 Obj *(*fn)(Side *side), *state = lispnil;
683
684 fn = all_ai_ops[side->aitype].to_save_state;
685 if (fn)
686 state = (*fn)(side);
687 /* Don't bother if there's no AI state to mess with. */
688 if (side->aidata == lispnil && state == lispnil)
689 return;
690 side->aidata = replace_at_key(side->aidata, side->player->aitypename,
691 state);
692 }
693
694 /* Return a numerical value indicate the AI's use of the given location.
695 For instance, each number could represent a region or theater of
696 operations. */
697
698 int
ai_region_at(Side * side,int x,int y)699 ai_region_at(Side *side, int x, int y)
700 {
701 int (*fn)(Side *side, int x, int y);
702
703 fn = all_ai_ops[side->aitype].region_at;
704 if (fn)
705 return (*fn)(side, x, y);
706 else
707 return 0;
708 }
709
710 /* Provide textual information about the AI's usage or opinion of the
711 given location. */
712
713 char *
ai_at_desig(Side * side,int x,int y)714 ai_at_desig(Side *side, int x, int y)
715 {
716 char *(*fn)(Side *side, int x, int y);
717
718 fn = all_ai_ops[side->aitype].at_desig;
719 if (fn)
720 return (*fn)(side, x, y);
721 else
722 return NULL;
723 }
724
725 /* Set willingness to declare a draw. */
726
727 void
try_to_draw(Side * side,int flag,char * ainame)728 try_to_draw(Side *side, int flag, char *ainame)
729 {
730 /* If no change, nothing to say or do. */
731 if (flag == side->willingtodraw)
732 return;
733 /* If there is a human player and the decision has not been
734 delegated, allow the human to make the final decision. */
735 if (side_has_display(side) && !side->ai_may_resign) {
736 if (flag)
737 notify(side, "Your AI %s recommends being willing to draw.",
738 ainame);
739 else
740 notify(side, "Your AI %s recommends not being willing to draw.",
741 ainame);
742 return;
743 }
744 net_set_willing_to_draw(side, flag);
745 }
746
747 /* If an AI resigns, it tries to help its friends. */
748
749 void
give_up(Side * side,char * ainame)750 give_up(Side *side, char *ainame)
751 {
752 Side *side1;
753
754 /* The independents cannot resign unless played by a human. */
755 if (side == indepside && !side_has_display(side))
756 return;
757 /* Can't resign if we've been forbidden to do so. */
758 if (side_has_display(side) && !side->ai_may_resign) {
759 /* But speak up about it. */
760 notify(side, "Your AI %s recommends resignation", ainame);
761 return;
762 }
763 /* Try to give away all of our units to an ally. */
764 for_all_sides(side1) {
765 if (side != side1 && allied_side(side, side1) && side1->ingame) {
766 if (side_has_display(side))
767 notify(side, "Your AI resigns, giving its assets to %s!",
768 short_side_title(side1));
769 net_resign_game(side, side1);
770 return;
771 }
772 }
773 /* No allies left in game, leave everything to its fate. */
774 if (side_has_display(side))
775 notify(side, "Your AI resigns!");
776 net_resign_game(side, NULL);
777 }
778
779 /* (should go elsewhere eventually?) */
780
781 /* Goal handling. */
782
783 GoalDefn goaldefns[] = {
784
785 #undef DEF_GOAL
786 #define DEF_GOAL(NAME,DNAME,code,ARGTYPES) { NAME, DNAME, ARGTYPES },
787
788 #include "goal.def"
789
790 { NULL, NULL, NULL }
791 };
792
793
794 /* General handling of goals. */
795
796 Goal *
create_goal(GoalType type,Side * side,int tf)797 create_goal(GoalType type, Side *side, int tf)
798 {
799 Goal *goal = (Goal *) xmalloc(sizeof(Goal));
800
801 goal->type = type;
802 goal->side = side;
803 goal->tf = tf;
804 return goal;
805 }
806
807 int
cell_unknown(int x,int y)808 cell_unknown(int x, int y)
809 {
810 return !(tmpside->see_all || terrain_view(tmpside, x, y) != UNSEEN);
811 }
812
813 int
enemies_present(int x,int y)814 enemies_present(int x, int y)
815 {
816 UnitView *uv;
817
818 for_all_view_stack_with_occs(tmpside, x, y, uv) {
819 if (!trusted_side(tmpside, side_n(uv->siden)))
820 return TRUE;
821 }
822 return FALSE;
823 }
824
825 /* Test a goal to see if it is true for side, as specified. */
826
827 int
goal_truth(Side * side,Goal * goal)828 goal_truth(Side *side, Goal *goal)
829 {
830 int x, y, m, n;
831
832 if (goal == NULL) return 0;
833 switch (goal->type) {
834 case GOAL_POSITIONS_KNOWN:
835 /* what if no enemies present? then this is undefined? */
836 /* should goals have preconditions or prerequisites? */
837 return 0;
838 case GOAL_VICINITY_KNOWN:
839 tmpside = side;
840 if (search_around(goal->args[0], goal->args[1], goal->args[2],
841 cell_unknown, &x, &y, 1)) {
842 return -100;
843 } else {
844 return 100;
845 }
846 case GOAL_VICINITY_HELD:
847 tmpside = side;
848 if (search_around(goal->args[0], goal->args[1], goal->args[2],
849 enemies_present, &x, &y, 1)) {
850 return -100;
851 } else {
852 return 100;
853 }
854 case GOAL_CELL_OCCUPIED:
855 return 0;
856 case GOAL_UNIT_OCCUPIED:
857 return 0;
858 case GOAL_COLONIZE:
859 return 0;
860 case GOAL_HAS_UNIT_TYPE:
861 return 0;
862 case GOAL_HAS_UNIT_TYPE_NEAR:
863 return 0;
864 case GOAL_HAS_MATERIAL_TYPE:
865 m = goal->args[0];
866 n = goal->args[1];
867 if (side->treasury[m] >= n)
868 return 100;
869 else
870 return -100;
871 default:
872 case_panic("goal type", goal->type);
873 return 0;
874 }
875 }
876
877 /* (might eventually want another evaluator that guesses at another
878 side's goals) */
879
880 char *goalbuf = NULL;
881
882 char *
goal_desig(Goal * goal)883 goal_desig(Goal *goal)
884 {
885 int numargs, i, arg;
886 char *argtypes;
887
888 if (goal == NULL)
889 return "<null goal>";
890 if (goalbuf == NULL)
891 goalbuf = (char *)xmalloc(BUFSIZE);
892 sprintf(goalbuf, "<goal s%d %s%s",
893 side_number(goal->side), (goal->tf ? "" : "not "),
894 goaldefns[goal->type].name);
895 argtypes = goaldefns[goal->type].argtypes;
896 numargs = strlen(argtypes);
897 for (i = 0; i < numargs; ++i) {
898 arg = goal->args[i];
899 switch (argtypes[i]) {
900 case 'h':
901 tprintf(goalbuf, "%d", arg);
902 break;
903 case 'm':
904 if (is_material_type(arg))
905 tprintf(goalbuf, " %s", m_type_name(arg));
906 else
907 tprintf(goalbuf, " m%d?", arg);
908 break;
909 case 'S':
910 tprintf(goalbuf, " `%s'", side_desig(side_n(arg)));
911 break;
912 case 'u':
913 if (is_unit_type(arg))
914 tprintf(goalbuf, " %s", u_type_name(arg));
915 else
916 tprintf(goalbuf, " m%d?", arg);
917 break;
918 case 'U':
919 tprintf(goalbuf, " `%s'", unit_desig(find_unit(arg)));
920 break;
921 case 'w':
922 tprintf(goalbuf, " %dx", arg);
923 break;
924 case 'x':
925 tprintf(goalbuf, " %d,", arg);
926 break;
927 case 'y':
928 tprintf(goalbuf, "%d", arg);
929 break;
930 default:
931 tprintf(goalbuf, " %d", arg);
932 break;
933 }
934 }
935 strcat(goalbuf, ">");
936 return goalbuf;
937 }
938
939 /* Common AI code moved here from mplayer.c etc. */
940
941 /* Determine game type from name of included modules. */
942
943 GameClass
find_game_class(void)944 find_game_class(void)
945 {
946 Module *m;
947
948 for_all_modules(m) {
949 if (strcmp(m->name, "time") == 0
950 || (m->origmodulename && strcmp(m->origmodulename, "time") == 0))
951 return gc_time;
952 else if (strcmp(m->name, "advanced") == 0
953 || (m->origmodulename
954 && strcmp(m->origmodulename, "advanced") == 0))
955 return gc_advanced;
956 }
957 return gc_standard;
958 }
959
960 /* For each unit, decide what it should be doing (if anything). This is
961 when a side takes the initiative; a unit can also request info from
962 its side when it is working on its individual plan. */
963
964 void
update_unit_plans(Side * side)965 update_unit_plans(Side *side)
966 {
967 Unit *unit;
968
969 for_all_side_units(side, unit) {
970 if (is_active(unit) && ai_controlled(unit)) {
971 ai_decide_plan(side, unit);
972 }
973 }
974 }
975
976 /* Randomly change a unit's plans. (This is really more for
977 debugging, exercising plan execution code in novel ways.) */
978
979 void
update_unit_plans_randomly(Side * side)980 update_unit_plans_randomly(Side *side)
981 {
982 Unit *unit;
983
984 for_all_side_units(side, unit) {
985 if (is_active(unit) && ai_controlled(unit)) {
986 if (probability(10)) {
987 DMprintf("Randomly changed %s plan %s",
988 unit_desig(unit), plan_desig(unit->plan));
989 net_set_unit_plan_type(side, unit, xrandom((int) NUMPLANTYPES));
990 DMprintf("to plan %s\n", plan_desig(unit->plan));
991 }
992 /* (should add/remove goals randomly) */
993 if (probability(10)) {
994 net_set_unit_reserve(side, unit, TRUE, FALSE);
995 }
996 }
997 }
998 }
999
1000 /* This hook is triggered when certain actions are executed within the
1001 tactical range of our unit. */
1002
1003 static void
ai_react_to_action(Side * side,Unit * unit)1004 ai_react_to_action(Side *side, Unit *unit)
1005 {
1006 /* Don't mess with units that are doing resupply or repair ... */
1007 if (unit->plan
1008 && unit->plan->tasks
1009 && (unit->plan->tasks->type == TASK_REPAIR
1010 || unit->plan->tasks->type == TASK_RESUPPLY
1011 /* ... or are on their way to resupply or repair. */
1012 || (unit->plan->tasks->type == TASK_MOVE_TO
1013 && unit->plan->tasks->next
1014 && (unit->plan->tasks->next->type == TASK_REPAIR
1015 || unit->plan->tasks->next->type == TASK_RESUPPLY)))) {
1016 return;
1017 }
1018 /* Don't mess with non-mobile units that are building something. */
1019 if (!mobile(unit->type)
1020 && unit->plan
1021 && unit->plan->tasks
1022 && unit->plan->tasks->type == TASK_BUILD) {
1023 return;
1024 }
1025 /* First check that the unit's target (if it has one) is valid. */
1026 check_current_target(unit);
1027 /* Deal with tactical emergencies. */
1028 defensive_reaction(unit);
1029 offensive_reaction(unit);
1030 }
1031
1032 /* Check that any offensive targets are still valid. Replan if not. */
1033
1034 static void
check_current_target(Unit * unit)1035 check_current_target(Unit *unit)
1036 {
1037 int x, y, u, target = FALSE, valid = FALSE;
1038 Plan *plan = unit->plan;
1039 Side *side = unit->side;
1040 UnitView *uview;
1041 Unit *unit2;
1042
1043 /* Check if we are trying to hit or capture a unit. */
1044 if (plan->tasks
1045 && (plan->tasks->type == TASK_HIT_UNIT
1046 || plan->tasks->type == TASK_CAPTURE)){
1047 target = TRUE;
1048 x = plan->tasks->args[0];
1049 y = plan->tasks->args[1];
1050 u = plan->tasks->args[2];
1051 /* Also check if we are moving in for attack. */
1052 } else if (plan->tasks
1053 && plan->tasks->type == TASK_MOVE_TO
1054 && plan->tasks->next
1055 && (plan->tasks->next->type == TASK_HIT_UNIT
1056 || plan->tasks->next->type == TASK_CAPTURE)){
1057 target = TRUE;
1058 x = plan->tasks->next->args[0];
1059 y = plan->tasks->next->args[1];
1060 u = plan->tasks->next->args[2];
1061 }
1062 /* If we have no target we are done. */
1063 if (!target)
1064 return;
1065 /* Check if we still can see the intended target in the assumed position. */
1066 if (side->see_all) {
1067 for_all_stack_with_occs(x, y, unit2) {
1068 if (!trusted_side(side, unit2->side)
1069 && unit2->type == u)
1070 valid = TRUE;
1071 }
1072 } else {
1073 for_all_view_stack_with_occs(side, x, y, uview) {
1074 if (!trusted_side(side, side_n(uview->siden))
1075 && uview->type == u)
1076 valid = TRUE;
1077 }
1078 }
1079 /* Blast the plan if we lack a valid target. */
1080 if (!valid) {
1081 DMprintf("Forced replan for %s as target is no longer valid.\n",
1082 unit_desig(unit));
1083 net_force_replan(unit);
1084 }
1085 }
1086
1087 /* Check that advanced units are adequately defended, but release any
1088 excess defenders. */
1089
1090 static void
defensive_reaction(Unit * unit)1091 defensive_reaction(Unit *unit)
1092 {
1093 Plan *plan = unit->plan;
1094 Unit *unit2;
1095
1096 /* First check if our unit is assigned to protecting another unit,
1097 and release it from that duty if it is no longer needed. This is
1098 very important or all our units will soon be soaked up in this
1099 kind of defense! */
1100 if (plan->maingoal
1101 && plan->maingoal->type == GOAL_UNIT_OCCUPIED) {
1102 unit2 = find_unit(plan->maingoal->args[0]);
1103 /* Return if we are still busy with unit2. */
1104 if (keep_defensive_goal(unit, unit2))
1105 return;
1106 /* We need a new plan and goal. */
1107 DMprintf("Forced replan: %s released from defending %s\n",
1108 unit_desig(unit), unit_desig(unit2));
1109 net_force_replan(unit);
1110 }
1111 /* Then check if our own transport needs defense. */
1112 if (maybe_defend_own_transport(unit))
1113 return;
1114 /* If not, check if any neigbour needs defense. */
1115 unit2 = undefended_neighbour(unit);
1116 if (unit2) {
1117 maybe_defend_other_transport(unit, unit2);
1118 }
1119 }
1120
1121 /* Returns true if unit is busy defending or recapturing unit2, false
1122 if it needs a new goal. */
1123
1124 static int
keep_defensive_goal(Unit * unit,Unit * unit2)1125 keep_defensive_goal(Unit *unit, Unit *unit2)
1126 {
1127 Plan *plan = unit->plan;
1128 int garrison = 0;
1129 Unit *unit3;
1130
1131 /* unit2 has been destroyed. */
1132 if (!in_play(unit2)) {
1133 return FALSE;
1134 /* We can't defend unit2 (should never happen). */
1135 } else if (!occ_can_defend_transport(unit->type, unit2->type)) {
1136 return FALSE;
1137 /* unit2 is held by the enemy. */
1138 } else if (enemy_side(unit->side, unit2->side)) {
1139 /* Don't interfere if we are trying to recapture unit2. */
1140 if (plan->tasks
1141 && (((plan->tasks->type == TASK_HIT_UNIT
1142 && plan->tasks->args[0] == unit2->x
1143 && plan->tasks->args[1] == unit2->y
1144 && plan->tasks->args[2] == unit2->type)
1145 || (plan->tasks->type == TASK_CAPTURE
1146 && plan->tasks->args[0] == unit2->x
1147 && plan->tasks->args[1] == unit2->y
1148 && plan->tasks->args[2] == unit2->type))
1149 /* Or if we are on our way to recapture unit2. */
1150 || (plan->tasks->type == TASK_MOVE_TO
1151 && plan->tasks->args[0] == unit2->x
1152 && plan->tasks->args[1] == unit2->y
1153 && plan->tasks->next
1154 && ((plan->tasks->next->type == TASK_HIT_UNIT
1155 && plan->tasks->next->args[0] == unit2->x
1156 && plan->tasks->next->args[1] == unit2->y
1157 && plan->tasks->next->args[2] == unit2->type)
1158 || (plan->tasks->next->type == TASK_CAPTURE
1159 && plan->tasks->next->args[0] == unit2->x
1160 && plan->tasks->next->args[1] == unit2->y
1161 && plan->tasks->next->args[2] == unit2->type))))) {
1162 return TRUE;
1163 }
1164 /* Try to recapture unit2 directly if we have a decent chance. */
1165 if (real_capture_chance(unit, unit2) > 20) {
1166 net_set_capture_task(unit, unit2->x, unit2->y, unit2->type,
1167 unit2->side->id);
1168 DMprintf("%s tries to recapture %s directly\n",
1169 unit_desig(unit), unit_desig(unit2));
1170 return TRUE;
1171 /* Otherwise attack unit2 if possible. */
1172 } else if (attack_can_damage_or_capture(unit, unit2)
1173 || fire_can_damage_or_capture(unit, unit2)) {
1174 net_set_hit_unit_task(unit, unit2->x, unit2->y,
1175 unit2->type, unit2->side->id);
1176 DMprintf("%s tries to take %s back by attacking it\n",
1177 unit_desig(unit), unit_desig(unit2));
1178 return TRUE;
1179 }
1180 return FALSE;
1181 } else {
1182 /* Check if unit2 is adequately defended by OTHER occupants. */
1183 for_all_occupants(unit2, unit3) {
1184 if (is_active(unit3)
1185 && unit3 != unit
1186 && unit3->plan
1187 && unit3->plan->maingoal
1188 && unit3->plan->maingoal->type == GOAL_UNIT_OCCUPIED
1189 && unit3->plan->maingoal->args[0] == unit2->id
1190 /* Occs that cannot defend the transport should never
1191 have been assigned to occupy it, but check
1192 anyway. */
1193 && occ_can_defend_transport(unit3->type, unit2->type)) {
1194 ++garrison;
1195 }
1196 }
1197 /* If so, release our unit from its duty. */
1198 if (enough_to_garrison(unit2, garrison)) {
1199 return FALSE;
1200 /* Else make sure we have the occupy task set if we are
1201 not there. */
1202 } else if (unit->transport != unit2
1203 && plan->tasks
1204 && plan->tasks->type != TASK_OCCUPY) {
1205 net_set_occupy_task(unit, unit2);
1206 return TRUE;
1207 /* Else just keep defending unit2. */
1208 } else {
1209 return TRUE;
1210 }
1211 }
1212 }
1213
1214 /* Returns true if we decide to defend it. */
1215
1216 static int
maybe_defend_own_transport(Unit * unit)1217 maybe_defend_own_transport(Unit *unit)
1218 {
1219 Unit *unit2;
1220
1221 /* First assign our unit to protect its own city if needed. */
1222 unit2 = unit->transport;
1223 if (unit2 != NULL) {
1224 /* A city is a transport that can build. */
1225 if (u_can_make(unit2->type)
1226 /* u_can_make is much faster than can_build. */
1227 && occ_can_defend_transport(unit->type, unit2->type)
1228 /* could_carry, which is called by occ_can_defend_transport,
1229 is much faster than can_carry_type, which was used before. */
1230 && !defended_by_occupants(unit2)) {
1231 assign_to_defend_unit(unit, unit2);
1232 DMprintf("%s assigned to defend own transport %s\n",
1233 unit_desig(unit), unit_desig(unit2));
1234 return TRUE;
1235 }
1236 }
1237 return FALSE;
1238 }
1239
1240 /* This code is twice as fast as the old code which used
1241 for_all_side_units. */
1242
1243 static Unit *
undefended_neighbour(Unit * unit)1244 undefended_neighbour(Unit *unit)
1245 {
1246 Unit *unit2;
1247 int x, y;
1248
1249 for_all_cells_within_range(unit->x, unit->y,
1250 u_ai_enemy_alert_range(unit->type), x, y) {
1251 if (!inside_area(x, y))
1252 continue;
1253 if (!terrain_visible(unit->side, x, y))
1254 continue;
1255 for_all_stack(x, y, unit2) {
1256 if (is_active(unit2)
1257 && unit2->side == unit->side
1258 /* (u_can_make is much faster than can_build). */
1259 && u_can_make(unit2->type)
1260 /* (could_carry, which is called by
1261 occ_can_defend_transport, is much faster than
1262 can_carry_type, which was used before). */
1263 && occ_can_defend_transport(unit->type, unit2->type)
1264 && !defended_by_occupants(unit2)) {
1265 return unit2;
1266 }
1267 }
1268 }
1269 return NULL;
1270 }
1271
1272 /* Returns true if we decide to defend it. */
1273
1274 static int
maybe_defend_other_transport(Unit * unit,Unit * unit2)1275 maybe_defend_other_transport(Unit *unit, Unit *unit2)
1276 {
1277 Unit *unit3;
1278 int garrison = 0;
1279
1280 /* Check if other defenders on their way are closer or same
1281 distance. This prevents buzzing of flocks of defenders in and
1282 out of a city without adequate defense. */
1283 for_all_side_units(unit->side, unit3) {
1284 if (is_active(unit3)
1285 /* Should never happen, but check. */
1286 && unit3 != unit
1287 && unit3->plan
1288 && unit3->plan->maingoal
1289 && unit3->plan->maingoal->type == GOAL_UNIT_OCCUPIED
1290 && unit3->plan->maingoal->args[0] == unit2->id
1291 && occ_can_defend_transport(unit3->type, unit2->type)
1292 /* (should take unit speeds into consideration here). */
1293 && (distance(unit2->x, unit2->y, unit3->x, unit3->y) <=
1294 distance(unit2->x, unit2->y, unit->x, unit->y))) {
1295 /* This is really the potential garrison as soon as all
1296 defenders get there. */
1297 ++garrison;
1298 }
1299 }
1300 /* If not enough defenders, assign our unit to the city's defense. */
1301 if (!enough_to_garrison(unit2, garrison)) {
1302 assign_to_defend_unit(unit, unit2);
1303 DMprintf("%s assigned to defend neighbour transport %s\n",
1304 unit_desig(unit), unit_desig(unit2));
1305 return TRUE;
1306 }
1307 return FALSE;
1308 }
1309
1310 /* Deal with tactical emergencies such as enemy units that suddenly
1311 appear nearby. */
1312
1313 static void
offensive_reaction(Unit * unit)1314 offensive_reaction(Unit *unit)
1315 {
1316 Plan *plan = unit->plan;
1317 int range;
1318
1319 /* Drop the current task and promptly attack any enemies within
1320 range. This is very important or we will loose the tactical
1321 initiative! */
1322
1323 /* But first check if we are assigned to defending another unit. */
1324 if (plan->maingoal
1325 && plan->maingoal->type == GOAL_UNIT_OCCUPIED) {
1326
1327 Unit *unit2 = find_unit(plan->maingoal->args[0]);
1328 /* Limit attack range to 1 if we are defending a unit. This
1329 will in most cases assure that the defender stays inside
1330 its protege, but an overrun action into an adjacent cell
1331 may still cause the defender to stray outside. */
1332 if (unit->transport && unit->transport == unit2) {
1333 range = 1;
1334 } else {
1335 range = u_ai_tactical_range(unit->type);
1336 }
1337 /* Fall through: don't interfere if we are on our way to
1338 defend a city. */
1339 if (in_play(unit2)
1340 && plan->tasks
1341 && plan->tasks->type == TASK_OCCUPY
1342 && plan->tasks->args[0] == unit2->id) {
1343 return;
1344 }
1345
1346 /* Also check if we are assigned to defending a specific cell. */
1347 } else if (plan->maingoal
1348 && plan->maingoal->type == GOAL_CELL_OCCUPIED) {
1349 int x = plan->maingoal->args[0], y = plan->maingoal->args[1];
1350
1351 /* Limit attack range to 1 in that case. */
1352 if (unit->x == x && unit->y == y) {
1353 range = 1;
1354 } else {
1355 range = u_ai_tactical_range(unit->type);
1356 }
1357 /* Fall through: don't interfere if we are on our way to
1358 defend a cell. */
1359 if (inside_area(x, y)
1360 && plan->tasks
1361 && plan->tasks->type == TASK_MOVE_TO
1362 && plan->tasks->args[0] == x
1363 && plan->tasks->args[1] == y) {
1364 return;
1365 }
1366
1367 /* Use default tactical range in all other cases. */
1368 } else
1369 range = u_ai_tactical_range(unit->type);
1370
1371 /* Fall-through: don't interfere if we already are in a fight. */
1372 if (plan->tasks
1373 && (plan->tasks->type == TASK_HIT_UNIT
1374 || plan->tasks->type == TASK_HIT_POSITION
1375 || plan->tasks->type == TASK_CAPTURE
1376 /* Don't forget about critical tasks. */
1377 || plan->tasks->type == TASK_REPAIR
1378 || plan->tasks->type == TASK_RESUPPLY
1379 /* Or if we are chasing a victim. */
1380 || (plan->tasks->type == TASK_MOVE_TO
1381 && plan->tasks->next
1382 && (plan->tasks->next->type == TASK_HIT_UNIT
1383 || plan->tasks->next->type == TASK_HIT_POSITION
1384 || plan->tasks->next->type == TASK_CAPTURE
1385 /* Don't forget about critical tasks. */
1386 || plan->tasks->next->type == TASK_REPAIR
1387 || plan->tasks->next->type == TASK_RESUPPLY
1388 ))))
1389 return;
1390 ai_go_after_victim(unit, range, TRUE);
1391 }
1392
1393 extern int victim_x, victim_y, victim_rating, victim_utype, victim_sidenum;
1394 extern OccStatus victim_occstatus;
1395 extern int victim_flags;
1396 extern int victim_dmgtypes;
1397
1398 /* (Nasty hack. Should rearrange header stuff instead, or put
1399 ai_go_after_victim in 'plan.c'.) */
1400 extern void set_hit_unit_task(Unit *unit, int x, int y, int u, int s);
1401 extern void set_move_to_task(Unit *unit, int x, int y, int dist);
1402 extern void push_move_to_task(Unit *unit, int x, int y, int dist);
1403 extern void set_capture_task(Unit *unit, int x, int y, int u, int s);
1404
1405 int
ai_go_after_victim(Unit * unit,int range,int broadcast)1406 ai_go_after_victim(Unit *unit, int range, int broadcast)
1407 {
1408 int x = -1, y = -1, rslt = FALSE;
1409 int u1 = NONUTYPE, u2 = NONUTYPE;
1410 Side *side = NULL, *oside = NULL;
1411 int dist = 0, strikedist = 0, range2 = -1, amtavail = 0, rsplypct = 0;
1412 int m = NONMTYPE;
1413
1414 u1 = unit->type;
1415 /* If we are immobile and cannot attack or fire,
1416 then get out immediately. */
1417 if (!mobile(u1) && !could_attack_any(u1) && !could_fire_at_any(u1))
1418 return FALSE;
1419 /* If victim seeker makes a better transport than victimizer,
1420 and it is now devoid of occs, then don't bother looking for
1421 victims. */
1422 /*! \note This shunt probably belongs elsewhere, but it fine here for
1423 now, until some heavy improvement can be done on the AI. */
1424 if (u_is_transport(u1) && !unit->occupant
1425 && (u_offensive_worth(u1) < u_defensive_worth(u1)))
1426 return FALSE;
1427 /* Clip the range based on a rough estimate of how much fuel we
1428 actually have left. */
1429 /* (TODO: Should move range clipper to a generic function.) */
1430 range2 = area.maxdim;
1431 for_all_material_types(m) {
1432 if (0 >= um_consumption_per_move(u1, m))
1433 continue;
1434 if (unit->side)
1435 rsplypct = unit_doctrine(unit)->resupply_percent;
1436 else
1437 rsplypct = 50;
1438 amtavail = unit->supply[m] - ((um_storage_x(u1, m) * rsplypct) / 100);
1439 if (amtavail < 0)
1440 return FALSE;
1441 range2 = min(range2,
1442 (amtavail / um_consumption_per_move(u1, m)) *
1443 u_move_range(u1));
1444 }
1445 range = min(range, range2);
1446 /* Clip the range to the striking distance, if unit is on transport. */
1447 /* (TODO: Account for attack ranges > 1.) */
1448 if (unit->transport) {
1449 range2 = max((could_attack_any(u1) ? 1 : 0),
1450 (could_fire_at_any(u1) ? u_range(u1) : 0));
1451 range = min(range, range2);
1452 }
1453 /* Perform search for a victim. */
1454 tmpunit = unit;
1455 DMprintf("%s (%s) seeking victim within radius %d... ",
1456 unit_desig(unit), ai_type_name(unit->side->aitype), range);
1457 victim_rating = 0;
1458 rslt = limited_search_around(unit->x, unit->y, range, ai_victim_here,
1459 &x, &y, 1, 5);
1460 run_ui_idler();
1461 if (victim_rating > 0) {
1462 rslt = TRUE;
1463 DMprintf("\n...and a victim is found!\n");
1464 }
1465 else {
1466 DMprintf("\n...and could not find one.\n");
1467 return FALSE;
1468 }
1469 u2 = victim_utype;
1470 side = unit->side;
1471 oside = side_n(victim_sidenum);
1472 x = victim_x; y = victim_y;
1473 dist = distance(unit->x, unit->y, x, y);
1474 strikedist = max((could_damage_by_fire(u1, u2) ?
1475 type_ideal_fire_range_max(u1, u2) : 0),
1476 (could_damage_by_attacks(u1, u2) ?
1477 type_ideal_attack_range_max(u1, u2) : 1));
1478 if ((victim_flags & VICTIM_ENCOUNTERABLE) && (g_combat_model() == 1)
1479 && mobile(u1)) {
1480 if (broadcast) {
1481 net_set_hit_unit_task(unit, x, y, u2, victim_sidenum);
1482 net_push_move_to_task(unit, x, y, 1);
1483 }
1484 else {
1485 set_hit_unit_task(unit, x, y, u2, victim_sidenum);
1486 push_move_to_task(unit, x, y, 1);
1487 }
1488 }
1489 else if (victim_flags & VICTIM_CAPTURABLE) {
1490 if (g_combat_model() == 1) {
1491 if (broadcast) {
1492 net_set_hit_unit_task(unit, x, y, u2, victim_sidenum);
1493 if (mobile(u1) && (dist > 1))
1494 net_push_move_to_task(unit, x, y, 1);
1495 }
1496 else {
1497 set_hit_unit_task(unit, x, y, u2, victim_sidenum);
1498 if (mobile(u1) && (dist > 1))
1499 push_move_to_task(unit, x, y, 1);
1500 }
1501 }
1502 /* Should check to see whether direct capture or capture by hitting
1503 is less expensive in terms of ACP, materials, etc.... */
1504 /* Should check to see if occs prevent direct capture. */
1505 else if (could_capture_by_attacks(u1, u2, oside)
1506 || could_capture_by_fire(u1, u2, oside)) {
1507 if (broadcast) {
1508 net_set_hit_unit_task(unit, x, y, u2, victim_sidenum);
1509 if (mobile(u1) && (dist > 1))
1510 net_push_move_to_task(unit, x, y, 1);
1511 }
1512 else {
1513 set_hit_unit_task(unit, x, y, u2, victim_sidenum);
1514 if (mobile(u1) && (dist > 1))
1515 push_move_to_task(unit, x, y, 1);
1516 }
1517 }
1518 else if (could_capture_by_capture(u1, u2, oside)
1519 && (g_combat_model() == 0)) {
1520 if (broadcast) {
1521 net_set_capture_task(unit, x, y, u2, victim_sidenum);
1522 if (mobile(u1) && (dist > 1))
1523 net_push_move_to_task(unit, x, y, 1);
1524 }
1525 else {
1526 set_capture_task(unit, x, y, u2, victim_sidenum);
1527 if (mobile(u1) && (dist > 1))
1528 push_move_to_task(unit, x, y, 1);
1529 }
1530 }
1531 else {
1532 if (broadcast)
1533 net_set_move_to_task(unit, x, y, 1);
1534 else
1535 set_move_to_task(unit, x, y, 1);
1536 }
1537 } /* victim_flags & VICTIM_CAPTURABLE */
1538 else {
1539 if ((victim_dmgtypes & DAMAGE_TYPE_HIT)
1540 || (victim_flags & VICTIM_SHAKEABLE)) {
1541 if (broadcast) {
1542 net_set_hit_unit_task(unit, x, y, u2, victim_sidenum);
1543 if (dist > strikedist)
1544 net_push_move_to_task(unit, x, y, strikedist);
1545 }
1546 else {
1547 set_hit_unit_task(unit, x, y, u2, victim_sidenum);
1548 if (dist > strikedist)
1549 push_move_to_task(unit, x, y, strikedist);
1550 }
1551 }
1552 else if (mobile(u1)) {
1553 if (broadcast)
1554 net_set_move_to_task(unit, x, y, 0);
1555 else
1556 set_move_to_task(unit, x, y, 0);
1557 }
1558 else
1559 return FALSE;
1560 }
1561 return rslt;
1562 }
1563
1564 /* The point of this new function is to limit the search for captives
1565 to a given range. */
1566
1567 static int
ai_go_after_captive(Unit * unit,int range)1568 ai_go_after_captive(Unit *unit, int range)
1569 {
1570 int x, y, rslt;
1571
1572 tmpunit = unit;
1573
1574 DMprintf("%s (%s) searching for useful capture within %d; found ",
1575 unit_desig(unit), ai_type_name(unit->side->aitype), range);
1576 rslt = search_around(unit->x, unit->y, range,
1577 useful_captureable_here, &x, &y, 1);
1578 if (rslt) {
1579 DMprintf("one at %d,%d\n", x, y);
1580 /* Set up a task to go after the unit found. */
1581 net_set_capture_task(unit, x, y, tmputype, tmpside->id);
1582 if (unit->transport
1583 && mobile(unit->transport->type)
1584 && unit->transport->plan) {
1585 net_set_move_to_task(unit->transport, x, y, 1);
1586 }
1587 return TRUE;
1588 } else {
1589 DMprintf("nothing\n");
1590 return FALSE;
1591 }
1592 }
1593
1594 static int
ai_fire_at_opportunity(Unit * unit)1595 ai_fire_at_opportunity(Unit *unit)
1596 {
1597 int x, y, range, rslt;
1598 extern int target_x, target_y, target_rating, target_utype, target_sidenum;
1599
1600 tmpunit = unit;
1601 range = u_range(unit->type);
1602 /* Look further for targets if we are mobile. */
1603 if (mobile(unit->type)) {
1604 range += u_ai_tactical_range(unit->type);
1605 }
1606 target_rating = -9999;
1607 DMprintf("%s (%s) seeking target within %d; found ",
1608 unit_desig(unit), ai_type_name(unit->side->aitype), range);
1609 rslt = search_around(unit->x, unit->y, range, target_here, &x, &y, 1);
1610 if (rslt) {
1611 DMprintf("s%d %s at %d,%d\n", target_sidenum,
1612 u_type_name(target_utype), x, y);
1613 /* Set up a task to shoot at the unit found. */
1614 net_set_hit_unit_task(unit, x, y, target_utype, target_sidenum);
1615 } else if (target_rating > -9999) {
1616 DMprintf("s%d %s (rated %d) at %d,%d\n",
1617 target_sidenum, u_type_name(target_utype), target_rating,
1618 x, y);
1619 /* Set up a task to shoot at the unit found. */
1620 net_set_hit_unit_task(unit, target_x, target_y, target_utype,
1621 target_sidenum);
1622 } else {
1623 DMprintf("nothing\n");
1624 }
1625 return rslt;
1626 }
1627
1628 /* Return true if the unit can actually damage the other unit. */
1629
1630 int
attack_can_damage_or_capture(Unit * unit,Unit * unit2)1631 attack_can_damage_or_capture(Unit *unit, Unit *unit2)
1632 {
1633 Unit *occ;
1634
1635 if (!alive(unit) || !alive(unit2))
1636 return FALSE;
1637 if (capture_chance(unit->type, unit2->type, unit2->side) > 0)
1638 return TRUE;
1639 /* (should check for right kind of ammo) */
1640 if (uu_hit(unit->type, unit2->type) <= 0)
1641 return FALSE;
1642 /* Also take into account if we can damage any occs. Differs from
1643 attack code in that only visible occs are considered. */
1644 /* Return TRUE if we can damage the unit itself. */
1645 if (uu_damage(unit->type, unit2->type) > 0)
1646 return TRUE;
1647 /* Else check if we can hit and damage any of its occs. */
1648 for_all_occs_with_occs(unit2, occ) {
1649 int immune = FALSE;
1650 Unit *transport = occ->transport;
1651
1652 /* Skip occs that we can't hit or damage. */
1653 if (uu_hit(unit->type, occ->type <= 0)
1654 || uu_damage(unit->type, occ->type <= 0))
1655 continue;
1656 /* Skip occs that we cannot see (no cheating - not even for the AI!) */
1657 if (!side_sees_image(unit->side, occ))
1658 continue;
1659 /* For vulnerable occs, check recursively that we also can hit
1660 all transports in the chain leading down to the occ. */
1661 while (transport) {
1662 if (uu_hit(unit->type, transport->type) <= 0) {
1663 immune = TRUE;
1664 break;
1665 }
1666 transport = transport->transport;
1667 }
1668 /* If we found an occ that is not immune we are done. */
1669 if (!immune)
1670 return TRUE;
1671 }
1672 /* We can't capture or hit anything. */
1673 return FALSE;
1674 }
1675
1676 /* Return true if the unit can actually damage the other unit by
1677 firing at it. */
1678
1679 int
fire_can_damage(Unit * unit,Unit * unit2)1680 fire_can_damage(Unit *unit, Unit *unit2)
1681 {
1682 Unit *occ;
1683
1684 if (!alive(unit) || !alive(unit2))
1685 return FALSE;
1686 /* (should check for right kind of ammo) */
1687 if (fire_hit_chance(unit->type, unit2->type) <= 0)
1688 return FALSE;
1689 /* Also take into account if we can damage any occs. Differs from fire code
1690 in that only visible occs are considered. */
1691 /* Return TRUE if we can damage the unit itself. */
1692 if (fire_damage(unit->type, unit2->type) > 0)
1693 return TRUE;
1694 /* Else check if we can hit and damage any of its occs. */
1695 for_all_occs_with_occs(unit2, occ) {
1696 int immune = FALSE;
1697 Unit *transport = occ->transport;
1698
1699 /* Skip occs that we can't hit or damage. */
1700 if (fire_hit_chance(unit->type, occ->type) <= 0
1701 || fire_damage(unit->type, occ->type) <= 0)
1702 continue;
1703 /* Skip occs that we cannot see (no cheating - not even for the AI!) */
1704 if (!side_sees_image(unit->side, occ))
1705 continue;
1706 /* For vulnerable occs, check recursively that we also can
1707 hit all transports in the chain leading down to the occ. */
1708 while (transport) {
1709 if (fire_hit_chance(unit->type, transport->type) <= 0) {
1710 immune = TRUE;
1711 break;
1712 }
1713 transport = transport->transport;
1714 }
1715 /* If we found an occ that is not immune we are done. */
1716 if (!immune)
1717 return TRUE;
1718 }
1719 /* We can't damage anything. */
1720 return FALSE;
1721 }
1722
1723 int
fire_can_damage_or_capture(Unit * unit,Unit * unit2)1724 fire_can_damage_or_capture(Unit *unit, Unit *unit2)
1725 {
1726 if (!alive(unit) || !alive(unit2))
1727 return FALSE;
1728 /* Always return TRUE if we can capture the unit. */
1729 if (capture_chance(unit->type, unit2->type, unit2->side) > 0)
1730 return TRUE;
1731 /* Determine whether the fire can damage. */
1732 return fire_can_damage(unit, unit2);
1733 }
1734
1735 /* Probability that one real unit will capture another real unit with
1736 protection taken into account. Differs from real capture code in
1737 that only visible occupants are considered (no cheating!) */
1738
1739 int
real_capture_chance(Unit * unit,Unit * unit2)1740 real_capture_chance(Unit *unit, Unit *unit2)
1741 {
1742 int chance, prot;
1743 int u2 = unit2->type;
1744 int u = unit->type;
1745 Unit *unit3;
1746
1747 chance = capture_chance(unit->type, unit2->type, unit2->side);
1748
1749 /* Occupants can protect the unit. */
1750 for_all_occupants(unit2, unit3) {
1751 if (is_active(unit3)
1752 && side_sees_image(unit->side, unit3)) {
1753 prot = uu_protection(unit3->type, u2);
1754 if (prot != 100)
1755 chance = (chance * prot) / 100;
1756 }
1757 }
1758 /* And so can its neighbours. */
1759 for_all_stack(unit2->x, unit2->y, unit3) {
1760 if (unit3 != unit2
1761 && is_active(unit3)
1762 && side_sees_image(unit->side, unit3)
1763 && unit3->side == unit2->side) {
1764 prot = uu_stack_protection(unit3->type, u2);
1765 if (prot != 100)
1766 chance = (chance * prot) / 100;
1767 }
1768 }
1769 for_all_stack_with_occs(unit2->x, unit2->y, unit3) {
1770 if (is_active(unit3)
1771 && side_sees_image(unit->side, unit3)
1772 /* We also extend protection to our buddies! */
1773 && trusted_side(unit3->side, unit2->side)) {
1774 /* This is when a unit, such as triple-A, provides unique
1775 protection against a specific attacker, such as
1776 bombers, to all other units in the cell. */
1777 prot = uu_cellwide_protection_against(unit3->type, u);
1778 if (prot != 100)
1779 chance = (chance * prot) / 100;
1780 /* This is when a unit (such as a garrison) specifically
1781 protects a second unit, such as a fort (but not other
1782 nearby units), against all forms of attack. It thus
1783 works the same way as uu_protection and
1784 uu_stack_protection. */
1785 prot = uu_cellwide_protection_for(unit3->type, u2);
1786 if (prot != 100)
1787 chance = (chance * prot) / 100;
1788 }
1789 }
1790 return chance;
1791 }
1792
1793 /* Integrate total worth of an advance by recursively accounting for any
1794 worth gained/lost by studying its precursor advances. */
1795
1796 static int
ai_integrate_advance_worth(Side * side,int a,int * numdeps)1797 ai_integrate_advance_worth(Side *side, int a, int *numdeps)
1798 {
1799 int a2 = NONATYPE, aval = 0;
1800
1801 assert_error(side, "Attempted to access a NULL side");
1802 assert_error(is_advance_type(a),
1803 "Attempted to use an illegal advance type");
1804 if (side_can_research(side, a))
1805 return max(0, tmp_a_array[a]);
1806 if (has_advance(side, a))
1807 return 0;
1808 for_all_advance_types(a2) {
1809 if (aa_needed_to_research(a, a2)) {
1810 if (has_advance(side, a2))
1811 continue;
1812 ++(*numdeps);
1813 aval += ai_integrate_advance_worth(side, a2, numdeps);
1814 }
1815 }
1816 return aval;
1817 }
1818
1819 /* Is the advance in question precluded by another advance? */
1820
1821 #if (0)
1822 static int
is_precluded_advance(Side * side,int a)1823 is_precluded_advance(Side *side, int a)
1824 {
1825 int a2 = NONATYPE;
1826
1827 assert_error(side, "Attempted to manipulate a NULL side");
1828 assert_error(is_advance_type(a),
1829 "Attempted to use an illegal advance type");
1830 for_all_advance_types(a2) {
1831 if (aa_needed_to_research(a, a2)) {
1832 if (aa_precludes(a2, a) && has_advance(side, a2))
1833 return TRUE;
1834 else {
1835 if (has_advance(side, a2))
1836 return FALSE;
1837 else
1838 return is_precluded_advance(side, a2);
1839 }
1840 }
1841 }
1842 return FALSE;
1843 }
1844 #endif
1845
1846 /* Choose a research goal for a side. */
1847
1848 static void
ai_pick_side_research_goal(Side * side)1849 ai_pick_side_research_goal(Side *side)
1850 {
1851 int a = NONATYPE, a2 = NONATYPE;
1852 int u = NONUTYPE, aval = -1, uval = -1;
1853 int n = -1, ntot = 0, numdeps = 0;
1854 int *tmparray = NULL;
1855 Obj *newgoals = lispnil, *newgoal = lispnil;
1856
1857 assert_error(side, "Attempted to manipulate a NULL side");
1858 /* If the side cannot research, then return. */
1859 if ((side == indepside) && (!g_indepside_can_research()
1860 || !g_indepside_has_treasury()))
1861 return;
1862 /* If a research goal is already set, then simply return. */
1863 if (is_advance_type(side->research_goal)
1864 && !(side->research_precluded[side->research_goal]))
1865 return;
1866 /* If a set of initial advances is specified, then utilize it. */
1867 newgoals = g_ai_initial_research_goals();
1868 if (lispnil != newgoals) {
1869 if (consp(newgoals))
1870 newgoal =
1871 choose_side_research_goal_from_weighted_list(newgoals, &ntot, side);
1872 else
1873 newgoal = eval(newgoals);
1874 }
1875 if (lispnil != newgoal) {
1876 newgoal = eval(newgoal);
1877 if (atypep(newgoal)) {
1878 if (is_advance_type(c_number(newgoal))) {
1879 side->research_goal = c_number(newgoal);
1880 return;
1881 }
1882 else
1883 run_warning(
1884 "Invalid research goal provided from list of initial research goals");
1885 }
1886 else
1887 run_warning(
1888 "Invalid research goal provided from list of initial research goals");
1889 }
1890 /* Prepare the advances scratch space. */
1891 memset(tmp_a_array, -1, numatypes * sizeof(int));
1892 /* Try to get a guesstimate of the worth of individual advances. */
1893 for_all_advance_types(a) {
1894 aval = 0;
1895 if (has_advance(side, a))
1896 continue;
1897 if (side->research_precluded[a])
1898 continue;
1899 for_all_advance_types(a2) {
1900 if (aa_needed_to_research(a2, a))
1901 ++aval;
1902 }
1903 for_all_unit_types(u) {
1904 #if (0)
1905 if (!type_ever_available(u, side))
1906 continue;
1907 #endif
1908 uval = total_worth(u);
1909 if (uval > 0) {
1910 aval += (uval * ua_needed_to_build(u, a));
1911 aval += (uval * ua_to_change_type(u, a));
1912 }
1913 }
1914 /* (TODO: Consider boosts to materials production, etc....) */
1915 if (aval > 0) {
1916 tmp_a_array[a] = aval;
1917 }
1918 else {
1919 tmp_a_array[a] = -a_rp(a);
1920 }
1921 } /* for_all_advance_types */
1922 /* If cycle is present, then choose a research goal from the immediately
1923 available advances only. */
1924 if (G_advances_graph_has_cycles) {
1925 for_all_advance_types(a) {
1926 if (!side_can_research(side, a))
1927 tmp_a_array[a] = 0;
1928 }
1929 }
1930 /* If no cycles, then integrate the worth of each advance. */
1931 else {
1932 tmparray = (int *)xmalloc(numatypes * sizeof(int));
1933 /* Integrate the worth of all dependent advances into each advance. */
1934 /* Also, rescale according distance from goal. */
1935 for_all_advance_types(a) {
1936 numdeps = 0;
1937 if (!(side->research_precluded[a]) && !has_advance(side, a))
1938 tmparray[a] += ai_integrate_advance_worth(side, a, &numdeps);
1939 if ((tmparray[a] > 0) && numdeps)
1940 tmparray[a] = (tmparray[a] / numdeps) + 1;
1941 }
1942 memcpy(tmp_a_array, tmparray, numatypes * sizeof(int));
1943 free(tmparray);
1944 }
1945 /* Knock intermediate advances out of contention. Only forking branches
1946 and leaves of the tree should remain. */
1947 if (!G_advances_graph_has_cycles) {
1948 for_all_advance_types(a) {
1949 numdeps = 0;
1950 for_all_advance_types(a2) {
1951 if (aa_needed_to_research(a2, a)) {
1952 #if (0)
1953 ++numdeps;
1954 break;
1955 #endif
1956 if (numdeps > 1)
1957 break;
1958 }
1959 }
1960 /* Ignore leaves (numdeps == 0) or forks (numdeps > 1). */
1961 if (1 == numdeps)
1962 tmp_a_array[a] = 0;
1963 #if (0)
1964 if (numdeps)
1965 tmp_a_array[a] = 0;
1966 #endif
1967 }
1968 }
1969 /* Randomly select a research goal from weighted list. */
1970 ntot = 0;
1971 for_all_advance_types(a) {
1972 if (tmp_a_array[a] > 0)
1973 ntot += tmp_a_array[a];
1974 }
1975 n = xrandom(ntot);
1976 ntot = 0;
1977 for_all_advance_types(a) {
1978 if (tmp_a_array[a] > 0) {
1979 ntot += tmp_a_array[a];
1980 if (ntot > n) {
1981 side->research_goal = a;
1982 return;
1983 }
1984 }
1985 }
1986 Dprintf("Could not find a research goal for side %d.\n", side->id);
1987 }
1988
1989 /* Determine if researching a particular topic leads to a given research
1990 goal. */
1991
1992 static int
advance_leads_to_goal(Side * side,int a)1993 advance_leads_to_goal(Side *side, int a)
1994 {
1995 int agoal = NONATYPE;
1996
1997 assert_error(side, "Attempted to manipulate a NULL side");
1998 assert_error(is_advance_type(a),
1999 "Attempted to use an illegal advance type");
2000 assert_warning_return(is_advance_type(side->research_goal),
2001 "Cannot seek unset advance goal", FALSE);
2002 if (G_advances_graph_has_cycles)
2003 return FALSE;
2004 agoal = side->research_goal;
2005 if (a == agoal)
2006 return TRUE;
2007 if (side->research_precluded[a])
2008 return FALSE;
2009 return get_packed_bool(G_advances_synopsis, agoal, a);
2010 }
2011
2012 /* Pick a research topic. First set a resarch goal, if necessary. */
2013
2014 void
ai_pick_side_research(Side * side)2015 ai_pick_side_research(Side *side)
2016 {
2017 int a = NONATYPE;
2018
2019 assert_error(side, "Attempted to manipulate a NULL side");
2020 /* If something is already being researched, then continue with it. */
2021 if (is_advance_type(side->research_topic))
2022 return;
2023 /* Reset a research goal that may have been precluded for some reason. */
2024 if (is_advance_type(side->research_goal)
2025 && side->research_precluded[side->research_goal])
2026 side->research_goal = NONATYPE;
2027 /* Choose a research goal if one is not already in place. */
2028 if (!is_advance_type(side->research_goal))
2029 ai_pick_side_research_goal(side);
2030 /* Work towards the research goal, if one was chosen. */
2031 if (is_advance_type(side->research_goal)) {
2032 for_all_advance_types(a) {
2033 if (side_can_research(side, a)
2034 && ((G_advances_graph_has_cycles && (a == side->research_goal))
2035 || advance_leads_to_goal(side, a))) {
2036 side->research_topic = a;
2037 return;
2038 }
2039 }
2040 Dprintf("Could not research towards goal for side %d.\n", side->id);
2041 side->research_goal = NONATYPE;
2042 }
2043 /* If no research goal or could not find an advance to get to the goal,
2044 then pick first researchable advance. */
2045 for_all_advance_types(a) {
2046 if (side_can_research(side, a)) {
2047 side->research_topic = a;
2048 return;
2049 }
2050 }
2051 }
2052
2053 /* Pick a good research topic for an AI-controlled side. */
2054
2055 static void
ai_plan_research(Side * side)2056 ai_plan_research(Side *side)
2057 {
2058 ai_pick_side_research(side);
2059 net_set_side_research_topic(side, side->research_topic);
2060 net_set_side_research_goal(side, side->research_goal);
2061 }
2062
2063 /* Return true if the given type should be used to collect the given
2064 type of material. */
2065
2066 int
need_this_type_to_collect(Side * side,int u,int m)2067 need_this_type_to_collect(Side *side, int u, int m)
2068 {
2069 return (strcmp(u_type_name(u), "villager") == 0);
2070 }
2071
2072 int
mp_collect_here(int x,int y)2073 mp_collect_here(int x, int y)
2074 {
2075 int m2;
2076
2077 if (can_extract_at(tmpunit, x, y, &m2)) {
2078 if (m2 == tmpmtype)
2079 return TRUE;
2080 }
2081 if (can_load_at(tmpunit, x, y, &m2)) {
2082 if (m2 == tmpmtype)
2083 return TRUE;
2084 }
2085 return FALSE;
2086 }
2087
2088 /* Assign the given unit to the collection of the given type of
2089 material. */
2090
2091 void
assign_to_collection(Side * side,Unit * unit,int m)2092 assign_to_collection(Side *side, Unit *unit, int m)
2093 {
2094 int x, y;
2095
2096 tmpunit = unit;
2097 tmpmtype = m;
2098 search_around(unit->x, unit->y, 10, mp_collect_here, &x, &y, 1);
2099 net_set_unit_plan_type(side, unit, PLAN_IMPROVING);
2100 net_set_collect_task(unit, m, x, y);
2101 DMprintf("%s assigned to collecting %s at %d,%d\n",
2102 unit_desig(unit), m_type_name(m), x, y);
2103 }
2104
2105 /* Unit's goal in life will be to improve the world...
2106 ...or, at least itself. */
2107
2108 void
assign_to_improve(Side * side,Unit * unit)2109 assign_to_improve(Side *side, Unit *unit)
2110 {
2111 Goal *goal = NULL;
2112
2113 goal = create_goal(GOAL_COLONIZE, side, TRUE);
2114 goal->args[0] = unit->type;
2115 net_set_unit_plan_type(side, unit, PLAN_IMPROVING);
2116 net_set_unit_main_goal(side, unit, goal);
2117 DMprintf("%s assigned to improve\n", unit_desig(unit));
2118 }
2119
2120 void
assign_to_defense(Side * side,Unit * unit)2121 assign_to_defense(Side *side, Unit *unit)
2122 {
2123 Theater *theater;
2124 Goal *goal;
2125
2126 net_set_unit_plan_type(side, unit, PLAN_DEFENSIVE);
2127 theater = theater_at(side, unit->x, unit->y);
2128 set_unit_theater(unit, theater);
2129 if (theater != NULL) {
2130 ++(theater->numassigned[unit->type]);
2131 goal = create_goal(GOAL_VICINITY_HELD, side, TRUE);
2132 goal->args[0] = theater->x; goal->args[1] = theater->y;
2133 goal->args[2] = (theater->xmax - theater->xmin) / 2;
2134 goal->args[3] = (theater->ymax - theater->ymin) / 2;
2135 net_set_unit_main_goal(side, unit, goal);
2136 DMprintf("%s now assigned to defense in %s\n",
2137 unit_desig(unit), theater->name);
2138 } else {
2139 DMprintf("%s now assigned to defense in no theater\n",
2140 unit_desig(unit));
2141 }
2142 }
2143
2144 #if 0
2145
2146 /* Assign unit to defend theater. Does NOT change the plan type. */
2147
2148 void
2149 assign_to_defend_theater(Unit *unit, Theater *theater)
2150 {
2151 Goal *goal;
2152
2153 /* Clear the task aganda. */
2154 net_clear_task_agenda(unit->side, unit);
2155
2156 /* Set main goal to hold the vicinity of (x, y). */
2157 goal = create_goal(GOAL_VICINITY_HELD, unit->side, TRUE);
2158 goal->args[0] = theater->x;
2159 goal->args[1] = theater->y;
2160 goal->args[2] = (theater->xmax - theater->xmin) / 2;
2161 goal->args[3] = (theater->ymax - theater->ymin) / 2;
2162 net_set_unit_main_goal(unit->side, unit, goal);
2163 DMprintf("%s now assigned to defense in %s\n",
2164 unit_desig(unit), theater->name);
2165 }
2166 #endif
2167
2168 /* Assign unit to defend unit2. Does NOT change the plan type. */
2169
2170 void
assign_to_defend_unit(Unit * unit,Unit * unit2)2171 assign_to_defend_unit(Unit *unit, Unit *unit2)
2172 {
2173 Goal *goal;
2174
2175 net_set_unit_plan_type(unit->side, unit, PLAN_DEFENSIVE);
2176 /* Set main goal to occupy unit2. */
2177 goal = create_goal(GOAL_UNIT_OCCUPIED, unit->side, TRUE);
2178 goal->args[0] = unit2->id;
2179 net_set_unit_main_goal(unit->side, unit, goal);
2180 DMprintf("%s assigned to occupy %s\n",
2181 unit_desig(unit), unit_desig(unit2));
2182 }
2183
2184 #if 0
2185 /* Assign unit to defend cell at (x, y). */
2186
2187 void
2188 assign_to_defend_cell(Unit *unit, int x, int y)
2189 {
2190 Goal *goal;
2191
2192 net_set_unit_plan_type(unit->side, unit, PLAN_DEFENSIVE);
2193 /* Set main goal to occupy (x, y). */
2194 goal = create_goal(GOAL_CELL_OCCUPIED, unit->side, TRUE);
2195 goal->args[0] = x;
2196 goal->args[1] = y;
2197 net_set_unit_main_goal(unit->side, unit, goal);
2198 DMprintf("%s assigned to occupy cell at (%d, %d)\n",
2199 unit_desig(unit), x, y);
2200 }
2201 #endif
2202
2203 #if 0
2204 /* Assign unit to defend the vicinity of (x, y). Does NOT change the
2205 plan type. */
2206
2207 void
2208 assign_to_defend_vicinity(Unit *unit, int x, int y, int w, int h)
2209 {
2210 Goal *goal;
2211
2212 /* Clear the task aganda. */
2213 net_clear_task_agenda(unit->side, unit);
2214
2215 /* Set main goal to hold the vicinity of (x, y). */
2216 goal = create_goal(GOAL_VICINITY_HELD, unit->side, TRUE);
2217 goal->args[0] = x;
2218 goal->args[1] = y;
2219 goal->args[2] = w;
2220 goal->args[3] = h;
2221 net_set_unit_main_goal(unit->side, unit, goal);
2222 DMprintf("%s now assigned to defense the vicinity of (%d, %d)\n",
2223 unit_desig(unit), x, y);
2224 }
2225 #endif
2226
2227 int
compare_weights(CONST void * w1,CONST void * w2)2228 compare_weights(CONST void *w1, CONST void *w2)
2229 {
2230 return (((struct weightelt *) w2)->weight
2231 - ((struct weightelt *) w1)->weight);
2232 }
2233
2234 /* Return true if the given unit type has a chance to reach a position
2235 where it can view the given location, for instance an adjacent cell
2236 with safe terrain. */
2237
2238 static int
probably_explorable(Side * side,int x,int y,int u)2239 probably_explorable(Side *side, int x, int y, int u)
2240 {
2241 int dir, x1, y1, tview, t;
2242
2243 if (UNSEEN != terrain_view(side, x, y))
2244 return FALSE;
2245 for_all_directions(dir) {
2246 if (interior_point_in_dir(x, y, dir, &x1, &y1)) {
2247 tview = terrain_view(side, x1, y1);
2248 if (tview == UNSEEN)
2249 return TRUE;
2250 t = vterrain(tview);
2251 if (could_be_on(u, t) && could_live_on(u, t))
2252 return TRUE;
2253 }
2254 }
2255 return FALSE;
2256 }
2257
2258 /* Set the unit up as an explorer and let it go. */
2259
2260 void
assign_to_exploration(Side * side,Unit * unit)2261 assign_to_exploration(Side *side, Unit *unit)
2262 {
2263 int numweights = 0, weight, i, dist;
2264 struct weightelt weights[MAXTHEATERS];
2265 Theater *theater;
2266
2267 /* Unit's goal in life will be to see that the world is all known. */
2268 net_set_unit_plan_type(side, unit, PLAN_EXPLORATORY);
2269 set_unit_theater(unit, NULL);
2270 /* Find the theater most in need of exploration. */
2271 for_all_theaters(side, theater) {
2272 if (theater->size > 0 && theater->unexplored > 0) {
2273 /* Weight by percentage of theater that is unknown. */
2274 weight = (100 * theater->unexplored) / theater->size;
2275 /* Downrate theaters that are far away. */
2276 dist = distance(unit->x, unit->y, theater->x, theater->y)
2277 - isqrt(theater->size) / 2;
2278 if (dist < 0)
2279 dist = 0;
2280 weight /= max(1, (4 * dist) / area.maxdim);
2281 /* Uprate the home front by a lot - it will become
2282 completely known quickly, and then effectively drop out
2283 of the list. */
2284 if (theater == ai(side)->homefront)
2285 weight *= 4;
2286 /* Flatten out 10% variations, thus giving equal weight to
2287 theaters of similar value. */
2288 weight = 10 * (weight / 10);
2289 weights[numweights].weight = weight;
2290 weights[numweights].data = theater->id;
2291 ++numweights;
2292 }
2293 }
2294 if (numweights > 0) {
2295 qsort(weights, numweights, sizeof(struct weightelt), compare_weights);
2296 /* Choose randomly among theaters of equal weight. */
2297 for (i = 0; i < numweights; ++i)
2298 if (weights[i].weight < weights[0].weight)
2299 break;
2300 theater = ai(side)->theatertable[weights[xrandom(i)].data];
2301 } else {
2302 theater = NULL;
2303 }
2304 assign_explorer_to_theater(side, unit, theater);
2305 }
2306
2307 /* For a given unit in a given theater, find a location that it ought to
2308 try to explore. Start by choosing random points in the theater, then
2309 switch to exhaustive search if necessary. */
2310
2311 void
assign_explorer_to_theater(Side * side,Unit * unit,Theater * theater)2312 assign_explorer_to_theater(Side *side, Unit *unit, Theater *theater)
2313 {
2314 int x, y, w, h, sq, tries, found;
2315 Goal *goal;
2316
2317 /* Undo any existing assignment. Note that we always undo, even if
2318 new theater assignment fails, so that unit continues to be free
2319 for something else. */
2320 if (unit_theater(unit) != NULL) {
2321 --(unit_theater(unit)->numassigned[unit->type]);
2322 set_unit_theater(unit, NULL);
2323 /* (should release existing main goal?) */
2324 }
2325 /* Try to find an unexplored cell in the given theater. */
2326 /* (TODO: Look for other explorers assigned to the theater,
2327 and explore a random cell no less than a certain distance from them?) */
2328 if (theater != NULL) {
2329 tries = theater->size * 2;
2330 found = FALSE;
2331 while (tries-- > 0) {
2332 /* Select a random point within the theater. */
2333 x = theater->xmin; y = theater->ymin;
2334 x += (xrandom(theater->xmax - theater->xmin)
2335 + xrandom(theater->xmax - theater->xmin)) / 2;
2336 y += (xrandom(theater->ymax - theater->ymin)
2337 + xrandom(theater->ymax - theater->ymin)) / 2;
2338 /* See if the point is of any interest. */
2339 if (inside_area(x, y)
2340 && theater_at(side, x, y) == theater
2341 && terrain_view(side, x, y) == UNSEEN
2342 && probably_explorable(side, x, y, unit->type)) {
2343 found = TRUE;
2344 break;
2345 }
2346 }
2347 if (!inside_area(x, y)) {
2348 /* Now try iterating over entire theater. */
2349 for (x = theater->xmin; x <= theater->xmax; ++x) {
2350 for (y = theater->ymin; y <= theater->ymax; ++y) {
2351 /* See if the point is of any interest. */
2352 if (inside_area(x, y)
2353 && theater_at(side, x, y) == theater
2354 && terrain_view(side, x, y) == UNSEEN
2355 && probably_explorable(side, x, y, unit->type)) {
2356 found = TRUE;
2357 break;
2358 }
2359 }
2360 if (found)
2361 break;
2362 }
2363 }
2364 if (!found) {
2365 /* (should indicate failure in unit data somehow?) */
2366 DMprintf("%s did not find anything to explore in %s\n",
2367 unit_desig(unit), theater->name);
2368 return;
2369 }
2370 set_unit_theater(unit, theater);
2371 ++(theater->numassigned[unit->type]);
2372 /* Create a goal of having the whole vicinity known. */
2373 goal = create_goal(GOAL_VICINITY_KNOWN, side, TRUE);
2374 goal->args[0] = x; goal->args[1] = y;
2375 sq = isqrt(theater->size);
2376 /* (should clip to theater boundary?) */
2377 w = h = sq / 2;
2378 goal->args[2] = w; goal->args[3] = h;
2379 net_set_unit_main_goal(side, unit, goal);
2380 DMprintf("%s now assigned to explore in %s, %dx%d area around %d,%d\n",
2381 unit_desig(unit), theater->name, w, h, x, y);
2382 }
2383 }
2384
2385 /* Explorer constructors concentrate on building types that are good for
2386 exploration. */
2387
2388 void
assign_to_explorer_construction(Side * side,Unit * unit)2389 assign_to_explorer_construction(Side *side, Unit *unit)
2390 {
2391 /* Unit's goal in life will be to help see that the world is all known. */
2392 net_set_unit_plan_type(side, unit, PLAN_EXPLORATORY);
2393 DMprintf("%s assigned to explorer construction\n", unit_desig(unit));
2394 }
2395
2396 void
assign_to_offense(Side * side,Unit * unit)2397 assign_to_offense(Side *side, Unit *unit)
2398 {
2399 int numweights = 0, weight;
2400 struct weightelt weights[MAXTHEATERS];
2401 Goal *goal;
2402 Theater *homefront, *theater;
2403 int w = -1, h = -1;
2404
2405 net_set_unit_plan_type(side, unit, PLAN_OFFENSIVE);
2406 /* If there is a target, then deal with it before any goals. */
2407 if (ai_go_after_victim(unit, u_ai_tactical_range(unit->type), TRUE))
2408 return;
2409 /* If our home area is being threatened, assign the unit to it. */
2410 homefront = ai(side)->homefront;
2411 if (homefront != NULL && homefront->enemystrengthmin > 0) {
2412 set_unit_theater(unit, homefront);
2413 goal = create_goal(GOAL_VICINITY_HELD, side, TRUE);
2414 goal->args[0] = homefront->x; goal->args[1] = homefront->y;
2415 goal->args[2] = goal->args[3] = isqrt(homefront->size);
2416 net_set_unit_main_goal(side, unit, goal);
2417 DMprintf("%s assigned to offensive in the home front\n",
2418 unit_desig(unit));
2419 return;
2420 }
2421 /* If the theater the unit is currently in is being threatened,
2422 assign the unit to it. */
2423 /* (should just increase it weight in next calculation?) */
2424 theater = theater_at(side, unit->x, unit->y);
2425 if (theater != NULL && theater->enemystrengthmin > 0) {
2426 set_unit_theater(unit, theater);
2427 #if (0)
2428 goal = create_goal(GOAL_VICINITY_HELD, side, TRUE);
2429 /* (should randomize?) */
2430 goal->args[0] = theater->x; goal->args[1] = theater->y;
2431 goal->args[2] = (theater->xmax - theater->xmin) / 2;
2432 goal->args[3] = (theater->ymax - theater->ymin) / 2;
2433 net_set_unit_main_goal(side, unit, goal);
2434 #else
2435 w = (theater->xmax - theater->xmin) / 2;
2436 h = (theater->ymax - theater->ymin) / 2;
2437 net_set_unit_main_goal(side, unit, NULL);
2438 ai_go_after_victim(unit, min(w, h), TRUE);
2439 #endif
2440 DMprintf("%s assigned to offensive in the theater where it's at now\n",
2441 unit_desig(unit));
2442 return;
2443 }
2444 for_all_theaters(side, theater) {
2445 if (theater->enemystrengthmin > 0 || theater->unexplored > 0) {
2446 /* (should weight by strength relative to own units already
2447 there) */
2448 weight = theater->enemystrengthmax * 20;
2449 /* Prefer not to send unit to farther-away theaters. */
2450 if (distance(unit->x, unit->y, theater->x, theater->y) >
2451 area.maxdim / 2) {
2452 weight /= 2;
2453 }
2454 /* Prefer theaters with more unknown territory. */
2455 weight += (10 * theater->unexplored) / max(1, theater->size);
2456 weights[numweights].weight = weight;
2457 weights[numweights].data = theater->id;
2458 ++numweights;
2459 }
2460 }
2461 if (numweights > 0) {
2462 qsort(weights, numweights, sizeof(struct weightelt), compare_weights);
2463 theater = ai(side)->theatertable[weights[0].data];
2464 } else {
2465 theater = theater_at(side, unit->x, unit->y);
2466 }
2467 set_unit_theater(unit, theater);
2468 if (theater != NULL) {
2469 ++(theater->numassigned[unit->type]);
2470 #if (0)
2471 goal = create_goal(GOAL_VICINITY_HELD, side, TRUE);
2472 /* (should randomize?) */
2473 goal->args[0] = theater->x; goal->args[1] = theater->y;
2474 goal->args[2] = (theater->xmax - theater->xmin) / 2;
2475 goal->args[3] = (theater->ymax - theater->ymin) / 2;
2476 net_set_unit_main_goal(side, unit, goal);
2477 #else
2478 w = (theater->xmax - theater->xmin) / 2;
2479 h = (theater->ymax - theater->ymin) / 2;
2480 net_set_unit_main_goal(side, unit, NULL);
2481 net_set_move_to_task(unit, theater->x, theater->y, min(w, h));
2482 #endif
2483 DMprintf("%s now assigned to offensive in %s",
2484 unit_desig(unit), theater->name);
2485 if (numweights > 1) {
2486 DMprintf(" (weight %d; runnerup was %s, weight %d)",
2487 weights[0].weight,
2488 (ai(side)->theatertable[weights[1].data])->name,
2489 weights[1].weight);
2490 }
2491 DMprintf("\n");
2492 } else {
2493 DMprintf("%s now assigned to offensive in no theater\n",
2494 unit_desig(unit));
2495 }
2496 }
2497
2498 void
assign_to_offense_support(Side * side,Unit * unit)2499 assign_to_offense_support(Side *side, Unit *unit)
2500 {
2501 net_set_unit_plan_type(side, unit, PLAN_OFFENSIVE);
2502 }
2503
2504 #if (0)
2505 void
assign_to_colonization_support(Side * side,Unit * unit)2506 assign_to_colonization_support(Side *side, Unit *unit)
2507 {
2508 net_set_unit_plan_type(side, unit, PLAN_COLONIZING);
2509 }
2510 #endif
2511
2512 void
assign_to_defense_support(Side * side,Unit * unit)2513 assign_to_defense_support(Side *side, Unit *unit)
2514 {
2515 net_set_unit_plan_type(side, unit, PLAN_DEFENSIVE);
2516 }
2517
2518 /* For the given side and unit and plan, calculate the right type of
2519 unit to build. */
2520
2521 static int *pbt_prefs;
2522 static int *pbt_fringe_terrain;
2523 static int *pbt_enemy_types;
2524 static int *pbt_num_to_transport;
2525
2526 static int type_can_leave_unit(int u, Unit *unit);
2527
2528 static int
type_can_leave_unit(int u,Unit * unit)2529 type_can_leave_unit(int u, Unit *unit)
2530 {
2531 int x = unit->x, y = unit->y, x1, y1, dir;
2532 int mpcost;
2533
2534 for_all_directions(dir) {
2535 if (interior_point_in_dir(x, y, dir, &x1, &y1)
2536 && type_survives_in_cell(u, x1, y1)
2537 /* Blocking occupants may leave before we are done. */
2538 && type_can_occupy_empty_cell(u, x1, y1)) {
2539 /* Now calculate the move cost. */
2540 mpcost = total_move_cost(u, unit->type, x, y, 0, x1, y1, 0);
2541 /* Check if we can have enough mps. */
2542 if (type_can_have_enough_mp(u, mpcost)) {
2543 return TRUE;
2544 break;
2545 }
2546 }
2547 }
2548 return FALSE;
2549 }
2550
2551 int
suitable_port(Unit * unit)2552 suitable_port(Unit *unit)
2553 {
2554 int x1, y1, dir, u = unit->type;
2555
2556 for_all_directions(dir) {
2557 if (interior_point_in_dir(unit->x, unit->y, dir, &x1, &y1)
2558 && t_liquid(terrain_at(x1, y1))
2559 && aref(area.landsea_regions, x1, y1)->size
2560 >= u_minimal_sea_for_docks(u)) {
2561 return TRUE;
2562 break;
2563 }
2564 }
2565 return FALSE;
2566 }
2567
2568 int
preferred_build_type(Side * side,Unit * unit,int plantype)2569 preferred_build_type(Side *side, Unit *unit, int plantype)
2570 {
2571 int u = unit->type, u2, u3, t, found = FALSE, canbuildtransport = FALSE;
2572 int x, y, dir, x1, y1, est, rslt, sumfringe, totfringe;
2573 Unit *unit2, *occ;
2574 UnitView *uview;
2575 Theater *theater;
2576
2577 if (pbt_prefs == NULL)
2578 pbt_prefs = (int *) xmalloc(numutypes * sizeof(int));
2579 if (pbt_fringe_terrain == NULL)
2580 pbt_fringe_terrain = (int *) xmalloc(numttypes * sizeof(int));
2581 if (pbt_enemy_types == NULL)
2582 pbt_enemy_types = (int *) xmalloc(numutypes * sizeof(int));
2583 if (pbt_num_to_transport == NULL)
2584 pbt_num_to_transport = (int *) xmalloc(numutypes * sizeof(int));
2585 if (plantype == PLAN_EXPLORATORY) {
2586 /* Calculate the amount of each type of terrain at the edges
2587 of the known world. */
2588 for_all_terrain_types(t)
2589 pbt_fringe_terrain[t] = 0;
2590 for_all_cells(x, y) {
2591 if (terrain_view(side, x, y) != UNSEEN) {
2592 for_all_directions(dir) {
2593 if (point_in_dir(x, y, dir, &x1, &y1)
2594 && terrain_view(side, x1, y1) == UNSEEN) {
2595 ++(pbt_fringe_terrain[(int) terrain_at(x, y)]);
2596 break;
2597 }
2598 }
2599 }
2600 }
2601 } else {
2602 /* should use estimated strengths instead? */
2603 for_all_unit_types(u2)
2604 pbt_enemy_types[u2] = 0;
2605 for_all_interior_cells(x, y) {
2606 if (side->see_all) {
2607 /* Use new recursive macro instead that also sees occs
2608 within occs. */
2609 for_all_stack_with_occs(x, y, unit2) {
2610 if (!trusted_side(side, unit2->side))
2611 ++pbt_enemy_types[unit2->type];
2612 }
2613 } else {
2614 for_all_view_stack_with_occs(side, x, y, uview) {
2615 if (!trusted_side(side, side_n(uview->siden)))
2616 ++pbt_enemy_types[uview->type];
2617 }
2618 }
2619 }
2620 }
2621 /* Calculate a basic preference for each possible type. */
2622 for_all_unit_types(u2) {
2623 pbt_prefs[u2] = 0;
2624 est = est_completion_time(unit, u2);
2625 if (could_create(u, u2)
2626 && est >= 0
2627 && side_can_build(side, u2)) {
2628 if (0 /* any demand in this unit's own theater */) {
2629 } else if (need_more_transportation(side)) {
2630 for_all_unit_types(u3) {
2631 pbt_num_to_transport[u3] = 0;
2632 }
2633 for_all_theaters(side, theater) {
2634 for_all_unit_types(u3) {
2635 pbt_num_to_transport[u3] += theater->numtotransport[u3];
2636 }
2637 }
2638 for_all_unit_types(u3) {
2639 if (pbt_num_to_transport[u3] > 0
2640 && mobile(u2)
2641 && could_carry(u2, u3)) {
2642 pbt_prefs[u2] += pbt_num_to_transport[u3];
2643 canbuildtransport = TRUE;
2644 }
2645 }
2646 }
2647 }
2648 }
2649 /* Check if any transports that we can build also can be used here. */
2650 if (canbuildtransport) {
2651 for_all_unit_types(u2) {
2652 if (pbt_prefs[u2] > 0) {
2653 /* First check that we can at all leave the unit. */
2654 if (type_can_leave_unit(u2, unit)) {
2655 /* Then check that any naval transports that we plan to
2656 build have more than just the city pond to swim in. */
2657 if (u_air_mobile(u2)
2658 || u_ground_mobile(u2)
2659 || (u_naval_mobile(u2)
2660 && suitable_port(unit))) {
2661 found = TRUE;
2662 } else {
2663 pbt_prefs[u2] = 0;
2664 }
2665 } else {
2666 pbt_prefs[u2] = 0;
2667 }
2668 }
2669 }
2670 }
2671 if (!found) {
2672 for_all_unit_types(u2) {
2673 pbt_prefs[u2] = 0;
2674 est = est_completion_time(unit, u2);
2675 if (could_create(u, u2)
2676 && est >= 0
2677 && side_can_build(side, u2)) {
2678 /* Prefer units by overall suitability for general plan. */
2679 if (plantype == PLAN_EXPLORATORY) {
2680 /* Weight unit types by suitability for exploration around
2681 the edges of the known area. */
2682 sumfringe = totfringe = 0;
2683 for_all_terrain_types(t) {
2684 totfringe += pbt_fringe_terrain[t];
2685 if (!terrain_always_impassable(u2, t))
2686 sumfringe += pbt_fringe_terrain[t];
2687 }
2688 if (totfringe < 1)
2689 sumfringe = totfringe = 1;
2690 /* Scale - so 5% diffs in amt of crossable terrain
2691 don't affect result. */
2692 pbt_prefs[u2] = (20 * sumfringe) / totfringe;
2693 /* Prefer types that are quicker to build. */
2694 pbt_prefs[u2] /= max(1, est / 8);
2695 } else if (plantype == PLAN_IMPROVING) {
2696 /* Eliminate all mobile units. */
2697 if (mobile(u2))
2698 pbt_prefs[u2] = 0;
2699 } else {
2700 /* Weight unit type by effectiveness against known
2701 enemies. */
2702 for_all_unit_types(u3) {
2703 if (pbt_enemy_types[u3] > 0) {
2704 if (uu_zz_bhw(u2, u3) > 0) {
2705 pbt_prefs[u2] +=
2706 ((uu_zz_bhw(u2, u3) * 100) / bhw_max) *
2707 pbt_enemy_types[u3];
2708 }
2709 if (uu_zz_bcw(u2, u3) > 0) {
2710 pbt_prefs[u2] +=
2711 uu_zz_bcw(u2, u3) * pbt_enemy_types[u3];
2712 }
2713 }
2714 }
2715 /* Prefer types that are quicker to build. */
2716 pbt_prefs[u2] /= max(1, est / 8);
2717 }
2718 if (pbt_prefs[u2] < 1)
2719 pbt_prefs[u2] = 1;
2720 }
2721 }
2722 /* Check that mobile units can leave. */
2723 for_all_unit_types(u2) {
2724 if (pbt_prefs[u2] > 0
2725 && mobile(u2)
2726 /* We may want to build mobile defenders,
2727 even if they cannot leave. */
2728 && plantype != PLAN_DEFENSIVE) {
2729 /* First check that we can at all leave the unit. */
2730 if (type_can_leave_unit(u2, unit)) {
2731 /* Then check that any naval units that we plan to
2732 build have more than just the city pond to swim in. */
2733 if (u_air_mobile(u2)
2734 || u_ground_mobile(u2)
2735 || (u_naval_mobile(u2)
2736 && suitable_port(unit))) {
2737 found = TRUE;
2738 } else {
2739 pbt_prefs[u2] = 0;
2740 }
2741 } else {
2742 pbt_prefs[u2] = 0;
2743 }
2744 }
2745 }
2746 }
2747 DMprintf("%s preferred build type is ", unit_desig(unit));
2748 /* Look for an existing incomplete occupant and prefer to build its type,
2749 if it is in the choices in the typelist. */
2750 for_all_occupants(unit, occ) {
2751 if (in_play(occ) && !completed(occ)) {
2752 if (pbt_prefs[occ->type] > 0 && flip_coin()) {
2753 rslt = occ->type;
2754 DMprintf("%s (incomplete occupant)\n", u_type_name(rslt));
2755 return rslt;
2756 }
2757 }
2758 }
2759 for_all_unit_types(u2)
2760 if (pbt_prefs[u2] < 0)
2761 pbt_prefs[u2] = 0;
2762 rslt = select_by_weight(pbt_prefs, numutypes);
2763 if (!is_unit_type(rslt))
2764 rslt = NONUTYPE;
2765 if (DebugM) {
2766 if (is_unit_type(rslt)) {
2767 DMprintf("%s (choices were", u_type_name(rslt));
2768 for_all_unit_types(u2) {
2769 if (pbt_prefs[u2] > 0)
2770 DMprintf(" %s,%d", utype_name_n(u2, 1), pbt_prefs[u2]);
2771 }
2772 DMprintf(")");
2773 } else {
2774 DMprintf("nothing (no choices)");
2775 }
2776 DMprintf("\n");
2777 }
2778 return rslt;
2779 }
2780
2781 int
need_more_transportation(Side * side)2782 need_more_transportation(Side *side)
2783 {
2784 int u3, u2, anytransport;
2785 Theater *theater;
2786
2787 for_all_theaters(side, theater) {
2788 for_all_unit_types(u3) {
2789 if (theater->numtotransport[u3] > 0) {
2790 anytransport = FALSE;
2791 for_all_unit_types(u2) {
2792 if (theater->numassigned[u2] > 0
2793 && mobile(u2)
2794 && could_carry(u2, u3))
2795 anytransport = TRUE;
2796 }
2797 if (!anytransport)
2798 return TRUE;
2799 }
2800 }
2801 }
2802 return FALSE;
2803 }
2804
2805 int
need_explorers(Side * side)2806 need_explorers(Side *side)
2807 {
2808 int s, numcontacted = 0, numfound = 0;
2809
2810 if (side->see_all)
2811 return FALSE;
2812 if (g_terrain_seen())
2813 return FALSE;
2814 for (s = 1; s <= numsides; ++s) {
2815 if (s == side->id)
2816 continue;
2817 if (ai(side)->contacted[s])
2818 ++numcontacted;
2819 if (ai(side)->homefound[s])
2820 ++numfound;
2821 }
2822 if (numcontacted == 0) {
2823 /* If we've haven't found anybody, always explore. */
2824 return TRUE;
2825 } else if (numfound == 0) {
2826 /* If we've made contact but haven't found their home base,
2827 we still need to explore. */
2828 return TRUE;
2829 } else if (numfound < numsides - 1) {
2830 /* If we haven't found everybody's home base,
2831 we still need to explore. */
2832 return probability(max(100, 20 + (numfound * 100) / numsides));
2833 } else {
2834 /* If everybody has been found, then we likely have more
2835 pressing concerns; don't do as much exploration. */
2836 return probability(20);
2837 }
2838 }
2839
2840 #if 0
2841 /* Decide for the unit whether it should build a base to help other units. */
2842
2843 int
2844 build_base_for_others(side, unit)
2845 Side *side;
2846 Unit *unit;
2847 {
2848 int u = unit->type, u2, cando = FALSE;
2849
2850 for_all_unit_types(u2) {
2851 if (uu_acp_to_create(u, u2) > 0
2852 && (uu_creation_cp(u, u2) >= u_cp(u2)
2853 && side_can_build(side, u2)
2854 || uu_acp_to_build(u, u2) > 0)
2855 && u_is_base(u2)
2856 /* (should check if any advantage to building) */
2857 ) {
2858 cando = TRUE;
2859 break;
2860 }
2861 }
2862 if (cando) {
2863 DMprintf("%s building %s as a base for others\n",
2864 unit_desig(unit), u_type_name(u2));
2865 net_set_build_task(unit, u2, 1, 0, 0);
2866 return TRUE;
2867 }
2868 return FALSE;
2869 }
2870 #endif
2871
2872 int
build_depot_for_self(Unit * unit)2873 build_depot_for_self(Unit *unit)
2874 {
2875 int u = unit->type, u2, cando = FALSE;
2876
2877 for_all_unit_types(u2) {
2878 if (valid(can_construct(unit, unit, u2))) {
2879 cando = TRUE;
2880 break;
2881 }
2882 }
2883 if (cando) {
2884 DMprintf("%s building %s as a depot for itself\n",
2885 unit_desig(unit), u_type_name(u2));
2886 net_set_construct_task(unit, u2, 1, -1, unit->x, unit->y);
2887 return TRUE;
2888 }
2889 return FALSE;
2890 }
2891
2892 int
can_develop_on(int u,int u2)2893 can_develop_on(int u, int u2)
2894 {
2895 int acp_res = uu_acp_to_develop(u, u2);
2896
2897 if (acp_res < 1 || acp_res > type_max_acp(u))
2898 return 0;
2899
2900 return 1;
2901 }
2902
2903 /* code specific to the "time" game */
2904 int
needs_develop(Side * side,int u)2905 needs_develop (Side *side, int u)
2906 {
2907 int u2, i;
2908
2909 if (game_class != gc_time)
2910 return 0;
2911
2912 if (side->tech[u] >= u_tech_to_build(u) ||
2913 u_tech_max(u) > u_tech_to_build(u))
2914 return 0;
2915
2916 i = 0;
2917 for_all_unit_types(u2) {
2918 i += (could_create(u, u2) ? 1 : 0);
2919 }
2920 if (i < 2)
2921 return 0;
2922
2923 return 1;
2924 }
2925
2926 int
assign_to_develop_on(Side * side,Unit * unit,int u2)2927 assign_to_develop_on(Side *side, Unit *unit, int u2)
2928 {
2929 int lev = u_tech_to_build(u2);
2930
2931 if (!can_develop_on(unit->type, u2)) {
2932 DMprintf("%s cannot develop on %s!\n",
2933 unit_desig(unit), u_type_name(u2));
2934 return 0;
2935 }
2936
2937 DMprintf("%s will develop for %s on %s (to level %d)\n",
2938 unit_desig(unit), side_desig(side), u_type_name(u2), lev);
2939
2940 net_set_unit_plan_type(side, unit, PLAN_IMPROVING);
2941 net_push_develop_task(unit, u2, lev);
2942 return 1;
2943 }
2944
2945 /* (should account for impassability because of borders, etc) */
2946
2947 int
desired_direction_impassable(Unit * unit,int x,int y)2948 desired_direction_impassable(Unit *unit, int x, int y)
2949 {
2950 int dirs[NUMDIRS], numdirs, i, x1, y1, t, numbaddirs = 0;
2951
2952 numdirs = choose_move_dirs(unit, x, y, TRUE, NULL, NULL, dirs);
2953 for (i = 0; i < numdirs; ++i) {
2954 point_in_dir(unit->x, unit->y, dirs[i], &x1, &y1);
2955 t = terrain_at(x1, y1);
2956 if (terrain_always_impassable(unit->type, t))
2957 ++numbaddirs;
2958 }
2959 return (numbaddirs == numdirs);
2960 }
2961
2962 /* Return true if a given unit could reach a given location by being
2963 carried on a transport of some sort. */
2964
2965 int
could_be_ferried(Unit * unit,int x,int y)2966 could_be_ferried(Unit *unit, int x, int y)
2967 {
2968 int dirs[NUMDIRS], numdirs, i, x1, y1, t, u2;
2969
2970 if (!carryable(unit->type))
2971 return FALSE;
2972 numdirs = choose_move_dirs(unit, x, y, FALSE, NULL, NULL, dirs);
2973 for (i = 0; i < numdirs; ++i) {
2974 point_in_dir(unit->x, unit->y, dirs[i], &x1, &y1);
2975 t = terrain_at(x1, y1);
2976 /* See if there is a type that can carry us through via this
2977 direction. */
2978 for_all_unit_types(u2) {
2979 if (could_carry(u2, unit->type)
2980 && mobile(u2)
2981 && !terrain_always_impassable(u2, t)
2982 /* should also have "and this type is avail to us" */
2983 ) {
2984 return TRUE;
2985 }
2986 }
2987 }
2988 return FALSE;
2989 }
2990
2991 int
blocked_by_enemy(Unit * unit,int x,int y,int shortest)2992 blocked_by_enemy(Unit *unit, int x, int y, int shortest)
2993 {
2994 int dirs[NUMDIRS], numdirs, i, x1, y1, numbaddirs = 0;
2995 Unit *unit2;
2996
2997 numdirs = choose_move_dirs(unit, x, y, shortest, plausible_move_dir, NULL, dirs);
2998 /* No plausible dirs anyhow, so presence of enemy irrelevant. */
2999 if (numdirs == 0)
3000 return FALSE;
3001 for (i = 0; i < numdirs; ++i) {
3002 point_in_dir(unit->x, unit->y, dirs[i], &x1, &y1);
3003 unit2 = unit_at(x1, y1);
3004 if (in_play(unit2) && !trusted_side(unit->side, unit2->side))
3005 ++numbaddirs;
3006 }
3007 return (numbaddirs == numdirs);
3008 }
3009
3010 int
attack_blockage(Side * side,Unit * unit,int x,int y,int shortest)3011 attack_blockage(Side *side, Unit *unit, int x, int y, int shortest)
3012 {
3013 int dirs[NUMDIRS], numdirs, i, x1, y1;
3014 Unit *unit2;
3015
3016 numdirs = choose_move_dirs(unit, x, y, shortest, plausible_move_dir,
3017 NULL, dirs);
3018 for (i = 0; i < numdirs; ++i) {
3019 point_in_dir(unit->x, unit->y, dirs[i], &x1, &y1);
3020 unit2 = unit_at(x1, y1);
3021 if (in_play(unit2)
3022 && !trusted_side(unit->side, unit2->side)
3023 && uu_zz_bhw(unit->type, unit2->type) > 0
3024 ) {
3025 DMprintf("%s blocked, hitting enemy %s.", unit_desig(unit), unit_desig(unit2));
3026 net_push_hit_unit_task(unit, x1, y1, unit2->type, unit2->side->id);
3027 return TRUE;
3028 }
3029 }
3030 return FALSE;
3031 }
3032
3033 /* Detect an enemy unit in our own or an adjacent cell. */
3034
3035 int
enemy_close_by(Side * side,Unit * unit,int dist,int * xp,int * yp)3036 enemy_close_by(Side *side, Unit *unit, int dist, int *xp, int *yp)
3037 {
3038 int x = unit->x, y = unit->y, dir, x1, y1, victimcount = 0;
3039 extern int victim_x, victim_y, victim_rating;
3040
3041 victim_rating = -9999;
3042 tmpunit = unit;
3043 ai_victim_here(x, y, &victimcount);
3044 for_all_directions(dir) {
3045 if (point_in_dir(x, y, dir, &x1, &y1)) {
3046 ai_victim_here(x1, y1, &victimcount);
3047 }
3048 }
3049 if (victim_rating > -9999) {
3050 *xp = victim_x; *yp = victim_y;
3051 return TRUE;
3052 } else {
3053 return FALSE;
3054 }
3055 }
3056
3057 /* Note the recursion - should precalc this property. */
3058
3059 int
carryable(int u)3060 carryable(int u)
3061 {
3062 int u2;
3063
3064 for_all_unit_types(u2) {
3065 if (could_carry(u2, u) && mobile(u2))
3066 return TRUE;
3067 }
3068 return FALSE;
3069 }
3070
3071 static short *accelerables = NULL;
3072
3073 int
accelerable(int u)3074 accelerable(int u)
3075 {
3076 int u1, u2;
3077
3078 if (accelerables == NULL) {
3079 accelerables = (short *) xmalloc(numutypes * sizeof(int));
3080 for_all_unit_types(u1) {
3081 for_all_unit_types(u2) {
3082 if (accelerator(u1, u2)) {
3083 accelerables[u2] = TRUE;
3084 break;
3085 }
3086 }
3087 }
3088 }
3089 return accelerables[u];
3090 }
3091
3092 /* True if u1 is a type that can move u2 faster by transporting it. */
3093
3094 int
accelerator(int u1,int u2)3095 accelerator(int u1, int u2)
3096 {
3097 int t;
3098
3099 if (could_carry(u1, u2)
3100 && mobile(u1)) {
3101 if (type_max_acp(u1) * type_max_speed(u1) >
3102 type_max_acp(u2) * type_max_speed(u2)) {
3103 /* The transport must be able to move on any type of terrain
3104 accessible to the transportee. */
3105 for_all_terrain_types(t) {
3106 if (terrain_always_impassable(u1, t)
3107 && !terrain_always_impassable(u2, t)) {
3108 return FALSE;
3109 }
3110 }
3111 }
3112 return TRUE;
3113 }
3114 return FALSE;
3115 }
3116
3117 /* Init used by all machine players. Precompute useful information
3118 relating to unit types in general, and that usually gets referenced
3119 in inner loops. */
3120
3121 void
ai_init_shared()3122 ai_init_shared()
3123 {
3124 int u, u1, u2, t, m1, numbuilders, tmp;
3125 int worthmax;
3126 int cswtmp, cswmax, eswtmp, eswmax, oswtmp, oswmax, dswtmp, dswmax;
3127 Side *side = NULL;
3128
3129 /* Need 3 scratch layers for routefinding. */
3130 allocate_area_scratch(3);
3131 /* Recognize unit types that are bases */
3132 for_all_unit_types(u1) {
3133 set_u_is_base(u1, FALSE);
3134 tmp = FALSE;
3135 for_all_material_types(m1) {
3136 if (um_base_production(u1, m1) > 0) {
3137 tmp = TRUE;
3138 break;
3139 }
3140 }
3141 if (tmp) {
3142 for_all_unit_types(u2) {
3143 if ((u1 != u2) && could_carry(u1,u2)) {
3144 set_u_is_base(u1, TRUE);
3145 continue;
3146 }
3147 }
3148 }
3149 }
3150 /* Note that is_base_builder is set to the type of base that can */
3151 /* be built. That means that unit zero can not be a base which */
3152 /* can be built. */
3153 for_all_unit_types(u1) {
3154 set_u_is_transport(u1, FALSE);
3155 set_u_is_carrier(u1, FALSE);
3156 set_u_is_base_builder(u1, FALSE);
3157 set_u_can_make(u1, FALSE);
3158 set_u_can_capture(u1, FALSE);
3159 set_u_is_ground_mobile(u1, FALSE);
3160 set_u_is_naval_mobile(u1, FALSE);
3161 set_u_is_air_mobile(u1, FALSE);
3162 set_u_is_colonizer(u1, FALSE);
3163 set_u_is_facility(u1, FALSE);
3164 /* DON'T set u_advanced to FALSE. It is already set by the
3165 game file. */
3166 numbuilders = 0;
3167 for_all_unit_types(u2) {
3168 if (u_is_base(u2) &&
3169 could_create(u1, u2)) {
3170 set_u_is_base_builder(u1, TRUE);
3171 }
3172 if (type_max_speed(u1) > 0 && could_carry(u1, u2)) {
3173 set_u_is_transport(u1, TRUE);
3174 }
3175 if (could_create(u1,u2)) {
3176 set_u_can_make(u1, TRUE);
3177 /* A colonizer is a mobile builder of advanced units. */
3178 if (u_advanced(u2) && mobile(u1))
3179 set_u_is_colonizer(u1, TRUE);
3180 }
3181 if (uu_capture(u1, u2) > 0 || uu_indep_capture(u1, u2) > 0) {
3182 set_u_can_capture(u1, TRUE);
3183 }
3184 }
3185 }
3186 /* a carrier is a unit that is a mobile base, but that cannot
3187 move a passenger anywhere the passenger could not go itself. */
3188 for_all_unit_types(u1) {
3189 if (u_is_transport(u1)) {
3190 set_u_is_carrier(u1, TRUE);
3191 for_all_unit_types(u2) {
3192 if (could_carry(u1, u2)) {
3193 for_all_terrain_types(t) {
3194 if (could_be_on(u1, t) && !could_be_on(u2, t))
3195 set_u_is_carrier(u1, FALSE);
3196 }
3197 }
3198 }
3199 }
3200 }
3201 maybe_set_mover_worths();
3202 maybe_set_seer_worths();
3203 maybe_set_depot_worths();
3204 maybe_set_distributor_worths();
3205 maybe_set_producer_worths();
3206 maybe_set_prod_enhancer_worths();
3207 maybe_set_base_worths_for();
3208 maybe_set_base_worths();
3209 maybe_set_explorer_worths();
3210 for_all_unit_types(u) {
3211 set_u_bw(u, basic_worth(u));
3212 set_u_offensive_worth(u, offensive_worth(u));
3213 set_u_defensive_worth(u, defensive_worth(u));
3214 set_u_colonizer_worth(u, colonizing_worth(u));
3215 set_u_facility_worth(u, facility_worth(u));
3216 set_u_random_worth(u, random_worth(u));
3217 set_u_siege_worth(u, siege_worth(u));
3218 if (mobile(u)) {
3219 /* Assume this is an air unit by default. */
3220 set_u_is_air_mobile(u, TRUE);
3221 for_all_terrain_types(t) {
3222 /* We only care about real terrain here. */
3223 if (t_is_connection(t) || t_is_border(t) || t_is_coating(t)) {
3224 continue;
3225 }
3226 /* Check that our unit can have enough mps to move within
3227 the given terrain. */
3228 if (type_can_move_in_terrain(u, t)
3229 /* And that there is room for our unit in the terrain. */
3230 && type_can_occupy_terrain(u, t)
3231 /* And that it does not vanish or wreck in the terrain. */
3232 && type_survives_in_terrain(u, t)) {
3233 /* It is naval mobile if it can enter at least one
3234 liquid terrain. */
3235 if (t_liquid(t))
3236 set_u_is_naval_mobile(u, TRUE);
3237 /* It is ground mobile if it can enter at least one
3238 non-liquid terrain. */
3239 if (!t_liquid(t))
3240 set_u_is_ground_mobile(u, TRUE);
3241 /* Air units should have zero size in all terrains. */
3242 /* This is not always adhered to in the game modules. */
3243 /* if (ut_size(u, t) > 0)
3244 set_u_is_air_mobile(u, FALSE);
3245 */ } else {
3246 /* Air units should be able to enter all terrains. */
3247 set_u_is_air_mobile(u, FALSE);
3248 }
3249 }
3250 /* Kind of crude, but OK for now. */
3251 } else
3252 set_u_is_facility(u, TRUE);
3253 }
3254 /* Normalize the worth values on a -10k to +10k scale. */
3255 worthmax = 0;
3256 for_all_unit_types(u)
3257 worthmax = max(worthmax, u_bw(u));
3258 for_all_unit_types(u)
3259 set_u_bw(u, normalize_on_pmscale(u_bw(u), worthmax, 10000));
3260 worthmax = 0;
3261 for_all_unit_types(u)
3262 worthmax = max(worthmax, u_offensive_worth(u));
3263 for_all_unit_types(u)
3264 set_u_offensive_worth(u,
3265 normalize_on_pmscale(u_offensive_worth(u),
3266 worthmax, 10000));
3267 worthmax = 0;
3268 for_all_unit_types(u)
3269 worthmax = max(worthmax, u_defensive_worth(u));
3270 for_all_unit_types(u)
3271 set_u_defensive_worth(u,
3272 normalize_on_pmscale(u_defensive_worth(u),
3273 worthmax, 10000));
3274 worthmax = 0;
3275 for_all_unit_types(u)
3276 worthmax = max(worthmax, u_colonizer_worth(u));
3277 for_all_unit_types(u)
3278 set_u_colonizer_worth(u,
3279 normalize_on_pmscale(u_colonizer_worth(u),
3280 worthmax, 10000));
3281 worthmax = 0;
3282 for_all_unit_types(u)
3283 worthmax = max(worthmax, u_facility_worth(u));
3284 for_all_unit_types(u)
3285 set_u_facility_worth(u,
3286 normalize_on_pmscale(u_facility_worth(u),
3287 worthmax, 10000));
3288 worthmax = 0;
3289 for_all_unit_types(u)
3290 worthmax = max(worthmax, u_random_worth(u));
3291 for_all_unit_types(u)
3292 set_u_random_worth(u,
3293 normalize_on_pmscale(u_random_worth(u),
3294 worthmax, 10000));
3295 worthmax = 0;
3296 for_all_unit_types(u)
3297 worthmax = max(worthmax, u_siege_worth(u));
3298 for_all_unit_types(u)
3299 set_u_siege_worth(u,
3300 normalize_on_pmscale(u_siege_worth(u),
3301 worthmax, 10000));
3302 /* Colonization support worth. */
3303 cswmax = 0;
3304 for_all_unit_types(u) {
3305 cswtmp = 0;
3306 for_all_unit_types(u2) {
3307 if (!could_create(u, u2))
3308 continue;
3309 if (could_colonize(u2))
3310 cswtmp += max(0, u_colonizer_worth(u2));
3311 }
3312 cswmax = max(cswtmp, cswmax);
3313 tmp_u_array[u] = cswtmp;
3314 }
3315 for_all_unit_types(u)
3316 set_u_colonization_support_worth(u,
3317 normalize_on_pmscale(
3318 tmp_u_array[u], cswmax, 10000));
3319 // Base construction worth.
3320 cswmax = 0;
3321 for_all_unit_types(u) {
3322 cswtmp = 0;
3323 for_all_unit_types(u2) {
3324 if (!could_create(u, u2))
3325 continue;
3326 if (0 < u_ai_base_worth(u2))
3327 cswtmp += u_ai_base_worth(u2);
3328 }
3329 cswmax = max(cswtmp, cswmax);
3330 tmp_u_array[u] = cswtmp;
3331 }
3332 for_all_unit_types(u)
3333 set_u_base_construction_worth(u,
3334 normalize_on_pmscale(
3335 tmp_u_array[u], cswmax, 10000));
3336 /* Exploration support worth. */
3337 eswmax = 0;
3338 for_all_unit_types(u) {
3339 eswtmp = 0;
3340 for_all_unit_types(u2) {
3341 if (!could_create(u, u2))
3342 continue;
3343 if (could_explore(u2))
3344 eswtmp += max(0, u_ai_explorer_worth(u2));
3345 }
3346 eswmax = max(eswtmp, eswmax);
3347 tmp_u_array[u] = eswtmp;
3348 }
3349 for_all_unit_types(u)
3350 set_u_exploration_support_worth(u,
3351 normalize_on_pmscale(
3352 tmp_u_array[u], eswmax, 10000));
3353 /* Offensive support worth. */
3354 oswmax = 0;
3355 for_all_unit_types(u) {
3356 oswtmp = 0;
3357 for_all_unit_types(u2) {
3358 if (!could_create(u, u2))
3359 continue;
3360 if (could_damage_any(u2))
3361 oswtmp += max(0, u_offensive_worth(u2));
3362 if (could_capture_any(u2))
3363 oswtmp += max(0, u_siege_worth(u2));
3364 }
3365 oswmax = max(oswtmp, oswmax);
3366 tmp_u_array[u] = oswtmp;
3367 }
3368 for_all_unit_types(u)
3369 set_u_offensive_support_worth(u,
3370 normalize_on_pmscale(
3371 tmp_u_array[u], oswmax, 10000));
3372 /* Defensive support worth. */
3373 dswmax = 0;
3374 for_all_unit_types(u) {
3375 dswtmp = 0;
3376 for_all_unit_types(u2) {
3377 if (!could_create(u, u2))
3378 continue;
3379 if (could_defend_against_any(u2))
3380 dswtmp += max(0, u_defensive_worth(u2));
3381 }
3382 dswmax = max(dswtmp, dswmax);
3383 tmp_u_array[u] = dswtmp;
3384 }
3385 for_all_unit_types(u)
3386 set_u_defensive_support_worth(u,
3387 normalize_on_pmscale(
3388 tmp_u_array[u], dswmax, 10000));
3389 /* UU worths. */
3390 for_all_unit_types(u) {
3391 for_all_unit_types(u2) {
3392 set_uu_bhw(u, u2, basic_hit_worth(u, u2));
3393 set_uu_bfw(u, u2, basic_fire_worth(u, u2));
3394 set_uu_bcw(u, u2, basic_capture_worth(u, u2));
3395 set_uu_btw(u, u2, basic_transport_worth(u, u2));
3396 if (uu_zz_bhw(u, u2) > bhw_max)
3397 bhw_max = uu_zz_bhw(u, u2);
3398 }
3399 }
3400 /* Normalize basic attack worths. */
3401 worthmax = 0;
3402 for_all_unit_types(u) {
3403 for_all_unit_types(u2)
3404 worthmax = max(worthmax, uu_zz_bhw(u, u2));
3405 }
3406 for_all_unit_types(u) {
3407 for_all_unit_types(u2)
3408 set_uu_bhw(u, u2,
3409 normalize_on_pmscale(uu_zz_bhw(u, u2), worthmax, 10000));
3410 }
3411 /* Normalize basic fire worths. */
3412 worthmax = 0;
3413 for_all_unit_types(u) {
3414 for_all_unit_types(u2)
3415 worthmax = max(worthmax, uu_zz_bfw(u, u2));
3416 }
3417 for_all_unit_types(u) {
3418 for_all_unit_types(u2)
3419 set_uu_bfw(u, u2,
3420 normalize_on_pmscale(uu_zz_bfw(u, u2), worthmax, 10000));
3421 }
3422 /* Normalize basic capture worths. */
3423 worthmax = 0;
3424 for_all_unit_types(u) {
3425 for_all_unit_types(u2)
3426 worthmax = max(worthmax, uu_zz_bcw(u, u2));
3427 }
3428 for_all_unit_types(u) {
3429 for_all_unit_types(u2)
3430 set_uu_bcw(u, u2,
3431 normalize_on_pmscale(uu_zz_bcw(u, u2), worthmax, 10000));
3432 }
3433 /* Normalize basic transport worths. */
3434 worthmax = 0;
3435 for_all_unit_types(u) {
3436 for_all_unit_types(u2)
3437 worthmax = max(worthmax, uu_zz_btw(u, u2));
3438 }
3439 for_all_unit_types(u) {
3440 for_all_unit_types(u2)
3441 set_uu_btw(u, u2,
3442 normalize_on_pmscale(uu_zz_btw(u, u2), worthmax, 10000));
3443 }
3444 /* Tell how things rated. */
3445 if (DebugM)
3446 display_assessment();
3447 }
3448
3449 int basic_transport_worth(int u1, int u2);
3450 void set_uu_btw(int u1, int u2, int v);
3451
3452 static int average_damage(int damage, int defender);
3453
3454 /* This function takes damage (any type) as input converts it into
3455 an average damage in case it is a dice value. */
3456
3457 int
average_damage(int damage,int defender)3458 average_damage(int damage, int defender)
3459 {
3460 int avgdamage = 0;
3461
3462 avgdamage = dice_roll_mean(damage);
3463 if (avgdamage > u_hp(defender))
3464 avgdamage = u_hp(defender);
3465 return avgdamage;
3466 }
3467
3468 /* A crude estimate of the worth of having one type of unit. */
3469
3470 int
basic_worth(int u)3471 basic_worth(int u)
3472 {
3473 int worth = 0, u2, r, range;
3474
3475 worth += u_hp(u) * 10;
3476 for_all_unit_types(u2) {
3477 if (could_create(u, u2))
3478 worth += (u_bw(u2) * (50)) / 1 /* uu_make(u, u2) */;
3479 /* (should account for shared capacity) */
3480 if (could_carry(u, u2))
3481 worth += (1 + type_max_speed(u)) * uu_capacity_x(u, u2) *
3482 (u_is_base(u) ? 10 : 1) * u_bw(u2) / 30;
3483 }
3484 range = 12345;
3485 for_all_material_types(r) {
3486 worth += um_base_production(u, r) * (u_is_base(u) ? 4 : 1);
3487 if (um_consumption_per_move(u, r) > 0)
3488 range = min(range,
3489 um_storage_x(u, r) /
3490 max(1, um_consumption_per_move(u, r)));
3491 if (um_base_consumption(u, r) > 0)
3492 range =
3493 min(range,
3494 type_max_speed(u) * um_storage_x(u, r) /
3495 max(1, um_base_consumption(u, r)));
3496 }
3497 worth += type_max_speed(u) * u_hp(u);
3498 worth += (range == 12345 ? area.maxdim : range)
3499 * u_hp(u) / max(1, 10 - type_max_speed(u));
3500 for_all_unit_types(u2) {
3501 worth += (worth * uu_capture(u, u2)) / 150;
3502 }
3503 worth = isqrt(worth);
3504 DMprintf("unit type %s basic worth %d \n ", u_type_name(u), worth);
3505 if (worth < 0)
3506 init_warning("%s has negative basic worth", u_type_name(u));
3507 return worth;
3508 }
3509
3510 int
offensive_worth(int u)3511 offensive_worth(int u)
3512 {
3513 int totoffvalue = 0, offvalue = 0, defenders = 0, hit = 0, dmg = 0;
3514 int worth = 0;
3515 int u2 = NONUTYPE;
3516
3517 if (g_combat_model() == 0) {
3518 for_all_unit_types(u2) {
3519 if (uu_acp_to_attack(u, u2) > 0) {
3520 hit = uu_hit(u, u2);
3521 if (hit) {
3522 offvalue = (hit * average_damage(uu_damage(u, u2), u2));
3523 if (offvalue)
3524 ++defenders;
3525 totoffvalue += offvalue;
3526 }
3527 }
3528 if (u_acp_to_fire(u) > 0) {
3529 hit = fire_hit_chance(u, u2);
3530 if (hit) {
3531 offvalue = hit * average_damage(fire_damage(u, u2), u2);
3532 if (offvalue)
3533 ++defenders;
3534 totoffvalue += offvalue;
3535 }
3536 }
3537 if ((0 < u_acp_to_detonate(u)) || u_detonate_with_attack(u)) {
3538 offvalue = uu_detonation_damage_at(u, u2);
3539 if (0 < uu_detonation_range(u, u2))
3540 offvalue +=
3541 (radius_covers_n_cells(uu_detonation_range(u, u2) - 1) *
3542 (uu_detonation_damage_adj(u, u2) / 2));
3543 hit = 0;
3544 if (0 < u_acp_to_detonate(u))
3545 hit = 100;
3546 hit += min(100, u_detonate_with_attack(u));
3547 offvalue = (offvalue * hit) / 100;
3548 if (offvalue)
3549 ++defenders;
3550 totoffvalue += offvalue;
3551 }
3552 }
3553 if (defenders > 0)
3554 totoffvalue /= defenders;
3555 worth = type_max_acp(u) * totoffvalue * u_range(u) *
3556 type_max_speed(u) / 100;
3557 DMprintf("unit type %s offensive worth %d (combat model 0)\n ",
3558 u_type_name(u), worth);
3559 return worth;
3560 } else if (g_combat_model() == 1) {
3561 worth = type_max_acp(u) * u_attack(u) * u_range(u) *
3562 type_max_speed(u) / 100;
3563 DMprintf("unit type %s offensive worth %d (combat model 1)\n ",
3564 u_type_name(u), worth);
3565 if (worth < 0)
3566 init_warning("%s has negative offensive worth", u_type_name(u));
3567 return worth;
3568 } else return 1;
3569 }
3570
3571 int
defensive_worth(int u)3572 defensive_worth(int u)
3573 {
3574 int defvalue = 0;
3575 int attackers = 0;
3576 int worth = 0;
3577 int u2, hit, dmg;
3578
3579 if (g_combat_model() == 0) {
3580 for_all_unit_types(u2) {
3581 if (uu_acp_to_attack(u2, u) > 0) {
3582 ++attackers;
3583 defvalue += 100 * u_hp_max(u);
3584 defvalue -= uu_hit(u2, u) * average_damage(uu_damage(u2, u), u);
3585 }
3586 if (u_acp_to_fire(u2) > 0) {
3587 ++attackers;
3588 hit = fire_hit_chance(u2, u);
3589 dmg = average_damage(fire_damage(u2, u), u);
3590 defvalue += 100 * u_hp_max(u) - hit * dmg;
3591 }
3592 }
3593 if (attackers > 0)
3594 defvalue /= attackers;
3595 worth = type_max_acp(u) * defvalue / 10;
3596 DMprintf("unit type %s defensive worth %d (combat model 0)\n ", u_type_name(u), worth);
3597 return worth;
3598 /* Much simpler to calculate things in combat model 1 since attack and defense strengths are
3599 absolute numbers. */
3600 } else if (g_combat_model() == 1) {
3601 worth = type_max_acp(u) * u_defend(u);
3602 DMprintf("unit type %s defensive worth %d (combat model 1)\n ", u_type_name(u), worth);
3603 if (worth < 0)
3604 init_warning("%s has negative defensive worth", u_type_name(u));
3605 return worth;
3606 } else return 1;
3607 }
3608
3609 #if (0)
3610
3611 int
exploring_worth(int u)3612 exploring_worth(int u)
3613 {
3614
3615 /* It should also be considered what kind of terrain the unit can
3616 move on, and how common that terrain is. */
3617 /* if ( g_synth_methods == what? */
3618 for_all_terrain_types(t) {
3619 if ( ( ! ut_vanishes_on(u, t) ) && ( ! ut_wrecks_on(u, t) ) ) {
3620 /* Can explore this terrain without dying! */
3621 mobility += ( ( t_alt_max(t) - t_alt_min(t) )
3622 * ( t_wet_max(t) - t_wet_min(t) ) )
3623 / ( ut_mp_to_enter(u, t) + 1);
3624 }
3625 }
3626 }
3627
3628 #endif
3629
3630 int
colonizing_worth(int u)3631 colonizing_worth(int u)
3632 {
3633 int colvalue = 0;
3634 int worth = 0;
3635 int u2;
3636
3637 /* A colonizer is a mobile builder of advanced units. */
3638 if (!mobile(u))
3639 return 0;
3640 for_all_unit_types(u2) {
3641 if (could_create(u, u2)
3642 && (u_advanced(u2) || could_create(u2, u))) {
3643 /* It is more valuable if it can build bigger cities. */
3644 colvalue += u_reach(u2) + 1;
3645 }
3646 }
3647 worth = type_max_acp(u) * type_max_speed(u) * colvalue / 10;
3648 DMprintf("unit type %s colonizer worth %d \n ", u_type_name(u), worth);
3649 if (worth < 0)
3650 init_warning("%s has negative colonizer worth", u_type_name(u));
3651 return worth;
3652 }
3653
3654 int
facility_worth(int u)3655 facility_worth(int u)
3656 {
3657 int worth = 0;
3658
3659 /* Kind of crude, but OK for now. */
3660 if (!mobile(u))
3661 worth = 1;
3662
3663 DMprintf("unit type %s facility worth %d \n ", u_type_name(u), worth);
3664 if (worth < 0)
3665 init_warning("%s has negative facility worth", u_type_name(u));
3666 return worth;
3667 }
3668
3669 int
siege_worth(int u)3670 siege_worth(int u)
3671 {
3672 int siegevalue = 0;
3673 int worth = 0;
3674 int u2;
3675
3676 for_all_unit_types(u2) {
3677 siegevalue += uu_capture(u, u2);
3678 }
3679 siegevalue = siegevalue / numutypes;
3680
3681 worth = type_max_acp(u) * u_range(u) * siegevalue;
3682
3683 DMprintf("unit type %s siege worth %d \n ", u_type_name(u), worth);
3684 if (worth < 0)
3685 init_warning("%s has negative siege worth", u_type_name(u));
3686 return worth;
3687 }
3688
3689 /* Assign the same worth to all unit types. */
3690
3691 int
random_worth(int u)3692 random_worth(int u)
3693 {
3694 return 1;
3695 }
3696
3697 /* A basic estimate of the payoff of one unit type attacking another
3698 type directly. This is "context-free", does not account for
3699 overall goals etc. */
3700
3701 int
basic_hit_worth(int u,int e)3702 basic_hit_worth(int u, int e)
3703 {
3704 int avgdamage, worth = 0, anti = 0, acp = 0, attacks = 0;
3705
3706 if (could_attack(u, e)) {
3707 if (!u_acp_independent(u))
3708 attacks = (u_acp(u) + u_free_acp(u)) / uu_acp_to_attack(u, e);
3709 else
3710 attacks = 1;
3711 avgdamage = average_damage(uu_damage(u, e), e);
3712 worth = (uu_hit(u, e) * avgdamage * attacks) / u_hp(e);
3713 }
3714 if (could_counterattack(e, u)) {
3715 if (!u_acp_independent(e))
3716 attacks = (u_acp(e) + u_free_acp(e)) / uu_acp_to_attack(e, u);
3717 else
3718 attacks = 1;
3719 avgdamage = average_damage(uu_damage(e, u), u);
3720 anti = (uu_hit(e, u) * uu_counterattack(u, e)) / 100;
3721 anti = (anti * avgdamage * attacks) / u_hp(u);
3722 }
3723 worth -= anti;
3724 return worth;
3725 }
3726
3727 int
basic_fire_worth(int u,int e)3728 basic_fire_worth(int u, int e)
3729 {
3730 int avgdamage, worth = 0, firings = 0;
3731
3732 if (could_fire_at(u, e)) {
3733 if (!u_acp_independent(u))
3734 firings = (u_acp(u) + u_free_acp(u)) / u_acp_to_fire(u);
3735 else
3736 firings = 1;
3737 avgdamage = average_damage(fire_damage(u, e), e);
3738 worth = (fire_hit_chance(u, e) * avgdamage * firings) / u_hp(e);
3739 }
3740 return worth;
3741 }
3742
3743 /* A crude estimate of the payoff of one unit type trying to capture. */
3744
3745 int
basic_capture_worth(int u,int e)3746 basic_capture_worth(int u, int e)
3747 {
3748 int acp, worth1 = 0, worth2 = 0, worth = 0;
3749
3750 acp = max(uu_acp_to_capture(u, e), uu_acp_to_attack(u, e));
3751 if (acp < 1)
3752 return -9999;
3753 if (uu_capture(u, e) > 0) {
3754 worth1 = (uu_capture(u, e) * type_max_acp(u)) / acp;
3755 }
3756 if (uu_indep_capture(u, e) > 0) {
3757 worth2 = (uu_indep_capture(u, e) * type_max_acp(u)) / acp;
3758 }
3759 /* (should account for chance of dying in attempt) */
3760 worth = max(worth1, worth2);
3761 return worth;
3762 }
3763
3764 int
basic_transport_worth(int u,int u2)3765 basic_transport_worth(int u, int u2)
3766 {
3767 int worth = 0;
3768
3769 if (could_carry(u, u2)) {
3770 worth += 1;
3771 }
3772 return worth;
3773 }
3774
3775 /* Display the results of our calculations. */
3776
3777 void
display_assessment(void)3778 display_assessment(void)
3779 {
3780 int u, u2;
3781
3782 DMprintf("\nUnit Attributes:\n");
3783 for_all_unit_types(u) {
3784 DMprintf(" %-3.3s : base %d, transport %d, carrier %d, worth %d\n",
3785 shortest_unique_name(u), u_is_base(u),
3786 u_is_transport(u), u_is_carrier(u), u_bw(u));
3787 DMprintf(" Operate between ranges %d and %d\n",
3788 operating_range_worst(u), operating_range_best(u));
3789 }
3790 DMprintf("\nUnit vs Unit Combat:\n");
3791 for_all_unit_types(u) {
3792 DMprintf(" %-3.3s:", shortest_unique_name(u));
3793 for_all_unit_types(u2)
3794 DMprintf("%5d", uu_zz_bhw(u, u2));
3795 DMprintf("\n");
3796 }
3797 DMprintf("\nUnit vs Unit Fire:\n");
3798 for_all_unit_types(u) {
3799 DMprintf(" %-3.3s:", shortest_unique_name(u));
3800 for_all_unit_types(u2)
3801 DMprintf("%5d", uu_zz_bfw(u, u2));
3802 DMprintf("\n");
3803 }
3804 DMprintf("\nUnit vs Unit Capture:\n");
3805 for_all_unit_types(u) {
3806 DMprintf(" %-3.3s:", shortest_unique_name(u));
3807 for_all_unit_types(u2)
3808 DMprintf(" %4d", uu_zz_bcw(u, u2));
3809 DMprintf("\n");
3810 }
3811 DMprintf("\nUnit vs Unit Transport:\n");
3812 for_all_unit_types(u) {
3813 DMprintf(" %-3.3s:", shortest_unique_name(u));
3814 for_all_unit_types(u2)
3815 DMprintf(" %4d", uu_zz_btw(u, u2));
3816 DMprintf("\n");
3817 }
3818 DMprintf("\n");
3819 }
3820
3821 int
is_base_for(int u1,int u2)3822 is_base_for(int u1, int u2)
3823 {
3824 return (type_max_speed(u1) == 0
3825 && (uu_capacity_x(u2, u1) > 0
3826 || (uu_size(u2, u1) <= u_capacity(u1))));
3827 }
3828
3829 int
is_carrier_for(int u1,int u2)3830 is_carrier_for(int u1, int u2)
3831 {
3832 return (type_max_speed(u1) > 0
3833 && (uu_capacity_x(u2, u1) > 0
3834 || (uu_size(u2, u1) <= u_capacity(u1))));
3835 }
3836
3837 /* Since *.def parameters don't have setters usually, we have to supply
3838 some here. These are very sensitive to how the parameters are organized,
3839 and they don't do any checking, so you have to careful about using them. */
3840
set_u_is_base(int u,int n)3841 void set_u_is_base(int u, int n) { utypes[u].is_base = n; }
set_u_is_transport(int u,int n)3842 void set_u_is_transport(int u, int n) { utypes[u].is_transport = n; }
set_u_is_carrier(int u,int n)3843 void set_u_is_carrier(int u, int n) { utypes[u].is_carrier = n; }
set_u_is_base_builder(int u,int n)3844 void set_u_is_base_builder(int u, int n) { utypes[u].is_base_builder = n; }
set_u_can_make(int u,int n)3845 void set_u_can_make(int u, int n) { utypes[u].can_make = n; }
set_u_can_capture(int u,int n)3846 void set_u_can_capture(int u, int n) { utypes[u].can_capture = n; }
set_u_bw(int u,int n)3847 void set_u_bw(int u, int n) { utypes[u].bw = n; }
3848
set_u_offensive_worth(int u,int n)3849 void set_u_offensive_worth(int u, int n) { utypes[u].ow = n; }
set_u_defensive_worth(int u,int n)3850 void set_u_defensive_worth(int u, int n) { utypes[u].dw = n; }
set_u_colonizer_worth(int u,int n)3851 void set_u_colonizer_worth(int u, int n) { utypes[u].cw = n; }
set_u_facility_worth(int u,int n)3852 void set_u_facility_worth(int u, int n) { utypes[u].fw = n; }
set_u_random_worth(int u,int n)3853 void set_u_random_worth(int u, int n) { utypes[u].rw = n; }
set_u_siege_worth(int u,int n)3854 void set_u_siege_worth(int u, int n) { utypes[u].sw = n; }
set_u_colonization_support_worth(int u,int n)3855 void set_u_colonization_support_worth(int u, int n) { utypes[u].csw = n; }
set_u_base_construction_worth(int u,int n)3856 void set_u_base_construction_worth(int u, int n) { utypes[u].bcow = n; }
set_u_exploration_support_worth(int u,int n)3857 void set_u_exploration_support_worth(int u, int n) { utypes[u].esw = n; }
set_u_offensive_support_worth(int u,int n)3858 void set_u_offensive_support_worth(int u, int n) { utypes[u].osw = n; }
set_u_defensive_support_worth(int u,int n)3859 void set_u_defensive_support_worth(int u, int n) { utypes[u].dsw = n; }
3860
set_u_is_ground_mobile(int u,int n)3861 void set_u_is_ground_mobile(int u, int n) { utypes[u].is_ground_mobile = n; }
set_u_is_naval_mobile(int u,int n)3862 void set_u_is_naval_mobile(int u, int n) { utypes[u].is_naval_mobile = n; }
set_u_is_air_mobile(int u,int n)3863 void set_u_is_air_mobile(int u, int n) { utypes[u].is_air_mobile = n; }
set_u_is_advanced(int u,int n)3864 void set_u_is_advanced(int u, int n) { utypes[u].is_advanced = n; }
set_u_is_colonizer(int u,int n)3865 void set_u_is_colonizer(int u, int n) { utypes[u].is_colonizer = n; }
set_u_is_facility(int u,int n)3866 void set_u_is_facility(int u, int n) { utypes[u].is_facility = n; }
3867
3868 int bhwtab = -1;
3869 int bfwtab = -1;
3870 int bcwtab = -1;
3871 int btwtab = -1;
3872
3873 void
set_uu_bhw(int u1,int u2,int v)3874 set_uu_bhw(int u1, int u2, int v)
3875 {
3876 if (bhwtab < 0) {
3877 for (bhwtab = 0; tabledefns[bhwtab].name != NULL; ++bhwtab) {
3878 if (strcmp("zz-basic-hit-worth", tabledefns[bhwtab].name) == 0) {
3879 allocate_table(bhwtab, FALSE);
3880 break;
3881 }
3882 }
3883 }
3884 if (tabledefns[bhwtab].table == NULL)
3885 run_error("no bhw table allocated");
3886 (*(tabledefns[bhwtab].table))[numutypes * u1 + u2] = v;
3887 }
3888
3889 void
set_uu_bfw(int u1,int u2,int v)3890 set_uu_bfw(int u1, int u2, int v)
3891 {
3892 if (bfwtab < 0) {
3893 for (bfwtab = 0; tabledefns[bfwtab].name != NULL; ++bfwtab) {
3894 if (strcmp("zz-basic-fire-worth", tabledefns[bfwtab].name) == 0) {
3895 allocate_table(bfwtab, FALSE);
3896 break;
3897 }
3898 }
3899 }
3900 if (tabledefns[bfwtab].table == NULL)
3901 run_error("no bfw table allocated");
3902 (*(tabledefns[bfwtab].table))[numutypes * u1 + u2] = v;
3903 }
3904
3905 void
set_uu_bcw(int u1,int u2,int v)3906 set_uu_bcw(int u1, int u2, int v)
3907 {
3908 if (bcwtab < 0) {
3909 for (bcwtab = 0; tabledefns[bcwtab].name != NULL; ++bcwtab) {
3910 if (strcmp("zz-basic-capture-worth", tabledefns[bcwtab].name) == 0) {
3911 allocate_table(bcwtab, FALSE);
3912 break;
3913 }
3914 }
3915 }
3916 if (tabledefns[bcwtab].table == NULL)
3917 run_error("no bcw table allocated");
3918 (*(tabledefns[bcwtab].table))[numutypes * u1 + u2] = v;
3919 }
3920
3921
3922 void
set_uu_btw(int u1,int u2,int v)3923 set_uu_btw(int u1, int u2, int v)
3924 {
3925 if (btwtab < 0) {
3926 for (btwtab = 0; tabledefns[btwtab].name != NULL; ++btwtab) {
3927 if (strcmp("zz-basic-transport-worth", tabledefns[btwtab].name) == 0) {
3928 allocate_table(btwtab, FALSE);
3929 break;
3930 }
3931 }
3932 }
3933 if (tabledefns[btwtab].table == NULL)
3934 run_error("no btw table allocated");
3935 (*(tabledefns[btwtab].table))[numutypes * u1 + u2] = v;
3936 }
3937
3938
3939