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