1 /* Unit task execution and general task functions.
2    Copyright (C) 1992-2000 Stanley T. Shebs.
3    Copyright (C) 2004-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 #include "conq.h"
11 #include "kernel.h"
12 
13 /* (The following inclusion is only temporary if we end up proceeding
14     with the extraction of all AI code from this file.) */
15 #include "aiutil.h"
16 
17 #include "aiunit.h"
18 #include "aiunit2.h"
19 
20 /* This is the number of tasks to allocate initially.  More will always be
21    allocated as needed, so this should be a "reasonable" value. */
22 
23 #ifndef INITMAXTASKS
24 #define INITMAXTASKS 100
25 #endif
26 
27 enum choicestate {
28     eitherway,
29     leftthenright,
30     rightthenleft,
31     leftonly,
32     rightonly
33 };
34 
35 static int compare_directions(const void *a0, const void *a1);
36 static int test_for_buildable(int x, int y);
37 static int collect_test(int x, int y);
38 static int extractable_test(int x, int y);
39 static TaskOutcome execute_task_aux(Unit *unit, Task *task);
40 
41 //! Perform a toolup subtask on behalf of a construct/build task.
42 static TaskOutcome do_toolup_subtask(Unit *constructor, int uc);
43 
44 static TaskOutcome do_approach_subtask(Unit *unit, Task *task, int tx, int ty, int *statep);
45 static void allocate_task_block(void);
46 #if (0)
47 static Unit *repair_here(int x, int y);
48 #endif
49 static Unit *resupply_here(int x, int y);
50 
51 
52 /* Declare all the task functions. */
53 
54 #undef  DEF_TASK
55 #define DEF_TASK(name,dname,code,argtypes,DOFN,createfn,setfn,netsetfn,pushfn,netpushfn,argdecl)  \
56   static TaskOutcome DOFN(Unit *unit, Task *task);
57 
58 #include "task.def"
59 
60 /* Array of descriptions of task types. */
61 
62 TaskDefn taskdefns[] = {
63 
64 #undef  DEF_TASK
65 #define DEF_TASK(NAME,DNAME,code,ARGTYPES,DOFN,createfn,setfn,netsetfn,pushfn,netpushfn,argdecl)  \
66   { NAME, DNAME, ARGTYPES, DOFN },
67 
68 #include "task.def"
69 
70     { NULL, NULL, NULL }
71 };
72 
73 /* The list of available task objects. */
74 
75 Task *freetasks;
76 
77 /* Pointer to a buffer that task debug info goes into. */
78 
79 char *taskbuf;
80 
81 static int tmpbuildutype;
82 
83 static Unit *tmpbuilder, *tmpbuildunit;
84 
85 /* Used by the resupply code. */
86 
87 int *lowm = NULL;
88 
89 int numlow = 0;
90 
91 static int tmpx, tmpy;
92 
93 static int *foundm;
94 
95 /* Allocate an initial collection of task objects. */
96 
97 void
init_tasks(void)98 init_tasks(void)
99 {
100     allocate_task_block();
101 }
102 
103 /* Allocate a new block of tasks. */
104 
105 void
allocate_task_block(void)106 allocate_task_block(void)
107 {
108     int i;
109 
110     freetasks = (Task *) xmalloc(INITMAXTASKS * sizeof(Task));
111     /* Chain the tasks together. */
112     for (i = 0; i < INITMAXTASKS; ++i) {
113 	freetasks[i].next = &freetasks[i+1];
114     }
115     freetasks[INITMAXTASKS-1].next = NULL;
116 }
117 
118 /* Create and return a new task. */
119 
120 Task *
create_task(TaskType type)121 create_task(TaskType type)
122 {
123     int i;
124     Task *task;
125 
126     /* Scarf up some more memory if we need it. */
127     if (freetasks == NULL) {
128 	allocate_task_block();
129     }
130     /* Peel off a task from the free list. */
131     task = freetasks;
132     freetasks = task->next;
133     /* Reset its slots. */
134     task->type = type;
135     task->execnum = 0;
136     task->retrynum = 0;
137     for (i = 0; i < MAXTASKARGS; ++i)
138       task->args[i] = 0;
139     task->next = NULL;
140     return task;
141 }
142 
143 /* Make a copy of the given task. */
144 
145 Task *
clone_task(Task * oldtask)146 clone_task(Task *oldtask)
147 {
148     int i;
149     Task *newtask;
150 
151     newtask = create_task(oldtask->type);
152     /* Probably not a good idea to copy exec/retry counts, skip them. */
153     for (i = 0; i < MAXTASKARGS; ++i)
154       newtask->args[i] = oldtask->args[i];
155     return newtask;
156 }
157 
158 /* The empty task always succeeds immediately. */
159 
160 static TaskOutcome
do_none_task(Unit * unit,Task * task)161 do_none_task(Unit *unit, Task *task)
162 {
163     return TASK_IS_COMPLETE;
164 }
165 
166 static int
test_for_buildable(int x,int y)167 test_for_buildable(int x, int y)
168 {
169     Unit *unit;
170 
171     for_all_stack(x, y, unit) {
172 	if (in_play(unit)
173 	    && !fullsized(unit)
174 	    && unit->type == tmpbuildutype
175 	    && unit->side == tmpbuilder->side) {
176 	    tmpbuildunit = unit;
177 	    return TRUE;
178 	}
179     }
180     return FALSE;
181 }
182 
183 /* The build task handles the development, tooling up, creation, and
184    completion for a given number of units of a given type. */
185 
186 static TaskOutcome
do_build_task(Unit * builder,Task * task)187 do_build_task(Unit *builder, Task *task)
188 {
189     int rslt = A_ANY_OK;
190     int idc = -1;
191     int uc = NONUTYPE;
192     Unit *buildee = NULL;
193     Side *side = NULL;
194 
195     assert_error(is_active(builder),
196 		 "AI: Attempted to build with an inactive unit");
197     assert_warning_return(task, "AI: Attempted to run invalid construct task",
198                           TASK_IS_COMPLETE);
199     side = builder->side;
200     // Attempt to retrieve buildee unit from ID.
201     idc = task->args[0];
202     buildee = find_unit(idc);
203     if (!in_play(buildee))
204 	return TASK_FAILED;
205     if (fullsized(buildee))
206 	return TASK_IS_COMPLETE;
207     uc = buildee->type;
208     builder->creation_id = -1;
209     // If research or development is needed, then we should not be in this code.
210     if (!side_can_build(side, uc))
211         return TASK_FAILED;
212     // We must handle tooling, if necessary.
213     if (!has_enough_tooling(builder, uc))
214 	return do_toolup_subtask(builder, uc);
215     // Try performing build action.
216     if (valid(rslt = can_build(builder, builder, buildee))) {
217 	prep_build_action(builder, builder, buildee);
218 	return TASK_PREPPED_ACTION;
219     }
220     // Wait for more materials or ACP, if necessary.
221     // TODO: Proactively accumulate materials, if possible.
222     if ((A_ANY_NO_MATERIAL == rslt) || (A_ANY_NO_ACP == rslt)) {
223         set_unit_reserve(builder->side, builder, TRUE, FALSE);
224         return TASK_IS_INCOMPLETE;
225     }
226     return TASK_FAILED;
227 #if (0) // HACKING NOTE: Old devel logic. Keep around for now.
228     /* See if our technology needs improvement in order to build this
229        type. */
230     if (is_unit_type(u2)
231 	&& u_tech_to_build(u2) > 0
232 	&& us->tech[u2] < u_tech_to_build(u2)) {
233         if (uu_acp_to_develop(u, u2) > 0) {
234 	    push_develop_task(unit, u2, u_tech_to_build(u2));
235 	    return TASK_IS_INCOMPLETE;
236         } else {
237 	    /* Can't do the necessary development. */
238 	    /* (should filter out when asking to build?) */
239 	    notify(unit->side,
240 		   "You need tech of %d to build %s, but are only at %d.",
241 		   u_tech_to_build(u2), u_type_name(u2), us->tech[u2]);
242 	    notify(unit->side,
243 		   "%s cannot develop %s, so build task failed.",
244 		   unit_handle(unit->side, unit), u_type_name(u2));
245 	    return TASK_FAILED;
246         }
247     }
248 #endif
249 }
250 
251 Unit *
find_unit_to_complete(Unit * unit,Task * task)252 find_unit_to_complete(Unit *unit, Task *task)
253 {
254     Unit *occ;
255     int u = unit->type, nx, ny, range;
256     int u2 = task->args[0];
257     int x = unit->x, y = unit->y;
258 
259     /* Check out the unit supposedly in progress. */
260     if (task->args[1] != 0) {
261 	occ = find_unit(task->args[1]);
262 	if (in_play(occ) && occ->type == u2 && !fullsized(occ))
263 	  return occ;
264     }
265     /* Maybe search for any appropriate incomplete occupants. */
266     for_all_occupants(unit, occ) {
267 	if (in_play(occ)
268 	    && !fullsized(occ)
269 	    && occ->type == u2
270 	    && occ->side == unit->side)
271 	  return occ;
272     }
273     /* Or else search for any appropriate incomplete units in this cell. */
274     for_all_stack(x, y, occ) {
275 	if (in_play(occ)
276 	    && !fullsized(occ)
277 	    && occ->type == u2
278 	    && occ->side == unit->side) {
279 	    return occ;
280     	}
281     }
282     /* Or else search nearby area. */
283     if (is_unit_type(u2)) {
284 	range = uu_build_range(u, u2);
285 	if (range > 0) {
286 	    tmpbuilder = unit;
287 	    tmpbuildutype = u2;
288 	    if (search_around(x, y, range, test_for_buildable, &nx, &ny, 1)) {
289 	    	return tmpbuildunit;
290 	    }
291 	}
292     }
293     /* nothing found */
294     return NULL;
295 }
296 
297 /* This is a "pure development" task, with the sole objective of
298    increasing technology. */
299 
300 static TaskOutcome
do_develop_task(Unit * unit,Task * task)301 do_develop_task(Unit *unit, Task *task)
302 {
303     int u = unit->type;
304     int u2 = task->args[0], lev = task->args[1];
305     Side *us = unit->side;
306 
307     /* Independents can never ever do development. */
308     if (us == NULL)
309       return TASK_FAILED;
310     if (us->tech[u2] > u_tech_max(u2))
311       run_error("s%d tech for u%d is %d", side_number(us), u2, us->tech[u2]);
312     if (us->tech[u2] >= lev)
313       return TASK_IS_COMPLETE;
314     if (uu_acp_to_develop(u, u2) <= 0)
315       return TASK_FAILED;
316     if (valid(check_develop_action(unit, unit, u2))) {
317 	prep_develop_action(unit, unit, u2);
318 	return TASK_PREPPED_ACTION;
319     } else {
320 	/* We get three tries to develop before giving up. */
321 	return (task->execnum < 3 ? TASK_IS_INCOMPLETE : TASK_FAILED);
322     }
323 }
324 
325 /* This is to capture a given type/side of unit at a given place. */
326 
327 static TaskOutcome
do_capture_task(Unit * unit,Task * task)328 do_capture_task(Unit *unit, Task *task)
329 {
330     int u = unit->type, tx, ty, tu2, ts2, dist;
331     Unit *unit2;
332     Side *us = unit->side;
333 
334     /* (should be able to say how hard to try) */
335     tx = task->args[0];  ty = task->args[1];
336     tu2 = task->args[2];
337     ts2 = task->args[3];
338     dist = distance(tx, ty, unit->x, unit->y);
339     switch (dist) {
340       case 0:
341       case 1:
342 	for_all_stack(tx, ty, unit2) {
343 	    if ((ts2 >= 0 ?
344 		 (unit2->side->id == ts2) :
345 		 enemy_side(us, unit2->side))
346 		&& (tu2 == NONUTYPE || tu2 == unit2->type)) {
347 		if (valid(check_capture_action(unit, unit, unit2))) {
348 		    prep_capture_action(unit, unit, unit2);
349 		    return TASK_PREPPED_ACTION;
350 		} else if (valid(check_attack_action(unit, unit, unit2, 100))) {
351 		    prep_attack_action(unit, unit, unit2, 100);
352 		    return TASK_PREPPED_ACTION;
353 		} else {
354 		    /* We get several tries to capture before giving up. */
355 		    set_unit_reserve(unit->side, unit, TRUE, FALSE);
356 		    return (task->execnum < 5 ? TASK_IS_INCOMPLETE : TASK_FAILED);
357 		}
358 	    }
359 	}
360 	/* Nothing was here to capture. */
361 	return TASK_IS_COMPLETE;
362       default:
363 	/* If on mobile transport, let it handle things. */
364 	if (unit->transport != NULL
365 	    && mobile(unit->transport->type)
366 	    /* and the transport is not blocked */
367 	    && flip_coin()) {
368 	    return TASK_IS_INCOMPLETE;
369 	}
370 	/* If out of range and can move, push a task to get closer
371            (usually). */
372 	if (mobile(u) && probability(90)) {
373 	    push_move_to_task(unit, tx, ty, 1);
374 	    return TASK_IS_INCOMPLETE;
375 	}
376 	return TASK_FAILED;
377     }
378 }
379 
380 /* The disband task's purpose is to make the unit disappear, so just
381    keep doing actions; when the unit goes away, so will the task. */
382 
383 static TaskOutcome
do_disband_task(Unit * unit,Task * task)384 do_disband_task(Unit *unit, Task *task)
385 {
386     if (valid(check_disband_action(unit, unit))) {
387 	prep_disband_action(unit, unit);
388 	return TASK_PREPPED_ACTION;
389     } else {
390 	/* (should try to find a nearby unit to do it?) */
391 	return (task->execnum < 5 ? TASK_IS_INCOMPLETE : TASK_FAILED);
392     }
393 }
394 
395 static TaskOutcome
do_hit_position_task(Unit * unit,Task * task)396 do_hit_position_task(Unit *unit, Task *task)
397 {
398     int u = unit->type, tx, ty, dist;
399     UnitView *uview = NULL;
400 
401     /* (Temporary hack. Ask the planner to re-evaluate continuation of
402        this task. If it wants to, then it will issue a new one. If not,
403        then move on and do something more productive.) */
404     /* (A better solution would be to add a new arg to the task that would
405        tell it the number of times to attempt execution before returning to
406        the planner for guidance.) */
407     if (task->execnum > 3)
408       return TASK_IS_COMPLETE;
409     /* This is to hit a given place. */
410     /* (ask for a number of hits?) */
411     tx = task->args[0];  ty = task->args[1];
412     dist = distance(tx, ty, unit->x, unit->y);
413     /* Make sure that we are not going to hit a friendly unit. */
414     /* (What if we have unit with vision-range -1 in cell and they aren't
415        seen by any of our own units?) */
416     for_all_view_stack_with_occs(unit->side, tx, ty, uview) {
417         if (!enemy_side(unit->side, side_n(uview->siden)))
418           return TASK_FAILED;
419     }
420     /* Try performing a fire-into action. */
421     if (valid(check_fire_into_action(unit, unit, tx, ty, 0, -1))) {
422 	prep_fire_into_action(unit, unit, tx, ty, 0, -1);
423 	return TASK_PREPPED_ACTION;
424     } else if (mobile(u) && flip_coin()) {
425 	/* We're too far away to shoot directly, add a move-to task. */
426 	push_move_to_task(unit, tx, ty, max(1 /* attack range */, u_range(u)));
427 	return TASK_IS_INCOMPLETE;
428     }
429     return TASK_FAILED;
430 }
431 
432 static TaskOutcome
do_hit_unit_task(Unit * unit,Task * task)433 do_hit_unit_task(Unit *unit, Task *task)
434 {
435     int u = unit->type, tx, ty, dist, movedist, tu, ts;
436     Unit *unit2;
437     UnitView *uview;
438     Side *us = unit->side;
439 
440     /* Temporary hack. Ask the planner to re-evaluate continuation of
441        this task. If it wants to, then it will issue a new one. If not,
442        then move on and do something more productive. */
443     /* A better solution would be to add a new arg to the task that would
444        tell it the number of times to attempt execution before returning to
445        the planner for guidance. */
446     if (task->execnum > 3)
447       return TASK_IS_COMPLETE;
448     /* This is to hit a (given type/side of) unit at a given place. */
449     tx = task->args[0];
450     ty = task->args[1];
451     tu = task->args[2];
452     ts = task->args[3];
453     dist = distance(tx, ty, unit->x, unit->y);
454     if (dist <= 1) {
455 	if (can_attack_any(unit, unit)) {
456 	    for_all_view_stack(us, tx, ty, uview) {
457 		if (ts == uview->siden && tu == uview->type) {
458 		    unit2 = view_unit(uview);
459 		    if (unit2
460 			&& valid(check_attack_action(unit, unit, unit2, 100))) {
461 			prep_attack_action(unit, unit, unit2, 100);
462 			return TASK_PREPPED_ACTION;
463 		    }
464 		}
465 	    }
466 	    /* Maybe we can overrun, but not if our cell is known to
467 	       be clear of enemies. */
468 	    if (dist > 0
469 	        && valid(
470 		    check_overrun_action(unit, unit, tx, ty, unit->z, 100))) {
471 		prep_overrun_action(unit, unit, tx, ty, unit->z, 100);
472 		return TASK_PREPPED_ACTION;
473 	    }
474 	}
475 	/* Might be able to fire at pointblank range. */
476 	if (can_fire_at_any(unit, unit) && dist >= u_range_min(u)) {
477 	    for_all_view_stack(us, tx, ty, uview) {
478 		if (ts == uview->siden && tu == uview->type) {
479 		    unit2 = view_unit(uview);
480 		    if (unit2
481 			&& valid(check_fire_at_action(unit, unit, unit2, -1))) {
482 			prep_fire_at_action(unit, unit, unit2, -1);
483 			return TASK_PREPPED_ACTION;
484 		    }
485 		}
486 	    }
487 	}
488 	return TASK_FAILED;
489     }
490     if (dist < u_range_min(u)) {
491 	/* should move further away */
492 	return TASK_FAILED;
493     }
494     /* If we're within firing range, attempt to fire. */
495     if (dist <= u_range(u)) {
496 	for_all_view_stack(us, tx, ty, uview) {
497 	    if (ts == uview->siden && tu == uview->type) {
498 		unit2 = view_unit(uview);
499 		if (unit2 && valid(check_fire_at_action(unit, unit, unit2, -1))) {
500 		    prep_fire_at_action(unit, unit, unit2, -1);
501 		    return TASK_PREPPED_ACTION;
502 		}
503 	    }
504 	}
505 	return TASK_FAILED;
506     }
507     if (!target_visible(unit, task))
508       return TASK_FAILED;
509     /* If on mobile transport, let it handle things. */
510     if (unit->transport != NULL
511         && mobile(unit->transport->type)
512 	/* and the transport is not blocked */
513         && flip_coin()) {
514         return TASK_IS_INCOMPLETE;
515     }
516     /* If out of range and can move, push a task to get closer (maybe). */
517     if (mobile(u) && flip_coin()) {
518 	movedist = max(1 /* attack range */, u_range(u));
519 	if (dist > movedist + u_acp(u) /* or dist that could be covered in 1-2 turns */) {
520 	    movedist = max(movedist, (dist - movedist) / 4);
521 	}
522 	push_move_to_task(unit, tx, ty, movedist);
523 	return TASK_IS_INCOMPLETE;
524     }
525     return TASK_FAILED;
526 }
527 
528 int
target_visible(Unit * unit,Task * task)529 target_visible(Unit *unit, Task *task)
530 {
531     int tx, ty, tu, ts;
532     Side *us = unit->side;
533     UnitView *uview;
534 
535     tx = task->args[0];  ty = task->args[1];
536     tu = task->args[2];  ts = task->args[3];
537 
538     for_all_view_stack_with_occs(us, tx, ty, uview) {
539 	if (ts == uview->siden
540 	    && (tu == NONUTYPE || tu == uview->type)) {
541 	    return TRUE;
542 	}
543     }
544     return FALSE;
545 }
546 
547 /* Move in a straight line, go through things or stop rather than
548    going around. */
549 
550 static TaskOutcome
do_move_dir_task(Unit * unit,Task * task)551 do_move_dir_task(Unit *unit, Task *task)
552 {
553     int dir, tx, ty;
554     Unit *unit2 = NULL;
555     UnitView *uview = NULL;
556     Side *side = NULL;
557     int u = NONUTYPE;
558     int rslt = A_ANY_CANNOT_DO;
559     int curmp = 0, fullmp = 0;
560 
561     side = unit->side;
562     u = unit->type;
563     if ((task->args[1])-- > 0) {
564 	dir = task->args[0];
565 	/* Is the next cell even valid? */
566 	if (!point_in_dir(unit->x, unit->y, dir, &tx, &ty)) {
567 	    return TASK_FAILED;
568 	}
569 	/* Can we squeeze into the cell in any way, shape, or form? */
570 	if (!side_thinks_it_can_put_type_at(side, u, tx, ty))
571 	  return TASK_FAILED;
572 	/* Can the unit move into the cell? */
573 	if (valid(check_move_action(unit, unit, tx, ty, 0))) {
574 	    /* (Probably need to set reserve here for low ACP and MP cases,
575 		like we do for the enter action below.) */
576 	    prep_move_action(unit, unit, tx, ty, 0);
577 	    return TASK_PREPPED_ACTION;
578 	}
579 	/* Can the unit occupy another unit in the cell? */
580 	else if (unit_view_at(side, tx, ty)) {
581 	    for_all_view_stack(side, tx, ty, uview) {
582 		/* (A spy could enter untrusted unit...) */
583 		if (!trusted_side(side, side_n(uview->siden)))
584 		  continue;
585 		unit2 = view_unit(uview);
586 		rslt = check_enter_action(unit, unit, unit2);
587 		/* If not enough ACP left this turn, then wait. */
588 		if ((A_ANY_NO_ACP == rslt)
589 		    && (can_have_enough_acp(unit,
590 					    uu_acp_to_enter(u, uview->type)))) {
591 		    set_unit_reserve(side, unit, TRUE, FALSE);
592 		    return TASK_IS_INCOMPLETE;
593 		}
594 		/* If not enough MP left this turn, then wait. */
595 		else if (A_MOVE_NO_MP == rslt) {
596 		    if (can_be_actor(unit)) {
597 			curmp = (unit->act->acp * unit_speed(unit, tx, ty))
598 				/ 100 + u_free_mp(u);
599 			fullmp = ((total_acp_for_turn(unit) - u_acp_min(u)) *
600 				   unit_speed(unit, tx, ty)) / 100 +
601 				  u_free_mp(u);
602 		    }
603 		    else {
604 		      curmp = 0; fullmp = 0;
605 		    }
606 		    if (fullmp > curmp) {
607 			set_unit_reserve(side, unit, TRUE, FALSE);
608 			return TASK_IS_INCOMPLETE;
609 		    }
610 		}
611 		/* Else, we can enter now, then do it. */
612 		else if (valid(rslt)) {
613 		    prep_enter_action(unit, unit, unit2);
614 		    return TASK_PREPPED_ACTION;
615 		}
616 	    } /* for_all_view_stack */
617 	    return TASK_FAILED;
618 	}
619 	else {
620 	    return TASK_FAILED;
621 	}
622     } /* if ((task->args[1])-- > 0) */
623     /* Specified number of moves has already been executed. */
624     else {
625 	return TASK_IS_COMPLETE;
626     }
627 }
628 
629 #if (0)
630 /* If we are sitting in the same cell or transport as a resupply source,
631    resupply is "free" for both us and the resupply source, and the
632    resupply source has some supplies that we could stock up on, then
633    swipe the supplies before moving on. */
634 int
stock_up_materials_for_free(Unit * unit)635 stock_up_materials_for_free(Unit *unit)
636 {
637     Unit *supplier = NULL;
638     int u = NONUTYPE, u2 = NONUTYPE;
639     int m = NONMTYPE;
640 
641     u = unit->type;
642     if (!has_full_amount_of_all_materials(unit)) {
643         for_all_stack(unit->x, unit->y, supplier) {
644             if (enemy_side(unit->side, supplier->side))
645               continue;
646             if (!(supplier->supply))
647               continue;
648             u2 = supplier->type;
649             for_all_material_types(m) {
650     int dir;
651                 /* TODO: Finish implementing. */
652             }
653         }
654     }
655     return FALSE;
656 }
657 #endif
658 
659 static int
could_directly_board_ferry(Unit * unit,Unit * transport)660 could_directly_board_ferry(Unit * unit, Unit * transport)
661 {
662     return (can_occupy(unit, transport) &&
663 	        valid(check_enter_action(unit, unit, transport)));
664 }
665 
666 /* The move-to task is the main way for units to get from point A to
667    point B.  In addition to the destination, the task has a required
668    distance, so it will succeed if the unit is within that distance to
669    the nominal destination. */
670 
671 static TaskOutcome
do_move_to_task(Unit * unit,Task * task)672 do_move_to_task(Unit *unit, Task *task)
673 {
674     int dist, tx, ty, check;
675     Unit *unit2, *occ;
676     int canceltask = FALSE;
677     Task *tmptask = NULL;
678 
679     /* This task is to get to a designated location somehow. */
680     tx = task->args[0];  ty = task->args[1];
681     dist = distance(tx, ty, unit->x, unit->y);
682     if (dist <= task->args[3]) {
683 #if (0)
684 	/* If unit is a mobile transport, then don't get jittery. */
685 	if (unit->occupant && mobile(unit->type)) {
686 	    for_all_occupants(unit, occ) {
687 		if (has_acp_left(occ) && unit->plan
688 		    && !unit->plan->reserve) {
689 		    /* delay_unit(unit, TRUE); */
690 		    return TASK_IS_INCOMPLETE;
691 		}
692 	    }
693 	}
694 #endif
695 	return TASK_IS_COMPLETE;
696     }
697 #if (0)
698     /* Try to top off supplies if supplier around and supply transfer
699        does not cost any ACP. */
700     if (stock_up_materials_for_free(unit))
701       return TASK_IS_INCOMPLETE;
702 #endif
703     /* Abort the move-to, if it is associated with a resupply task that is
704        no longer necessary. Some games will run supply lines while a unit is
705        en route to resupply, and thereby negate the need to explicitly
706        move to a resupply point and resupply. */
707     if (task->next && (TASK_RESUPPLY == task->next->type)) {
708         if (NONMTYPE == task->next->args[0]) {
709 	    if (has_full_amount_of_all_materials(unit))
710 	      canceltask = TRUE;
711 	}
712         else if (has_full_amount_of_material(unit, task->next->args[0]))
713           canceltask = TRUE;
714         if (canceltask) {
715             tmptask = task->next;
716             task->next = task->next->next;
717             free_task(tmptask);
718             /* Lie, so that we can hopefully replan or retask. */
719             /* (Should have new TaskResult, TASK_CANCELLED.) */
720             return TASK_IS_COMPLETE;
721         }
722     }
723 #if (0)
724     /* Abort the move-to, if it is not associated with a resupply
725 	or entry task, and the unit is AI-controlled,
726 	and the distance to the destination
727 	is > the real operating range of the unit,
728 	or unit has less fuel than its doctrine threshold,
729 	and the unit is not in a transport. */
730     if ((!task->next
731 	 || (task->next
732 	     && ((task->next->type != TASK_RESUPPLY)
733 		 && (task->next->type != TASK_OCCUPY))))
734 	&& ai_controlled(unit)
735 	&& (((dist - task->args[3]) > real_operating_range_best(unit))
736 	    || past_halfway_point(unit))
737 	&& !unit->transport) {
738 	clear_task_agenda(unit);
739 	/* Lie, so that we can hopefully replan or retask. */
740 	/* (Should have new TaskResult, TASK_CANCELLED.) */
741 	return TASK_IS_COMPLETE;
742     }
743 #endif
744     switch (dist) {
745       case 0:
746       /* We're there already, nothing more to do. */
747       return TASK_IS_COMPLETE;
748       case 1:
749 	/* Adjacent cell, do a single move. */
750 	/* But first, if there are units here already, prefer to
751 	   interact with them. */
752 	for_all_stack(tx, ty, unit2) {
753 	    /* If there's somebody that we can enter, prefer to do that. */
754 	    if (can_occupy(unit, unit2)
755 		&& valid(check_enter_action(unit, unit, unit2))) {
756 		prep_enter_action(unit, unit, unit2);
757 		return TASK_PREPPED_ACTION;
758 	    }
759 	    /* Perhaps an occupant... */
760 	    /* (We could use the recursive occupant test, but if
761 	       things are that complicated, the player should probably
762 	       exercise manual control here.) */
763 	    for_all_occupants(unit2, occ) {
764 		if (can_occupy(unit, occ)
765 		    && valid(check_enter_action(unit, unit, occ))) {
766 		    prep_enter_action(unit, unit, occ);
767 		    return TASK_PREPPED_ACTION;
768 		}
769 	    }
770 	}
771 #if 0 /* auto-attack on move should be player-controlled... */
772 		if (!trusted_side(unit->side, unit2->side)) {
773 		    /* This is probably not a good idea, combat odds not
774 		       taken into account. */
775 		    if (valid(check_attack_action(unit, unit, unit2, 100))) {
776 			prep_attack_action(unit, unit, unit2, 100);
777 			return TASK_PREPPED_ACTION;
778 		    } else {
779 			continue;
780 		    }
781 		}
782 #endif
783 	/* Now try a basic move action. */
784 	if (valid(check = check_move_action(unit, unit, tx, ty, unit->z))) {
785 	    /* Moving into an empty cell. */
786 	    prep_move_action(unit, unit, tx, ty, unit->z);
787 	    return TASK_PREPPED_ACTION;
788 	} else {
789 	    /* If we're just short on mp, wait until the next turn to
790                try to move. */
791 	    if (check == A_MOVE_NO_MP) {
792 		notify(unit->side,
793 		       "%s is resting until next turn.",
794 		       unit_handle(unit->side, unit));
795 		set_unit_reserve(unit->side, unit, TRUE, FALSE);
796 		return TASK_IS_INCOMPLETE;
797 	    }
798 	    Dprintf("%s move action fails check, result is %s\n",
799 		    unit_desig(unit), hevtdefns[check].name);
800 	    return TASK_FAILED;
801 	}
802 	break;
803       default:
804 	if (dist <= u_move_range(unit->type)
805 	    && valid(check_move_action(unit, unit, tx, ty, unit->z))) {
806 	    prep_move_action(unit, unit, tx, ty, unit->z);
807 	    return TASK_PREPPED_ACTION;
808 	} else if (dist == 2
809 		   && valid(check_move_action(unit, unit, tx, ty, unit->z))) {
810 	    /* Border slide check. */
811 	    prep_move_action(unit, unit, tx, ty, unit->z);
812 	    return TASK_PREPPED_ACTION;
813 	} else {
814 	    /* Still some distance away, pick a way to go. */
815 	    return do_approach_subtask(unit, task, tx, ty, &(task->args[4]));
816 	}
817     }
818     return TASK_FAILED;
819 }
820 
821 static TaskOutcome
do_approach_subtask(Unit * unit,Task * task,int tx,int ty,int * statep)822 do_approach_subtask(Unit *unit, Task *task, int tx, int ty, int *statep)
823 {
824     int nx, ny, dirs[NUMDIRS], numdirs, i, numdirs2, check;
825     Unit *unit2;
826 
827     /* If on mobile transport, let it handle things. */
828     if (unit->transport != NULL
829 	&& mobile(unit->transport->type)
830 	/* and the transport is not stuck */
831 	&& probability(95)) {
832 	set_unit_reserve(unit->side, unit, TRUE, FALSE);
833 	return TASK_IS_INCOMPLETE;
834     }
835     numdirs =
836 	choose_move_dirs(unit, tx, ty, TRUE, plausible_move_dir,
837 			 sort_directions, dirs);
838     if (!numdirs)
839       numdirs =
840 	choose_move_dirs(unit, tx, ty, FALSE, plausible_move_dir,
841 			 sort_directions, dirs);
842     for (i = 0; i < numdirs; ++i) {
843 	point_in_dir(unit->x, unit->y, dirs[i], &nx, &ny);
844 	for_all_stack(nx, ny, unit2) {
845 	    if (can_occupy(unit, unit2)) {
846 		if (valid(check_enter_action(unit, unit, unit2))) {
847 		    prep_enter_action(unit, unit, unit2);
848 		    /* We (probably) made forward progress,
849 			so reopen choice of dirs. */
850 		    *statep = eitherway;
851 		    return TASK_PREPPED_ACTION;
852 		} else {
853 		    continue;
854 		}
855 	    } else if (!trusted_side(unit->side, unit2->side)) {
856 		if (unit->occupant) {
857 		    /* More important to find a way through. */
858 		    continue;
859 		} else {
860 		    /* This will encourage some re-evaluation. */
861 		    return TASK_FAILED;
862 		}
863 #if 0 /* the following is rarely a good idea */
864 		if (valid(check_attack_action(unit, unit, unit2, 100))) {
865 		    prep_attack_action(unit, unit, unit2, 100);
866 		    /* We (probably) made forward progress, so reopen choice of dirs. */
867 		    *statep = eitherway;
868 		    return TASK_PREPPED_ACTION;
869 		} else {
870 		    continue;
871 		}
872 #endif
873 	    }
874 	}
875 	if (valid(check_move_action(unit, unit, nx, ny, unit->z))) {
876 	    prep_move_action(unit, unit, nx, ny, unit->z);
877 	    /* We (probably) made forward progress, so reopen choice of dirs. */
878 	    *statep = eitherway;
879 	    return TASK_PREPPED_ACTION;
880 	}
881     }
882     /* Get both right and left non-decreasing dirs. */
883     numdirs  = choose_move_dirs(unit, tx, ty, TRUE, NULL, NULL, dirs);
884     numdirs2 = choose_move_dirs(unit, tx, ty, FALSE, NULL, NULL, dirs);
885     for (i = numdirs; i < numdirs2; ++i) {
886 	if (plausible_move_dir(unit, dirs[i])) {
887 	    switch (*statep) {
888 	      case eitherway:
889 		if (i == numdirs)
890 		  *statep = leftonly /* leftthenright */;
891 		if (i == numdirs+1)
892 		  *statep = rightonly /* rightthenleft */;
893 		break;
894 #if 0
895 	      case leftthenright:
896 		if (i == numdirs)
897 		  *statep = rightonly;
898 		if (i == numdirs+1)
899 		  *statep = rightonly;
900 		continue;
901 		break;
902 	      case rightthenleft:
903 		if (i == numdirs+1)
904 		  *statep = leftonly;
905 		continue;
906 		break;
907 #endif
908 	      case leftonly:
909 		if (i == numdirs+1)
910 		  continue;
911 		break;
912 	      case rightonly:
913 		if (i == numdirs)
914 		  continue;
915 		break;
916 	      default:
917 		run_warning("Weird right/left state %d", *statep);
918 		*statep = leftonly;
919 		break;
920 	    }
921 	} else {
922 	    switch (*statep) {
923 	      case eitherway:
924 		if (i == numdirs)
925 		  *statep = rightonly;
926 		if (i == numdirs+1)
927 		  *statep = leftonly;
928 		continue;
929 		break;
930 #if 0
931 	      case leftthenright:
932 		if (i == numdirs)
933 		  *statep = rightonly;
934 		if (i == numdirs+1)
935 		  *statep = rightonly;
936 		continue;
937 		break;
938 	      case rightthenleft:
939 		if (i == numdirs+1)
940 		  *statep = leftonly;
941 		continue;
942 		break;
943 #endif
944 	      case leftonly:
945 		if (i == numdirs)
946 		  return TASK_FAILED;
947 		if (i == numdirs+1)
948 		  continue;
949 		break;
950 	      case rightonly:
951 		if (i == numdirs)
952 		  continue;
953 		if (i == numdirs+1)
954 		  return TASK_FAILED;
955 		break;
956 	      default:
957 		run_warning("Weird right/left state %d", *statep);
958 		*statep = leftonly;
959 		break;
960 	    }
961 	}
962 	point_in_dir(unit->x, unit->y, dirs[i], &nx, &ny);
963 	for_all_stack(nx, ny, unit2) {
964 	    if (can_occupy(unit, unit2)) {
965 		if (valid(check_enter_action(unit, unit, unit2))) {
966 		    prep_enter_action(unit, unit, unit2);
967 		    return TASK_PREPPED_ACTION;
968 		} else {
969 		    continue;
970 		}
971 	    } else if (!trusted_side(unit->side, unit2->side)) {
972 		if (unit->occupant) {
973 		    /* More important to find a way through. */
974 		    continue;
975 		} else {
976 		    /* This will encourage some re-evaluation. */
977 		    return TASK_FAILED;
978 		}
979 #if 0				/* the following is rarely a good idea */
980 		if (valid(check_attack_action(unit, unit, unit2, 100))) {
981 		    prep_attack_action(unit, unit, unit2, 100);
982 		    return TASK_PREPPED_ACTION;
983 		} else {
984 		    continue;
985 		}
986 #endif
987 	    }
988 	}
989 	if (valid(check = check_move_action(unit, unit, nx, ny, unit->z))) {
990 	    prep_move_action(unit, unit, nx, ny, unit->z);
991 	    return TASK_PREPPED_ACTION;
992 	}
993 	/* If we're just short on mp, wait until the next turn to try to move. */
994 	if (check == A_MOVE_NO_MP) {
995 	    if (unit->side)
996 	      notify(unit->side, "%s is resting until next turn.",
997 				 unit_handle(unit->side, unit));
998 	    set_unit_reserve(unit->side, unit, TRUE, FALSE);
999 	    return TASK_IS_INCOMPLETE;
1000 	}
1001     }
1002     return TASK_FAILED;
1003 }
1004 
1005 static TaskOutcome
do_occupy_task(Unit * unit,Task * task)1006 do_occupy_task(Unit *unit, Task *task)
1007 {
1008     int dist;
1009     Unit *transport = NULL;
1010     int tx = -1;
1011     int ty = -1;
1012 
1013     transport = find_unit_dead_or_alive(task->args[0]);
1014     /* Transport may have left play in the interim between attempted task
1015        executions.
1016     */
1017     if (!transport || !in_play(transport)) {
1018         if (transport) {
1019           DMprintf("%s attempted to enter out-of-play transport %s.\n",
1020                     unit_desig(unit), unit_desig(transport));
1021         } else {
1022           DMprintf("%s attempted to enter a bogus transport with id %d.\n",
1023                    unit_desig(unit), task->args[0]);
1024         }
1025         return TASK_FAILED;
1026     }
1027 
1028     tx = transport->x;
1029     ty = transport->y;
1030     /* (should also fail if we don't know where transport is anymore) */
1031     if (unit->transport == transport) {
1032 	return TASK_IS_COMPLETE;
1033     }
1034     dist = distance(unit->x, unit->y, transport->x, transport->y);
1035     if (dist <= 1) {
1036 	if (valid(check_enter_action(unit, unit, transport))) {
1037 	    prep_enter_action(unit, unit, transport);
1038 	    return TASK_PREPPED_ACTION;
1039 	} else {
1040 	    /* Try a couple times, then fail if not working. */
1041 	    return (task->execnum < 3 ? TASK_IS_INCOMPLETE : TASK_FAILED);
1042 	}
1043     } else {
1044 	/* Still some distance away, pick a way to go. */
1045 	return do_approach_subtask(unit, task, transport->x, transport->y,
1046 				   &(task->args[1]));
1047     }
1048 }
1049 
1050 /* Wait around for a particular unit.  Give up if the unit is not
1051    forthcoming. */
1052 
1053 static TaskOutcome
do_pickup_task(Unit * unit,Task * task)1054 do_pickup_task(Unit *unit, Task *task)
1055 {
1056     Unit *occupant = NULL;
1057 
1058     occupant = find_unit_dead_or_alive(task->args[0]);
1059     /* Potential occupant may have left play in the interim between
1060        attempted task executions. */
1061     if (!occupant || !in_play(occupant)) {
1062         if (occupant) {
1063           DMprintf("%s attempted to pickup out-of-play unit %s.\n",
1064                     unit_desig(unit), unit_desig(occupant));
1065         } else {
1066           DMprintf("%s attempted to pickup a bogus unit with id %d.\n",
1067                    unit_desig(unit), task->args[0]);
1068         }
1069         return TASK_FAILED;
1070     }
1071     wake_unit(occupant->side, occupant, FALSE);
1072     if (occupant->transport == unit)
1073       return TASK_IS_COMPLETE;
1074     if (distance(unit->x, unit->y, occupant->x, occupant->y) > 1)
1075       return do_approach_subtask(unit, task, occupant->x, occupant->y,
1076 				 &(task->args[1]));
1077     if (task->execnum > 10) {
1078 	/* Waiting around isn't working for us, give up.  If the
1079 	   prospective occupant still needs us, we'll get another
1080 	   call. */
1081 	return TASK_FAILED;
1082     } else {
1083 	if (valid(check_enter_action(occupant, occupant, unit))) {
1084 	    prep_enter_action(occupant, occupant, unit);
1085 	    return TASK_PREPPED_ACTION;
1086 	} else if (valid(check_enter_action(unit, occupant, unit))) {
1087 	    prep_enter_action(unit, occupant, unit);
1088 	    return TASK_PREPPED_ACTION;
1089 	} else {
1090 	    return (task->execnum < 5 ? TASK_IS_INCOMPLETE : TASK_FAILED);
1091 	}
1092     }
1093 }
1094 
1095 static TaskOutcome
do_produce_task(Unit * unit,Task * task)1096 do_produce_task(Unit *unit, Task *task)
1097 {
1098     int m, tot, sofar, amt;
1099 
1100     m = task->args[0];
1101     if (!is_material_type(m)) {
1102 	/* This may be an indication of code bogosity; warn? */
1103 	return TASK_FAILED;
1104     }
1105     tot = task->args[1];
1106     sofar = task->args[2];
1107     if (sofar >= tot)
1108       return TASK_IS_COMPLETE;
1109     amt = um_material_per_production(unit->type, m);
1110     if (valid(check_produce_action(unit, unit, m, amt))) {
1111 	task->args[2] += amt;
1112 	prep_produce_action(unit, unit, m, amt);
1113 	return TASK_PREPPED_ACTION;
1114     }
1115     return TASK_FAILED;
1116 }
1117 
1118 /* The collection task runs a series of extraction actions,
1119    transferring the collected material to another, given, unit. */
1120 
1121 static int tmpm;
1122 
1123 static Unit *collect_here(int x, int y);
1124 static Unit *aux_collect_here(Unit *unit);
1125 
1126 static TaskOutcome
do_collect_task(Unit * unit,Task * task)1127 do_collect_task(Unit *unit, Task *task)
1128 {
1129     int m, x, y, dir, x1, y1, x2, y2, range;
1130     Unit *collector, *unit3;
1131 
1132     m = task->args[0];
1133     x = task->args[1];  y = task->args[2];
1134     /* Set up tmp globals early, all steps use these. */
1135     tmpunit = unit;
1136     tmpm = m;
1137     if (!is_material_type(m)) {
1138 	/* This may be an indication of code bogosity; warn? */
1139 	return TASK_FAILED;
1140     }
1141     /* If the unit is full, then arrange to dump the supply somewhere. */
1142     if (unit->supply[m] == um_storage_x(unit->type, m)) {
1143 	for_all_directions(dir) {
1144 	    if (interior_point_in_dir(unit->x, unit->y, dir, &x1, &y1)) {
1145 		if ((collector = collect_here(x1, y1)) != NULL) {
1146 		    transfer_supply(unit, collector, m, unit->supply[m]);
1147 		    if (unit->supply[m] == um_storage_x(unit->type, m))
1148 		      return TASK_FAILED;
1149 		    push_move_to_task(unit, task->args[1], task->args[2], 0);
1150 		    return TASK_IS_INCOMPLETE;
1151 		}
1152 	    }
1153 	}
1154 	/* Compute how far out to look for a delivery point. */
1155 	range = real_operating_range_best(unit);
1156 	if (search_around(unit->x, unit->y, range, collect_test,
1157 			  &x2, &y2, 1)) {
1158     	    /* (should find actual unit and chase it directly) */
1159 	    push_move_to_task(unit, x2, y2, 1);
1160 	    return TASK_IS_INCOMPLETE;
1161 	} else {
1162 	    /* Failure - sometimes just sit, but usually try something else. */
1163 	    if (probability(10))
1164 	      set_unit_reserve(unit->side, unit, TRUE, FALSE);
1165     	    /* (should be able to signal interface usefully somehow) */
1166 	    return TASK_FAILED;
1167 	}
1168     }
1169     if (distance(unit->x, unit->y, x, y) > 1) {
1170 	push_move_to_task(unit, x, y, 1);
1171 	return TASK_IS_INCOMPLETE;
1172     }
1173     if (valid(check_extract_action(unit, unit, x, y, m, 1))) {
1174 	prep_extract_action(unit, unit, x, y, m, 1);
1175 	return TASK_PREPPED_ACTION;
1176     }
1177     for_all_stack(x, y, unit3) {
1178 	if (in_play(unit3)
1179 	    && unit3->side == unit->side
1180 	    && type_max_acp(unit3->type) == 0) {
1181 	    if (valid(check_transfer_action(unit, unit3, m, 1, unit))) {
1182 		prep_transfer_action(unit, unit3, m, 1, unit);
1183 		return TASK_PREPPED_ACTION;
1184 	    }
1185 	}
1186     }
1187     /* We've run out of extractables in the immediate vicinity; look around
1188        for more. */
1189     tmpunit = unit;
1190     tmpm = m;
1191     if (search_around(x, y, 3, extractable_test, &x1, &y1, 1)) {
1192 	push_move_to_task(unit, x1, y1, 1);
1193 	task->args[1] = x1;  task->args[2] = y1;
1194 	return TASK_IS_INCOMPLETE;
1195     }
1196     return TASK_FAILED;
1197 }
1198 
1199 static int
collect_test(int x,int y)1200 collect_test(int x, int y)
1201 {
1202     return (collect_here(x, y) != NULL);
1203 }
1204 
1205 static Unit *
collect_here(int x,int y)1206 collect_here(int x, int y)
1207 {
1208     Unit *unit, *collector;
1209 
1210     for_all_stack(x, y, unit) {
1211     	collector = aux_collect_here(unit);
1212     	if (collector)
1213     	  return collector;
1214     }
1215     return NULL;
1216 }
1217 
1218 static Unit *
aux_collect_here(Unit * unit)1219 aux_collect_here(Unit *unit)
1220 {
1221     Unit *occ;
1222 
1223     /* what about allies? */
1224     if (unit != tmpunit && unit_trusts_unit(unit, tmpunit)) {
1225 	if ((unit->supply[tmpm] < um_storage_x(unit->type, tmpm)
1226 	     || um_gives_to_treasury(unit->type, tmpm))
1227 	    /* this is a hack to prevent foragers from trying to
1228                deliver to each other */
1229 	    && !mobile(unit->type))
1230 	  return unit;
1231 	/* (should also test for ability to transfer to side's storage) */
1232     }
1233     for_all_occupants(unit, occ) {
1234 	if (aux_collect_here(occ)) {
1235 	    return occ;
1236 	}
1237     }
1238     return NULL;
1239 }
1240 
1241 static int
extractable_test(int x,int y)1242 extractable_test(int x, int y)
1243 {
1244     Unit *unit;
1245 
1246     /* (should only look at already-seen cells) */
1247     /* (should test if unit can extract from these places) */
1248     if (any_cell_materials_defined()
1249 	&& cell_material_defined(tmpm)
1250 	&& material_at(x, y, tmpm) > 0)
1251       return TRUE;
1252     for_all_stack(x, y, unit) {
1253 	if (in_play(unit)
1254 	    && indep(unit)
1255 	    && unit->supply[tmpm] > 0)
1256 	  return TRUE;
1257     }
1258     return FALSE;
1259 }
1260 
1261 /* This function uses a global approach in that it checks if the unit
1262 and its destination are located in or are adjacent to the same region
1263 (sea or continent). Since the region area layer is precomputed during
1264 startup, this check is fast. There are certain simplistic assumptions
1265 built into the code, however. First, it is assumed that resupply and
1266 repair points for naval units can be on land (i.e. in ports) but not vice
1267 versa. Second, it is assumed that naval units always can enter such
1268 land-based resupply points, if they are adjacent to a liquid cell. */
1269 
1270 /* This code does not handle units on board of transports. A ground
1271 unit at sea will therefore fail to set a resupply or repair task since
1272 it cannot find a land path to a supply point. An air unit on board of a
1273 carrier will, however, be able to set a resupply task on land, since
1274 it can get there by itself. Ultimately, we should implement a way for
1275 occupants to set repair tasks and signal their transport where they
1276 need to go. In some games, occupants will leech supplies off their
1277 transport, so the latter will evetually run out of supplies and set
1278 its own resupply task. */
1279 
1280 /* The code does not check if a path to the destination really exists
1281 that our unit may follow. Posible problems: enemy units and hostile
1282 terrain. The fact that u_ground_mobile is set for a unit does not
1283 mean that it may traverse all possible ground terrain. Ultimately,
1284 the code should test for paths as well. */
1285 
1286 int
direct_access_to(int x,int y)1287 direct_access_to(int x, int y)
1288 {
1289 	int x1, y1, x2, y2;
1290 	int u = tmpunit->type;
1291 	int ux = tmpunit->x;
1292 	int uy = tmpunit->y;
1293 
1294 	/* Airborne units always have access everywhere. */
1295 	if (u_air_mobile(u)) {
1296 		return TRUE;
1297 	}
1298 	/* Landborne units have access if both cells belong
1299 	to the same non-liquid region. */
1300 	if (u_ground_mobile(u)) {
1301 		if (!t_liquid(terrain_at(ux, uy))
1302 		    && !t_liquid(terrain_at(x, y))) {
1303 			if (aref(area.landsea_regions, ux, uy)
1304 				== aref(area.landsea_regions, x, y)) {
1305 				return TRUE;
1306 			}
1307 		}
1308 	}
1309 	/* Seaborne units have access if both cells are adjacent
1310 	to the same liquid region. */
1311 	if (u_naval_mobile(u)) {
1312 		/* We are starting from a liquid cell. */
1313 		if (t_liquid(terrain_at(ux, uy))) {
1314 			/* Test if the destination belongs to the same region. */
1315 			if (aref(area.landsea_regions, ux, uy)
1316 				== aref(area.landsea_regions, x, y)) {
1317 				return TRUE;
1318 			}
1319 			/* Next test cells adjacent to the destination. */
1320 			for_all_cells_within_range(x, y, 1, x2, y2) {
1321 				if (aref(area.landsea_regions, ux, uy)
1322 					== aref(area.landsea_regions, x2, y2)) {
1323 					return TRUE;
1324 				}
1325 			}
1326 		/* We are starting from a land cell. */
1327 		} else {
1328 			/* Scan adjacent liquid cells. */
1329 			for_all_cells_within_range(ux, uy, 1, x1, y1) {
1330 				if (t_liquid(terrain_at(x1, y1))) {
1331 					/* Test if the destination belongs to the same region. */
1332 					if (aref(area.landsea_regions, x1, y1)
1333 						== aref(area.landsea_regions, x, y)) {
1334 						return TRUE;
1335 					}
1336 					/* Next test cells adjacent to the destination. */
1337 					for_all_cells_within_range(x, y, 1, x2, y2) {
1338 						if (aref(area.landsea_regions, x1, y1)
1339 							== aref(area.landsea_regions, x2, y2)) {
1340 							return TRUE;
1341 						}
1342 					}
1343 				}
1344 			}
1345 		}
1346 	}
1347 	return FALSE;
1348 }
1349 
1350 static TaskOutcome
do_toolup_subtask(Unit * constructor,int uc)1351 do_toolup_subtask(Unit *constructor, int uc)
1352 {
1353     int rslt = A_ANY_OK;
1354 
1355     assert_error(is_active(constructor),
1356 		 "AI: Attempted to toolup an inactive unit");
1357     assert_error(is_unit_type(uc),
1358 		 "AI: Encountered and invalid unit type to toolup for");
1359     // If by some strange coincidence we are inside this function,
1360     //	and constructor already has enough tooling,
1361     //	then get out.
1362     if (has_enough_tooling(constructor, uc))
1363 	return TASK_IS_INCOMPLETE;
1364     // If we cannot perform the toolup action, then the task must fail.
1365     if (!valid(rslt =
1366 	       can_toolup_for(constructor, constructor, uc))) {
1367 	// TODO: Should notify side.
1368 	return TASK_FAILED;
1369     }
1370     // Try to prep a toolup action.
1371     if (prep_toolup_action(constructor, constructor, uc))
1372 	return TASK_PREPPED_ACTION;
1373     return TASK_FAILED;
1374 }
1375 
1376 static TaskOutcome
do_construct_task(Unit * constructor,Task * task)1377 do_construct_task(Unit *constructor, Task *task)
1378 {
1379     int rslt = A_ANY_OK;
1380     int uc = NONUTYPE;
1381     int run = 0, x = -1, y = -1;
1382     int transid = -1;
1383     Unit *creation = NULL, *transport = NULL;
1384     Side *side = NULL;
1385     Task *tasks = NULL;
1386 
1387     assert_error(is_active(constructor),
1388 		 "AI: Attempted to construct with an inactive unit");
1389     assert_warning_return(task, "AI: Attempted to run invalid construct task",
1390 			  TASK_IS_COMPLETE);
1391     side = constructor->side;
1392     // Unpack task args.
1393     uc = task->args[0];
1394     run = task->args[1];
1395     // If run length <= 0, then we're done.
1396     if (0 >= run)
1397 	return TASK_IS_COMPLETE;
1398     transid = task->args[2];
1399     // If no transport or out-of-play transport, then try getting coords.
1400     transport = find_unit(transid);
1401     if (!in_play(transport)) {
1402 	x = task->args[3];  y = task->args[4];
1403 	// If coords are also invalid, then task fails.
1404 	if (!inside_area(x, y))
1405 	    return TASK_FAILED;
1406     }
1407     // If constructor has its creation ID set,
1408     //	then see if it matches an incomplete unit.
1409     //  If so, then decrement the construction run length,
1410     //  clear the creation ID, and push a build task, if necessary.
1411     creation = find_unit(constructor->creation_id);
1412     if (in_play(creation)) {
1413 	constructor->creation_id = -1;
1414 	--task->args[1];
1415 	// Push or set build task, if creation is incomplete.
1416 	// Push, if we have more construction planned.
1417 	// Set, if this is last of construction run.
1418 	if (task->args[1])
1419 	    push_build_task(
1420 		constructor, creation->id, u_cp(creation->type));
1421 	else
1422 	    set_build_task(
1423 		constructor, creation->id, u_cp(creation->type));
1424 	tasks = (constructor->plan ? constructor->plan->tasks : NULL);
1425 	if (!tasks || (TASK_BUILD != tasks->type))
1426 	    return TASK_FAILED;
1427 	tasks->args[1] = creation->id;
1428 	return TASK_IS_INCOMPLETE;
1429     }
1430     // Else, we try to proceed with creating an unit
1431     //	in the desired cell or transport.
1432     // If research or development is needed, then we should not be in this code.
1433     if (!side_can_build(side, uc))
1434 	return TASK_FAILED;
1435     // We must handle tooling, if necessary.
1436     if (!has_enough_tooling(constructor, uc))
1437 	return do_toolup_subtask(constructor, uc);
1438     // If transport is valid, then try creating in it.
1439     if (in_play(transport)) {
1440 	if (valid(rslt =
1441 		  can_create_in(constructor, constructor, uc, transport))) {
1442 	    prep_create_in_action(constructor, constructor, uc, transport);
1443 	    return TASK_PREPPED_ACTION;
1444 	}
1445     }
1446     // Else, try creating in designated cell.
1447     else {
1448 	if (valid(rslt =
1449 		  can_create_at(constructor, constructor, uc, x, y))) {
1450 	    prep_create_at_action(constructor, constructor, uc, x, y, 0);
1451 	    return TASK_PREPPED_ACTION;
1452 	}
1453     }
1454     // Wait for more materials or ACP, if necessary.
1455     // TODO: Proactively accumulate materials, if possible.
1456     if ((A_ANY_NO_MATERIAL == rslt) || (A_ANY_NO_ACP == rslt)) {
1457 	set_unit_reserve(constructor->side, constructor, TRUE, FALSE);
1458 	return TASK_IS_INCOMPLETE;
1459     }
1460     return TASK_FAILED;
1461 }
1462 
1463 static TaskOutcome
do_repair_self_subtask(Unit * repairee,Task * task)1464 do_repair_self_subtask(Unit *repairee, Task *task)
1465 {
1466     Unit *unit2 = NULL, *unitbest = NULL;
1467     Side *side = NULL;
1468     Task *tasks2 = NULL;
1469     int u = NONUTYPE, u2 = NONUTYPE;
1470     int tx = -1, ty = -1, dist = -1;
1471     int score = -1, scorebest = -1;
1472 
1473     assert_error(is_active(repairee),
1474 		 "AI: Attempted to repair with an inactive unit");
1475     assert_warning_return(task, "AI: Attempted to run invalid repair task",
1476 			  TASK_IS_COMPLETE);
1477     // Useful info.
1478     side = repairee->side;
1479     u = repairee->type;
1480     tx = repairee->x;  ty = repairee->y;
1481     // Try hp-recovery mechanism.
1482     if (0 < u_hp_recovery(u)) {
1483 	set_unit_reserve(side, repairee, TRUE, FALSE);
1484 	return TASK_IS_INCOMPLETE;
1485     }
1486     // Check if anyone else is tasked with repairing us.
1487     for_all_side_units(side, unit2) {
1488 	if (unit2 == repairee)
1489 	    continue;
1490 	// Skip inactive units.
1491 	if (!is_active(unit2))
1492 	    continue;
1493 	// Skip taskless units.
1494 	tasks2 = (unit2->plan ? unit2->plan->tasks : NULL);
1495 	if (!tasks2)
1496 	    continue;
1497 	// Useful info.
1498 	u2 = unit2->type;
1499 	// If 'move-to' task, then inspect closer.
1500 	if ((TASK_MOVE_TO == tasks2->type)
1501 	    && (uu_auto_repair_range(u2, u)
1502 		>= distance(tasks2->args[0], tasks2->args[1], tx, ty)))
1503 	    tasks2 = tasks2->next;
1504 	if ((TASK_MOVE_TO == tasks2->type)
1505 	    && (uu_repair_range(u2, u)
1506 		>= distance(tasks2->args[0], tasks2->args[1], tx, ty)))
1507 	    tasks2 = tasks2->next;
1508 	// If 'occupy' task, then inspect closer.
1509 	if (TASK_OCCUPY == tasks2->type)
1510 	    tasks2 = tasks2->next;
1511 	// If not 'repair' task, then skip.
1512 	if (TASK_REPAIR != tasks2->type)
1513 	    continue;
1514 	// Skip, if repairee is not the object of the repair.
1515 	if (repairee->id != tasks2->args[0])
1516 	    continue;
1517 	// If we've made it this far, then we know enough.
1518 	// Now we just sit back and let the other unit do the work.
1519 	set_unit_reserve(side, repairee, TRUE, FALSE);
1520 	return TASK_IS_INCOMPLETE;
1521     } // for all side units
1522     // If not auto-repair, then we report that the task failed.
1523     // TODO: Find an unit to explicitly repair us, and schedule the repair.
1524     if (!Xconq::any_auto_repair)
1525 	return TASK_FAILED;
1526     // Try to find someone to auto-repair us.
1527     for_all_side_units(side, unit2) {
1528 	if (unit2 == repairee)
1529 	    continue;
1530 	// Skip inactive units.
1531 	if (!is_active(unit2))
1532 	    continue;
1533 	// Probably not worth chasing mobile units. Let them come to us.
1534 	if (mobile(unit2->type))
1535 	    continue;
1536 	// Useful info.
1537 	u2 = unit2->type;
1538 	dist = distance(unit2->x, unit2->y, tx, ty);
1539 	// Subtract auto-repair range from distance.
1540 	// Note: For repairs that must occur inside a transport,
1541 	//  a penalty of 1 is effectively added.
1542 	dist = max(0, dist - uu_auto_repair_range(u2, u));
1543 	// If repairee is immobile,
1544 	//   and potential repairer is out of range, then skip it.
1545 	if (!mobile(u) && (0 < dist))
1546 	    continue;
1547 	// Score potential repairer.
1548 	score = hp_per_turn_est(unit2, u) / isqrt(dist + 1);
1549 	// Remember unit if it is best potential repairer.
1550 	if (score > scorebest) {
1551 	    scorebest = score;
1552 	    unitbest = unit2;
1553 	}
1554     } // for all side units
1555     if (0 < scorebest) {
1556 	u2 = unitbest->type;
1557 	// Calculate distance to be within repair range of best
1558 	//  potential repairer.
1559 	dist = distance(unitbest->x, unitbest->y, repairee->x, repairee->y);
1560 	dist = max(0, dist - uu_auto_repair_range(u2, u));
1561 	// If distance to repairer > 0, then move there.
1562 	// Note: A potential repairer with distance > 0 should never
1563 	//  have been selected, so this is not a concern.
1564 	if (dist > 0) {
1565 	    // Move within range of potential repairer.
1566 	    if (0 <= uu_auto_repair_range(u2, u))
1567 		// Move within auto-repair range of potential repairer.
1568 		push_move_to_task(
1569 		    repairee, unitbest->x, unitbest->y,
1570 		    uu_auto_repair_range(u2, u));
1571 	    else {
1572 		// Prepare to occupy potential repairer.
1573 		// TODO: Technically, we need to search not only
1574 		//  the potential repairer but all occs under it to
1575 		//  find an opening that we can occupy.
1576 		push_occupy_task(repairee, unitbest);
1577 		// Move-to potential repairer before occupation of it.
1578 		// NOTE: Move-to may not be necessary in all cases,
1579 		//  but it cannot hurt.
1580 		push_move_to_task(repairee, unitbest->x, unitbest->y, 1);
1581 	    }
1582 	}
1583 	// Else, wait around.
1584 	else
1585 	    set_unit_reserve(side, repairee, TRUE, FALSE);
1586 	// Return the task as being incomplete.
1587 	// If tasks were pushed onto the stack they will execute next.
1588 	return TASK_IS_INCOMPLETE;
1589     } // 0 < scorebest
1590     return TASK_FAILED;
1591 }
1592 
1593 static TaskOutcome
do_repair_task(Unit * repairer,Task * task)1594 do_repair_task(Unit *repairer, Task *task)
1595 {
1596     TaskOutcome rslt = TASK_IS_INCOMPLETE;
1597     Unit *repairee = NULL;
1598     Side *side = NULL;
1599     int id = -1;
1600     int u = NONUTYPE, u2 = NONUTYPE;
1601     int hpgoal = -1;
1602 
1603     assert_error(is_active(repairer),
1604 		 "AI: Attempted to repair with an inactive unit");
1605     assert_warning_return(task, "AI: Attempted to run invalid repair task",
1606 			  TASK_IS_COMPLETE);
1607     // Get repairee.
1608     id = task->args[0];
1609     repairee = find_unit(id);
1610     // Is repairee in play?
1611     if (!in_play(repairee))
1612 	return TASK_FAILED;
1613     // Useful info.
1614     u = repairer->type;
1615     u2 = repairee->type;
1616     side = repairer->side;
1617     hpgoal = task->args[1];
1618     // If repair is finished, then indicate that the task is complete.
1619     if (repairee->hp >= hpgoal)
1620 	return TASK_IS_COMPLETE;
1621     // Set up explicit repair action, if possible.
1622     if (valid(can_repair(repairer, repairer, repairee))) {
1623 	prep_repair_action(repairer, repairer, repairee);
1624 	return TASK_PREPPED_ACTION;
1625     }
1626     // Wait around for auto-repair, if possible.
1627     if (valid(can_auto_repair(repairer, repairee))) {
1628 	// If repairer is repairee, then try to get repaired various ways.
1629 	if ((repairer == repairee)
1630 	    && (TASK_FAILED != (rslt = do_repair_self_subtask(repairee, task))))
1631 	    return rslt;
1632 	else {
1633 	    set_unit_reserve(side, repairer, TRUE, FALSE);
1634 	    return TASK_IS_INCOMPLETE;
1635 	}
1636     }
1637     // None of the above worked. Something is wrong.
1638     Dprintf("%s repair task failed!\n", unit_desig(repairer));
1639     return TASK_FAILED;
1640 }
1641 
1642 #if (0)
1643 int
can_repair_from_here(int x,int y)1644 can_repair_from_here(int x, int y)
1645 {
1646 	int x1, y1, u = tmpunit->type, u2, range = 0, space = FALSE;
1647 	Unit *unit;
1648 
1649 	/* First test if auto-repair of this unit type is at all possible
1650 	    (should never get this far if not, but check anyway). */
1651 	if (!will_be_auto_repaired
1652 	    || !will_be_auto_repaired[u]) {
1653 	    return FALSE;
1654 	}
1655 	/* Then test if we can get there. */
1656 	if (!direct_access_to(x, y)) {
1657 	    return FALSE;
1658 	}
1659 	/* Also check if we can sit there. */
1660 	if (!type_survives_in_cell(u, x, y)
1661 	    || !type_can_occupy_cell(u, x, y)) {
1662 	    /* If not, check if we can sit inside a unit at (x, y). */
1663 	    for_all_stack_with_occs(x, y, unit) {
1664 		/* We are testing for empty type on the optimistic assumption
1665 		    that there will be some space when we get there. */
1666 		if (type_can_occupy_empty_type(u, unit->type)) {
1667 		    space = TRUE;
1668 		    break;
1669 		}
1670 	    }
1671 	    if (!space) {
1672 		    return FALSE;
1673 	    }
1674 	}
1675 	tmpx = x;
1676 	tmpy = y;
1677 	/* First check this cell. */
1678 	if (repair_here(x, y)) {
1679 	    return TRUE;
1680 	}
1681 	/* Compute how far out we need to search. */
1682 	for_all_unit_types(u2) {
1683 	    range = max(range, uu_auto_repair_range(u2, u));
1684 	}
1685 	/* Search adjacent cells. */
1686 	if (search_around(
1687 		x, y, range, (int (*)(int, int)) repair_here, &x1, &y1, 1)) {
1688 	    return TRUE;
1689 	}
1690 	return FALSE;
1691 }
1692 
1693 Unit *
repair_here(int x,int y)1694 repair_here(int x, int y)
1695 {
1696     int u = tmpunit->type, range = 0;
1697     Unit *unit2;
1698 
1699     for_all_stack_with_occs(x, y, unit2) {
1700 	/* Skip over inactive units. */
1701 	if (!is_active(unit2)) {
1702 		continue;
1703 	}
1704 	/* Skip over untrusting units. */
1705 	if (!unit_trusts_unit(unit2, tmpunit)) {
1706 		continue;
1707 	}
1708 	/* Skip over units that cannot repair us. */
1709 	if (uu_auto_repair(unit2->type, u) <= 0) {
1710 		continue;
1711 	}
1712 	range = uu_auto_repair_range(unit2->type, u);
1713 	/* Test if unit2 can repair unit and is within auto repair range of
1714 	    (x, y). Force the auto repair range to 0 if it is set to -1 to
1715 	    signal that only occupants should be repaired. */
1716 	if (distance(x, y, tmpx, tmpy) <= max(range, 0)) {
1717 	    /* Check that tmpunit can occupy unit2 if this is required.
1718 		Note: we optimistically test for room in empty transport
1719 		since things may change once we get there.
1720 		Should eventually add code that kicks out other occs to
1721 		make room for damaged units that need repair. */
1722 	    if (range < 0
1723 		&& !type_can_occupy_empty_type(u, unit2->type)) {
1724 		    continue;
1725 	    }
1726 	    /* If the auto-repair range is zero and we cannot enter either
1727 		the cell or unit2, we also have a problem. */
1728 	    if (range == 0
1729 		&& (!type_survives_in_cell(u, x, y)
1730 		    || !type_can_occupy_cell(u, x, y))
1731 		&& !type_can_occupy_empty_type(u, unit2->type)) {
1732 		    continue;
1733 	    }
1734 	    /* We assume that the calling code already has checked that
1735 		tmpunit can sit at (tmpx, tmpy). */
1736 	    return unit2;
1737 	}
1738     }
1739     return NULL;
1740 }
1741 #endif
1742 
1743 /* Replenish our supplies, using one of several strategies, which as
1744    usual depends on the game, unit, terrain, etc.  Strategies include
1745    1) wait for supply line or own production to replenish, 2) move to
1746    productive terrain and then wait, 3) move within range of a
1747    supplier, and 4) request a supplier to approach. */
1748 
1749 /* (should see if production actions would resupply, prep those actions) */
1750 
1751 static TaskOutcome
do_resupply_task(Unit * unit,Task * task)1752 do_resupply_task(Unit *unit, Task *task)
1753 {
1754     int x, y, u = unit->type, m, range;
1755     int ux = unit->x, uy = unit->y;
1756     Unit *unit2;
1757 #if (0)
1758     int amtavail = 0, amtwanted = 0;
1759 #endif
1760     int i = 0;
1761 
1762     /* A unit acting randomly might have gotten this task, even if the
1763     game has no materials or the unit no supply. Pretend that it was OK
1764     and get out of here. */
1765     if (nummtypes == 0 || unit->supply == NULL)
1766       return TASK_IS_COMPLETE;
1767     tmpside = unit->side;
1768     tmpunit = unit;
1769     if (lowm == NULL)
1770       lowm = (int *) xmalloc(nummtypes * sizeof(int));
1771     numlow = 0;
1772     if (task->args[0] == NONMTYPE) {
1773 	for_all_material_types(m) {
1774 	    if (unit->supply[m] < um_storage_x(u, m)) {
1775 		lowm[numlow++] = m;
1776 	    }
1777 	}
1778     } else {
1779 	m = task->args[0];
1780 	if (unit->supply[m] < um_storage_x(u, m)) {
1781 	    lowm[numlow++] = m;
1782 	}
1783     }
1784     /* We're all filled up, must be OK. */
1785     if (numlow == 0) {
1786     	return TASK_IS_COMPLETE;
1787     /* Set up an explicit extraction action if possible. We will still
1788 	benefit from any auto-resupply that is available.*/
1789     } else if (valid(check_extract_action(unit, unit,
1790 					  unit->x, unit->y, m, 1))) {
1791 	prep_extract_action(unit, unit, unit->x, unit->y, m, 1);
1792 	return TASK_PREPPED_ACTION;
1793     /* Should not just sit around when there may be more expedient ways to
1794 	get supplies that could let us get back into action the same turn. */
1795     } else if (can_auto_resupply_self(unit, lowm, numlow)) {
1796 	set_unit_reserve(unit->side, unit, TRUE, FALSE);
1797     	return TASK_IS_INCOMPLETE;
1798     /* Check if we are already at a valid resupply point. */
1799     } else if (can_resupply_from_here(ux, uy)) {
1800 	/* Try to enter any provider in the same cell. Note: this
1801 	    is to ensure that aircraft lands on a carrier. If we already
1802 	    have a transport, we stay put. */
1803 	if (!unit->transport) {
1804 	    for (i = 0; i < numlow; ++i) {
1805 		tmpmtype = lowm[i];
1806 		tmpx = ux;
1807 		tmpy = uy;
1808 		unit2 = resupply_here(ux, uy);
1809 		if (unit2
1810 		    && can_occupy(unit, unit2)) {
1811 		    prep_enter_action(unit, unit, unit2);
1812 		    return TASK_PREPPED_ACTION;
1813 		}
1814 	    }
1815 	}
1816 	/* Otherwise, just wait for the economy code to to its job. */
1817 	set_unit_reserve(unit->side, unit, TRUE, FALSE);
1818 	return TASK_IS_INCOMPLETE;
1819     } else {
1820 	/* Compute how far out to look for a resupply point. */
1821 	range = real_operating_range_best(unit);
1822 	if (search_around(ux, uy, range, can_resupply_from_here, &x, &y, 1)) {
1823 	    push_move_to_task(unit, x, y, 0);
1824 	    DMprintf("Resupply task: %s is moving to (%d, %d).",
1825 		     unit_desig(unit), x, y);
1826 	    return TASK_IS_INCOMPLETE;
1827 	} else {
1828 	    /* None of the above worked. Something is wrong. */
1829 	    Dprintf("%s resupply task failed!\n", unit_desig(unit));
1830 	    return TASK_FAILED;
1831 	}
1832     }
1833 }
1834 
1835 int
can_resupply_from_here(int x,int y)1836 can_resupply_from_here(int x, int y)
1837 {
1838     int i, x1, y1, u = tmpunit->type, space = FALSE;
1839     Unit *unit;
1840 
1841     /* First test if we can get there. */
1842     if (!direct_access_to(x, y)) {
1843 	return FALSE;
1844     }
1845     /* Also check if we can sit there. */
1846     if (!type_survives_in_cell(u, x, y)
1847 	|| !type_can_occupy_cell(u, x, y)) {
1848 	/* If not, check if we can sit inside a unit at (x, y). */
1849 	for_all_stack_with_occs(x, y, unit) {
1850 	    /* We are testing for empty type on the optimistic assumption
1851 		that there will be some space when we get there. */
1852 	    if (type_can_occupy_empty_type(u, unit->type)) {
1853 		space = TRUE;
1854 		break;
1855 	    }
1856 	}
1857 	if (!space) {
1858 	    return FALSE;
1859 	}
1860     }
1861     if (foundm == NULL) {
1862 	foundm = (int *) xmalloc(nummtypes * sizeof(int));
1863     }
1864     /* Search adjacent cells within our inlength for needed supplies. */
1865     for (i = 0; i < numlow; ++i) {
1866 	foundm[i] = FALSE;
1867 	tmpmtype = lowm[i];
1868 	tmpx = x;
1869 	tmpy = y;
1870 	/* First search this cell. */
1871 	if (resupply_here(x, y)) {
1872 	    foundm[i] = TRUE;
1873 	    continue;
1874 	}
1875 	if (search_around(x, y, um_inlength(u, lowm[i]),
1876 	    (int (*)(int, int)) resupply_here, &x1, &y1, 1)){
1877 	    foundm[i] = TRUE;
1878 	    continue;
1879 	}
1880     }
1881     /* If we cannot resupply a needed material from here, we are done. */
1882     for (i = 0; i < numlow; ++i) {
1883 	if (foundm[i] == FALSE) {
1884 	    return FALSE;
1885 	}
1886     }
1887     return TRUE;
1888 }
1889 
1890 Unit *
resupply_here(int x,int y)1891 resupply_here(int x, int y)
1892 {
1893     int u, tu = tmpunit->type, range = 0;
1894     Unit *unit;
1895 
1896     for_all_stack_with_occs(x, y, unit) {
1897 	u = unit->type;
1898 	/* Can't resupply from ourselves. */
1899 	if (unit == tmpunit)
1900 	  continue;
1901 	/* Can't resupply from enemies. */
1902 	if (!unit_trusts_unit(unit, tmpunit))
1903 	  continue;
1904 	/* The unit lacks our needed supply. */
1905 	if (unit->supply[tmpmtype] == 0)
1906 	  continue;
1907 	/* Compute the maximal possible supply range. */
1908 	range = min(um_outlength(u, tmpmtype), um_inlength(tu, tmpmtype));
1909 	/* Resupply is impossible. */
1910 	if (range < 0)
1911 	  continue;
1912 	/* We are out of range. */
1913 	if (range < distance(unit->x, unit->y, tmpx, tmpy))
1914 	  continue;
1915 	/* Range zero and there is no room for us. We assume
1916 	    that it is necessary to enter the provider. */
1917 	if (range == 0 && !can_occupy(tmpunit, unit))
1918 	  continue;
1919 	/* If range > 0 we assume that there is always room for
1920 	    us in a cell within range. */
1921 	return unit;
1922     }
1923     return NULL;
1924 }
1925 
1926 /* Return true if our own automatic material production is *greater*
1927    than our consumption, for the given list of materials. */
1928 
1929 int
can_auto_resupply_self(Unit * unit,int * materials,int numtypes)1930 can_auto_resupply_self(Unit *unit, int *materials, int numtypes)
1931 {
1932     int u = unit->type, i, m, rslt = TRUE, t = terrain_at(unit->x, unit->y);
1933 
1934     for (i = 0; i < numtypes; ++i) {
1935 	m = materials[i];
1936 	if ((um_base_production(u, m) * ut_productivity(u, t))
1937 	    <= um_base_consumption(u, m))
1938 	  rslt = FALSE;
1939     }
1940     return rslt;
1941 }
1942 
1943 /* The sentry task puts the unit into reserve each turn for a given
1944    number of turns. */
1945 
1946 static TaskOutcome
do_sentry_task(Unit * unit,Task * task)1947 do_sentry_task(Unit *unit, Task *task)
1948 {
1949     Task *nexttask = NULL;
1950     Unit *transport = NULL;
1951 
1952     if (task->next)
1953       nexttask = task->next;
1954     /* If we were waiting for a transport, and are now in it,
1955 	then don't wait. */
1956     if (nexttask->type == TASK_OCCUPY) {
1957 	transport = find_unit_dead_or_alive(nexttask->args[0]);
1958 	if (in_play(transport) && (transport == unit->transport)) {
1959 	    task->next = nexttask->next;
1960 	    free_task(nexttask);
1961 	}
1962 	return TASK_IS_COMPLETE;
1963     }
1964     if (task->args[0] > 0) {
1965 	set_unit_reserve(unit->side, unit, TRUE, FALSE);
1966 	--(task->args[0]);
1967 	return TASK_IS_INCOMPLETE;
1968     } else {
1969 	/* Unit won't necessarily wake up, may just replan and
1970 	   continue sleeping. */
1971 	return TASK_IS_COMPLETE;
1972     }
1973 }
1974 
1975 /* This is the main routine for a unit to execute a task.  It
1976    basically consists of a dispatch to the execution code for each
1977    task type, and handling for a task's several possible outcomes.
1978    Note that a task does *not* directly invoke any actions; instead it
1979    will schedule ("prep") an action, which will be executed later by
1980    execute_action.  Therefore, it is possible for a task to succeed
1981    but the action to fail, although each task type's code tries to
1982    reduce the chances of this happening (not possible to prevent
1983    entirely - unit may become damaged and unable to do perform an
1984    action after the task had decided on that action). */
1985 
1986 TaskOutcome
execute_task(Unit * unit)1987 execute_task(Unit *unit)
1988 {
1989     Plan *plan = unit->plan;
1990     TaskOutcome rslt;
1991     Task *task;
1992     extern int taskexecs;
1993 
1994     /* This should never happen. */
1995     if (unit->plan == NULL)
1996       run_error("???");
1997     /* If the unit is AI-run, don't do more than one task execution with
1998        it during each run step. */
1999     if (ai_controlled(unit)
2000          && plan->last_task_outcome != TASK_UNKNOWN
2001 	&& plan->last_task_outcome != TASK_PREPPED_ACTION
2002 	/* unless it is acp-independent ... */
2003 	&& !acp_indep(unit))
2004       return unit->plan->last_task_outcome;
2005     task = plan->tasks;
2006     if (task == NULL)
2007       return TASK_UNKNOWN;
2008     ++taskexecs;
2009     rslt = execute_task_aux(unit, task);
2010     DMprintf("%s did task %s, ", unit_desig(unit), task_desig(task));
2011     /* Record it. */
2012     memcpy(&(unit->plan->last_task), task, sizeof(Task));
2013     unit->plan->last_task_outcome = rslt;
2014     /* Now look at what happened with task execution. */
2015     switch (rslt) {
2016       case TASK_UNKNOWN:
2017 	DMprintf("???unknown outcome???");
2018 	break;
2019       case TASK_FAILED:
2020         ++task->retrynum;
2021 	DMprintf("failed try %d, ", task->retrynum);
2022 	/* If a task fails, it might be because the task cannot be
2023 	   completed, or just because conditions are temporarily
2024 	   unfavorable, such as a passing unit blocking the way while
2025 	   moving through.  So we need to retry a couple times at
2026 	   least; the variables here control how hard to keep
2027 	   trying. */
2028 	/* (should be doctrine, since these affect human-run units too) */
2029 	if (probability(g_ai_badtask_remove_chance())
2030 	    || task->retrynum >= g_ai_badtask_max_retries()) {
2031 	    pop_task(plan);
2032 	    DMprintf("removed it");
2033 	    /* We might be buzzing, so maybe go into reserve. */
2034 	    if (probability(g_ai_badtask_reserve_chance())) {
2035 		plan->reserve = TRUE;
2036 	    	DMprintf(" and went into reserve");
2037 	    }
2038 	} else {
2039 	    DMprintf("will retry");
2040 	}
2041 	break;
2042       case TASK_IS_INCOMPLETE:
2043 	/* Leave the task alone. */
2044 	DMprintf("incomplete");
2045 	break;
2046       case TASK_PREPPED_ACTION:
2047 	/* Mention the action that was prepared to execute. */
2048 	DMprintf("prepped action %s", action_desig(&(unit->act->nextaction)));
2049 	break;
2050       case TASK_IS_COMPLETE:
2051 	/* Task completed successfully, get rid of it. */
2052 	DMprintf("completed after %d executions", task->execnum);
2053 	pop_task(plan);
2054 	break;
2055       default:
2056 	break;
2057     }
2058     DMprintf("\n");
2059     return rslt;
2060 }
2061 
2062 /* Perform a single given task. */
2063 
2064 static TaskOutcome
execute_task_aux(Unit * unit,Task * task)2065 execute_task_aux(Unit *unit, Task *task)
2066 {
2067     TaskOutcome (*fn)(Unit *unit, Task *task);
2068 
2069     if (!alive(unit) || task == NULL)
2070       return TASK_UNKNOWN;
2071     DMprintf("%s doing task %s\n", unit_desig(unit), task_desig(task));
2072     if (task->type < 0 || task->type >= NUMTASKTYPES) {
2073 	run_warning("Unknown task type %d", task->type);
2074     	return TASK_FAILED;
2075     }
2076     /* Count this execution. */
2077     ++task->execnum;
2078     /* Do it. */
2079     fn = taskdefns[task->type].exec;
2080     return (*fn)(unit, task);
2081 }
2082 
2083 /* Wrapper to 'choose_move_dirs' function for providing "backward"
2084    compatibility to the 'choose_move_direction' function that some
2085    functions scattered around the kernel came to depend upon. */
2086 /* (The 'range' parameter is dead weight. Should we/can we do anything
2087     meaningful with it in the new context?) */
2088 int
choose_move_direction(Unit * unit,int x,int y,int range)2089 choose_move_direction(Unit *unit, int x, int y, int range)
2090 {
2091     int rslt = NODIR;
2092     int numdirs = 0;
2093     int dirs[NUMDIRS];
2094     int i = 0, ix, iy;
2095 
2096     /* Try to find a shortest path first. */
2097     numdirs = choose_move_dirs(unit, x, y, TRUE, plausible_move_dir,
2098 			       sort_directions, dirs);
2099 #if (1)
2100     /* If that fails then try to find any path. */
2101     /* (Unfortunately, this is not compatible with 'do_approach_subtask'.
2102 	If this piece of code is enabled and called from an UI,
2103 	it may say a move is OK, but a movement task that is prepped may,
2104 	in fact, fail in do_approach_subtask. So, for the time being, we
2105 	must accept that certain legitimate paths will be rejected.) */
2106     if (!numdirs)
2107       numdirs = choose_move_dirs(unit, x, y, FALSE, plausible_move_dir,
2108 				 sort_directions, dirs);
2109 #endif
2110     /* If that fails then either no path exists, or else our pathfinder
2111        algorithm does not do a more thorough search such as with Astar. */
2112     if (!numdirs)
2113       return NODIR;
2114     for (i = 0; i < numdirs; ++i) {
2115 	interior_point_in_dir(unit->x, unit->y, dirs[i], &ix, &iy);
2116 	if (!side_thinks_it_can_put_type_at(unit->side, unit->type, ix, iy))
2117 	  continue;
2118 	/* (Should put other tests here to make this function emulate
2119 	    the 'choose_move_direction' from Peter's pathfinder as much as
2120 	    is sane.) */
2121 	rslt = dirs[i];
2122 	break;
2123     }
2124     return rslt;
2125 }
2126 
2127 /* This weird-looking routine computes next directions for moving to a
2128    given spot.  The number of directions ranges from 1 to 4, depending
2129    on whether there is a straight-line path to the dest, and whether we are
2130    required to take a direct path or are allowed to move in dirs that don't
2131    bring the unit any closer (we never increase our distance though).
2132    Some trickinesses:  if area wraps, must resolve ambiguity about
2133    getting to the same place going either direction (we pick shortest). */
2134 
2135 int
choose_move_dirs(Unit * unit,int tx,int ty,int shortest,int (* dirtest)(Unit *,int),void (* dirsort)(Unit *,int *,int),int * dirs)2136 choose_move_dirs(Unit *unit, int tx, int ty, int shortest,
2137 		 int (*dirtest)(Unit *, int),
2138 		 void (*dirsort)(Unit *, int *, int),
2139 		 int *dirs)
2140 {
2141     int dx, dxa, dy, dist, d1, d2, d3, d4, axis = -1, hextant = -1;
2142     int numdirs = 0, shortestnumdirs;
2143 
2144     dist = distance(unit->x, unit->y, tx, ty);
2145     dx = tx - unit->x;  dy = ty - unit->y;
2146     if (area.xwrap) {
2147 	dxa = (tx + area.width) - unit->x;
2148 	if (ABS(dx) > ABS(dxa))
2149 	  dx = dxa;
2150 	dxa = (tx - area.width) - unit->x;
2151 	if (ABS(dx) > ABS(dxa))
2152 	  dx = dxa;
2153     }
2154     if (dx == 0 && dy == 0) {
2155 	return -1;
2156     }
2157     axis = hextant = -1;
2158     if (dx == 0) {
2159 	axis = (dy > 0 ? NORTHEAST : SOUTHWEST);
2160     } else if (dy == 0) {
2161 	axis = (dx > 0 ? EAST : WEST);
2162     } else if (dx == (0 - dy)) {
2163 	axis = (dy > 0 ? NORTHWEST : SOUTHEAST);
2164     } else if (dx > 0) {
2165 	hextant = (dy > 0 ? EAST :
2166 		   (ABS(dx) > ABS(dy) ? SOUTHEAST : SOUTHWEST));
2167     } else {
2168 	hextant = (dy < 0 ? WEST :
2169 		   (ABS(dx) > ABS(dy) ? NORTHWEST : NORTHEAST));
2170     }
2171     if (axis >= 0) {
2172 	d1 = d2 = axis;
2173 	if (dirtest == NULL || (*dirtest)(unit, d1)) {
2174 	    dirs[numdirs++] = d1;
2175 	}
2176     }
2177     if (hextant >= 0) {
2178 	d1 = left_dir(hextant);
2179 	d2 = hextant;
2180 	if (dirtest == NULL || (*dirtest)(unit, d1)) {
2181 	    dirs[numdirs++] = d1;
2182 	}
2183 	if (dirtest == NULL || (*dirtest)(unit, d2)) {
2184 	    dirs[numdirs++] = d2;
2185 	}
2186     }
2187     /* Check on other properties of the two choices. */
2188     if (numdirs > 1 && dirsort != NULL) {
2189     	(*dirsort)(unit, dirs, numdirs);
2190     }
2191     if (dist > 1 && !shortest) {
2192 	shortestnumdirs = numdirs;
2193     	d3 = left_dir(d1);
2194     	d4 = right_dir(d2);
2195 	if (dirtest == NULL || (*dirtest)(unit, d3)) {
2196 	    dirs[numdirs++] = d3;
2197 	}
2198 	if (dirtest == NULL || (*dirtest)(unit, d4)) {
2199 	    dirs[numdirs++] = d4;
2200 	}
2201 	if (numdirs > shortestnumdirs + 1 && dirsort != NULL) {
2202 	    (*dirsort)(unit, dirs + shortestnumdirs, numdirs - shortestnumdirs);
2203 	}
2204     }
2205     return numdirs;
2206 }
2207 
2208 /* A heuristic test for whether the given direction is a good one
2209    to move in. */
2210 
2211 int
plausible_move_dir(Unit * unit,int dir)2212 plausible_move_dir(Unit *unit, int dir)
2213 {
2214     int u = unit->type, ux = unit->x, uy = unit->y, u2, nx, ny, t, c, cost;
2215     int totcost, speed, maxmpavail;
2216 
2217     point_in_dir(ux, uy, dir, &nx, &ny);
2218     if (unit_at(nx, ny))
2219       return TRUE;
2220     t = terrain_at(nx, ny);
2221     /* Deadly terrain with no bridges is always implausible. */
2222     if ((ut_vanishes_on(u, t) || ut_wrecks_on(u, t))
2223         && !can_move_via_conn(unit, nx, ny))
2224       return FALSE;
2225     speed = unit_speed(unit, nx, ny);
2226     /* Try the easy test first. */
2227     if (ut_mp_to_enter(u, t) <= ((new_acp_for_turn(unit) * speed) / 100))
2228       return TRUE;
2229     u2 = (unit->transport ? unit->transport->type : NONUTYPE);
2230     totcost = total_move_cost(u, u2, ux, uy, 0, nx, ny, 0);
2231     /* Check if unit can possibly have enough mp for the move. */
2232     /* (We need to be careful here, since this function is not
2233 	actually privy to all knowledge. Should use type generic
2234 	functions instead.) */
2235     maxmpavail =
2236       (((u_acp_max(u) > 0 ? u_acp_max(u) : new_acp_for_turn(unit))
2237        - u_acp_min(u)) * speed) / 100
2238       + u_free_mp(u);
2239     if (maxmpavail >= totcost)
2240       return TRUE;
2241     /* Cross-country movement is not possible; try each connection
2242        type to see if it provides an alternative. */
2243     for_all_connection_types(c) {
2244 	if (aux_terrain_defined(c)
2245 	    && connection_at(ux, uy, dir, c)
2246 	    && ((cost = ut_mp_to_traverse(u, c)) >= 0)) {
2247 	    if ((ut_mp_to_enter(u, c) + cost + ut_mp_to_leave(u, c))
2248 		<= ((new_acp_for_turn(unit) * speed) / 100))
2249 	      return TRUE;
2250 	}
2251     }
2252     return FALSE;
2253 }
2254 
2255 /* This compares the desirability of two different directions.  This is
2256    somewhat tricky, because it should return < 0 if i0 designates a BETTER
2257    direction than i1. */
2258 
2259 int xs[NUMDIRS];
2260 int ys[NUMDIRS];
2261 int terrs[NUMDIRS];
2262 
2263 static int
compare_directions(CONST void * a0,CONST void * a1)2264 compare_directions(CONST void *a0, CONST void *a1)
2265 {
2266     int i0, i1;
2267     int u = tmputype, t0, t1;
2268     int ux = tmpunit->x, uy = tmpunit->y, u2 = NONUTYPE;
2269     int cost0 = 0, cost1 = 0, s, ps0, ps1, surr0, surr1, rslt;
2270     int cs0, cs1;
2271     extern short *any_people_surrenders;
2272 
2273     i0 = *((int *) a0);  i1 = *((int *) a1);
2274     t0 = terrs[i0];  t1 = terrs[i1];
2275     if (tmpunit->transport)
2276       u2 = tmpunit->transport->type;
2277     /* Check the overall movement cost of each direction. */
2278     cost0 = total_move_cost(u, u2, ux, uy, 0, xs[i0], ys[i0], 0);
2279     cost1 = total_move_cost(u, u2, ux, uy, 0, xs[i1], ys[i1], 0);
2280     if (cost0 != cost1) {
2281 	return cost0 - cost1;
2282     }
2283     if (1 /* not in supply */) {
2284 	if ((rslt = ut_productivity(u, t1) - ut_productivity(u, t0)) != 0) {
2285 	    return rslt;
2286 	}
2287     }
2288     if ((rslt = ut_mp_to_leave(u, t1) - ut_mp_to_leave(u, t0)) != 0) {
2289 	return rslt;
2290     }
2291     /* Chooser the safer terrain. */
2292     if ((rslt = ut_accident_hit(u, t1) - ut_accident_hit(u, t0)) != 0) {
2293 	return rslt;
2294     }
2295     /* Choose the better-concealing terrain. */
2296     /* (should only do if limited visibility) */
2297     if ((rslt = ut_visibility(u, t1) - ut_visibility(u, t0)) != 0) {
2298 	return rslt;
2299     }
2300     /* Prefer to go over cells that we can change to our side. */
2301     /* (should control via doctrine, this will reveal movements
2302        more often) */
2303     if (any_people_surrenders != NULL
2304 	&& any_people_surrenders[u]
2305 	&& people_sides_defined()) {
2306     	s = side_number(tmpunit->side);
2307     	ps0 = people_side_at(xs[i0], ys[i0]);
2308     	ps1 = people_side_at(xs[i1], ys[i1]);
2309     	surr0 = ut_people_surrender(u, t0)
2310 	  * ((ps0 != NOBODY && s != ps0) ? 1 : 0);
2311     	surr1 = ut_people_surrender(u, t1)
2312 	  * ((ps1 != NOBODY && s != ps1) ? 1 : 0);
2313     	if (surr0 != surr1) {
2314 	    return surr1 - surr0;
2315     	}
2316     }
2317     if (control_sides_defined()) {
2318     	s = side_number(tmpunit->side);
2319     	cs0 = control_side_at(xs[i0], ys[i0]);
2320     	cs1 = control_side_at(xs[i1], ys[i1]);
2321 	/* (should test trusted side) */
2322     	surr0 = ((ps0 != NOBODY && s != ps0) ? 1 : 0);
2323     	surr1 = ((ps1 != NOBODY && s != ps1) ? 1 : 0);
2324     	if (surr0 != surr1) {
2325 	    return surr1 - surr0;
2326     	}
2327     }
2328     return 0;
2329 }
2330 
2331 void
sort_directions(Unit * unit,int * dirs,int numdirs)2332 sort_directions(Unit *unit, int *dirs, int numdirs)
2333 {
2334     int i, tmp, i0 = 0, i1 = 1, compar;
2335 
2336     for (i = 0; i < numdirs; ++i) {
2337 	point_in_dir(unit->x, unit->y, dirs[i], &(xs[i]), &(ys[i]));
2338 	terrs[i] = terrain_at(xs[i], ys[i]);
2339     }
2340     tmpunit = unit;
2341     tmputype = unit->type;
2342     if (numdirs == 2) {
2343 	compar = compare_directions(&i0, &i1);
2344     	if (compar > 0 || (compar == 0 && flip_coin())) {
2345     	    tmp = dirs[0];  dirs[0] = dirs[1];  dirs[1] = tmp;
2346     	}
2347     } else if (numdirs > 2) {
2348     	qsort(dirs, numdirs, sizeof(int), compare_directions);
2349 	if (compare_directions(&i0, &i1) == 0 && flip_coin()) {
2350 	    tmp = dirs[0];  dirs[0] = dirs[1];  dirs[1] = tmp;
2351 	}
2352     }
2353 }
2354 
2355 /* Put the given task back onto the list of free tasks. */
2356 
2357 void
free_task(Task * task)2358 free_task(Task *task)
2359 {
2360     task->next = freetasks;
2361     freetasks = task;
2362 }
2363 
2364 void
add_task(Unit * unit,int pos,Task * task)2365 add_task(Unit *unit, int pos, Task *task)
2366 {
2367     int numcleared;
2368     Task *agenda = NULL;
2369 
2370     if (unit->plan == NULL && !completed(unit)) {
2371 	init_unit_plan(unit);
2372     }
2373     if (!in_play(unit) || unit->plan == NULL) {
2374 	run_warning("Trying to do %s task with bad %s",
2375 		    task_desig(task), unit_desig(unit));
2376 	return;
2377     }
2378     DMprintf("%s add task %s",
2379 	    unit_desig(unit), task_desig(task));
2380     if (pos == CLEAR_AGENDA) {
2381 	numcleared = clear_task_agenda(unit);
2382 	DMprintf(" (cleared %d existing tasks)", numcleared);
2383     }
2384     DMprintf("\n");
2385     switch (pos) {
2386       // Put the task on the front of the agenda.
2387       case ADD_TO_AGENDA_AS_LIFO:
2388       case CLEAR_AGENDA:
2389 	task->next = unit->plan->tasks;
2390 	unit->plan->tasks = task;
2391 	break;
2392       // Put the task on the end of the agenda.
2393       case ADD_TO_AGENDA_AS_FIFO:
2394 	task->next = NULL;
2395 	agenda = unit->plan->tasks;
2396 	if (!agenda)
2397 	    unit->plan->tasks = task;
2398 	else {
2399 	    for (; agenda && agenda->next; agenda = agenda->next);
2400 	    agenda->next = task;
2401 	}
2402 	break;
2403       default:
2404 	run_error("Tried to add a task to a task agenda in a strange manner");
2405 	break;
2406     }
2407     // Shouldn't be asleep any longer.
2408     unit->plan->asleep = FALSE;
2409     // We're not in reserve.
2410     unit->plan->reserve = FALSE;
2411     // Presumably we're no longer waiting to be told what to do.
2412     set_waiting_for_tasks(unit, FALSE);
2413     // Reflect all this on displays.
2414     update_unit_display(unit->side, unit, FALSE);
2415 }
2416 
2417 /* This routine sets up a task to build a unit of the given type. */
2418 
2419 Task *
create_build_task(Unit * unit,int id,int cp)2420 create_build_task(Unit *unit, int id, int cp)
2421 {
2422     Task *task = NULL;
2423 
2424     task = create_task(TASK_BUILD);
2425     task->args[0] = id;
2426     task->args[1] = cp;
2427     return task;
2428 }
2429 
2430 void
set_build_task(Unit * unit,int id,int cp)2431 set_build_task(Unit *unit, int id, int cp)
2432 {
2433     add_task(unit, CLEAR_AGENDA, create_build_task(unit, id, cp));
2434 }
2435 
2436 void
push_build_task(Unit * unit,int id,int cp)2437 push_build_task(Unit *unit, int id, int cp)
2438 {
2439     add_task(unit, 0, create_build_task(unit, id, cp));
2440 }
2441 
2442 Task *
create_capture_task(Unit * unit,int x,int y,int u,int s)2443 create_capture_task(Unit *unit, int x, int y, int u, int s)
2444 {
2445     Task *task = create_task(TASK_CAPTURE);
2446 
2447     task->args[0] = x;  task->args[1] = y;
2448     task->args[2] = u;
2449     task->args[3] = s;
2450     return task;
2451 }
2452 
2453 void
set_capture_task(Unit * unit,int x,int y,int u,int s)2454 set_capture_task(Unit *unit, int x, int y, int u, int s)
2455 {
2456     add_task(unit, CLEAR_AGENDA, create_capture_task(unit, x, y, u, s));
2457 }
2458 
2459 void
push_capture_task(Unit * unit,int x,int y,int u,int s)2460 push_capture_task(Unit *unit, int x, int y, int u, int s)
2461 {
2462     add_task(unit, 0, create_capture_task(unit, x, y, u, s));
2463 }
2464 
2465 Task *
create_collect_task(Unit * unit,int m,int x,int y)2466 create_collect_task(Unit *unit, int m, int x, int y)
2467 {
2468     Task *task = create_task(TASK_COLLECT);
2469 
2470     task->args[0] = m;
2471     task->args[1] = x;  task->args[2] = y;
2472     return task;
2473 }
2474 
2475 void
set_collect_task(Unit * unit,int m,int x,int y)2476 set_collect_task(Unit *unit, int m, int x, int y)
2477 {
2478     add_task(unit, 0, create_collect_task(unit, m, x, y));
2479 }
2480 
2481 Task *
create_disband_task(Unit * unit)2482 create_disband_task(Unit *unit)
2483 {
2484     return create_task(TASK_DISBAND);
2485 }
2486 
2487 void
set_disband_task(Unit * unit)2488 set_disband_task(Unit *unit)
2489 {
2490     add_task(unit, CLEAR_AGENDA, create_disband_task(unit));
2491 }
2492 
2493 Task *
create_hit_unit_task(Unit * unit,int x,int y,int u,int s)2494 create_hit_unit_task(Unit *unit, int x, int y, int u, int s)
2495 {
2496     Task *task = create_task(TASK_HIT_UNIT);
2497 
2498     task->args[0] = x;  task->args[1] = y;
2499     task->args[2] = u;
2500     task->args[3] = s;
2501     return task;
2502 }
2503 
2504 void
set_hit_unit_task(Unit * unit,int x,int y,int u,int s)2505 set_hit_unit_task(Unit *unit, int x, int y, int u, int s)
2506 {
2507     add_task(unit, CLEAR_AGENDA, create_hit_unit_task(unit, x, y, u, s));
2508 }
2509 
2510 void
push_hit_unit_task(Unit * unit,int x,int y,int u,int s)2511 push_hit_unit_task(Unit *unit, int x, int y, int u, int s)
2512 {
2513     add_task(unit, 0, create_hit_unit_task(unit, x, y, u, s));
2514 }
2515 
2516 /* Create a task to move in a given direction for a given distance. */
2517 
2518 Task *
create_move_dir_task(Unit * unit,int dir,int n)2519 create_move_dir_task(Unit *unit, int dir, int n)
2520 {
2521     Task *task = create_task(TASK_MOVE_DIR);
2522 
2523     task->args[0] = dir;
2524     task->args[1] = n;
2525     return task;
2526 }
2527 
2528 /* Fill in the given unit with direction-moving orders. */
2529 
2530 void
set_move_dir_task(Unit * unit,int dir,int n)2531 set_move_dir_task(Unit *unit, int dir, int n)
2532 {
2533     add_task(unit, CLEAR_AGENDA, create_move_dir_task(unit, dir, n));
2534 }
2535 
2536 Task *
create_move_to_task(Unit * unit,int x,int y,int dist)2537 create_move_to_task(Unit *unit, int x, int y, int dist)
2538 {
2539     Task *task = create_task(TASK_MOVE_TO);
2540 
2541     /* Other (time-critical AI) code expects that our data is clean,
2542        so filter it. */
2543     if (!in_area(x, y)) {
2544 	run_warning("move-to task with bad dest %d,%d, replacing", x, y);
2545 	/* Replace with a location guaranteed to be valid. */
2546 	x = area.width / 2;  y = area.height / 2;
2547     }
2548     task->args[0] = x;  task->args[1] = y;  task->args[2] = 0;
2549     task->args[3] = dist;
2550     task->args[4] = eitherway;
2551     return task;
2552 }
2553 
2554 void
set_move_to_task(Unit * unit,int x,int y,int dist)2555 set_move_to_task(Unit *unit, int x, int y, int dist)
2556 {
2557     add_task(unit, CLEAR_AGENDA, create_move_to_task(unit, x, y, dist));
2558 }
2559 
2560 void
push_move_to_task(Unit * unit,int x,int y,int dist)2561 push_move_to_task(Unit *unit, int x, int y, int dist)
2562 {
2563     add_task(unit, 0, create_move_to_task(unit, x, y, dist));
2564 }
2565 
2566 Task *
create_occupy_task(Unit * unit,Unit * transport)2567 create_occupy_task(Unit *unit, Unit *transport)
2568 {
2569     Task *task = create_task(TASK_OCCUPY);
2570 
2571     task->args[0] = transport->id;
2572     task->args[1] = eitherway;
2573     /* add a waiting period also? */
2574     return task;
2575 }
2576 
2577 void
set_occupy_task(Unit * unit,Unit * transport)2578 set_occupy_task(Unit *unit, Unit *transport)
2579 {
2580     add_task(unit, CLEAR_AGENDA, create_occupy_task(unit, transport));
2581 }
2582 
2583 void
push_occupy_task(Unit * unit,Unit * transport)2584 push_occupy_task(Unit *unit, Unit *transport)
2585 {
2586     add_task(unit, 0, create_occupy_task(unit, transport));
2587 }
2588 
2589 Task *
create_pickup_task(Unit * unit,Unit * occ)2590 create_pickup_task(Unit *unit, Unit *occ)
2591 {
2592     Task *task = create_task(TASK_PICKUP);
2593 
2594     task->args[0] = occ->id;
2595     /* add a waiting period also? */
2596     return task;
2597 }
2598 
2599 void
push_pickup_task(Unit * unit,Unit * occ)2600 push_pickup_task(Unit *unit, Unit *occ)
2601 {
2602     add_task(unit, 0, create_pickup_task(unit, occ));
2603 }
2604 
2605 Task *
create_produce_task(Unit * unit,int m,int n)2606 create_produce_task(Unit *unit, int m, int n)
2607 {
2608     Task *task = create_task(TASK_PRODUCE);
2609 
2610     task->args[0] = m;
2611     task->args[1] = n;
2612     /* Third arg is amount produced, which starts at 0. */
2613     return task;
2614 }
2615 
2616 void
push_produce_task(Unit * unit,int m,int n)2617 push_produce_task(Unit *unit, int m, int n)
2618 {
2619     add_task(unit, 0, create_produce_task(unit, m, n));
2620 }
2621 
2622 /* Construct Task */
2623 
2624 Task *
create_construct_task(Unit * unit,int u,int run,int transid,int x,int y)2625 create_construct_task(Unit *unit, int u, int run, int transid, int x, int y)
2626 {
2627     Task *task = NULL;
2628 
2629     task = create_task(TASK_CONSTRUCT);
2630     task->args[0] = u;
2631     task->args[1] = run;
2632     task->args[2] = transid;
2633     task->args[3] = x;
2634     task->args[4] = y;
2635     return task;
2636 }
2637 
2638 void
set_construct_task(Unit * unit,int u,int run,int transid,int x,int y)2639 set_construct_task(Unit *unit, int u, int run, int transid, int x, int y)
2640 {
2641     add_task(
2642 	unit, CLEAR_AGENDA, create_construct_task(unit, u, run, transid, x, y));
2643 }
2644 
2645 void
push_construct_task(Unit * unit,int u,int run,int transid,int x,int y)2646 push_construct_task(Unit *unit, int u, int run, int transid, int x, int y)
2647 {
2648     add_task(unit, 0, create_construct_task(unit, u, run, transid, x, y));
2649 }
2650 
2651 /* Repair Task */
2652 
2653 Task *
create_repair_task(Unit * unit,int id,int hp)2654 create_repair_task(Unit *unit, int id, int hp)
2655 {
2656     Task *task = NULL;
2657 
2658     task = create_task(TASK_REPAIR);
2659     task->args[0] = id;
2660     task->args[1] = hp;
2661     return task;
2662 }
2663 
2664 void
set_repair_task(Unit * unit,int id,int hp)2665 set_repair_task(Unit *unit, int id, int hp)
2666 {
2667     add_task(unit, CLEAR_AGENDA, create_repair_task(unit, id, hp));
2668 }
2669 
2670 void
push_repair_task(Unit * unit,int id,int hp)2671 push_repair_task(Unit *unit, int id, int hp)
2672 {
2673     add_task(unit, 0, create_repair_task(unit, id, hp));
2674 }
2675 
2676 /* This routine sets up a task to develop a unit of the given type. */
2677 
2678 Task *
create_develop_task(Unit * unit,int u2,int n)2679 create_develop_task(Unit *unit, int u2, int n)
2680 {
2681     Task *task = create_task(TASK_DEVELOP);
2682 
2683     task->args[0] = u2;
2684     task->args[1] = n;
2685     return task;
2686 }
2687 
2688 void
set_develop_task(Unit * unit,int u2,int techgoal)2689 set_develop_task(Unit *unit, int u2, int techgoal)
2690 {
2691     add_task(unit, CLEAR_AGENDA, create_develop_task(unit, u2, techgoal));
2692 }
2693 
2694 void
push_develop_task(Unit * unit,int u2,int techgoal)2695 push_develop_task(Unit *unit, int u2, int techgoal)
2696 {
2697     add_task(unit, 0, create_develop_task(unit, u2, techgoal));
2698 }
2699 
2700 Task *
create_resupply_task(Unit * unit,int m)2701 create_resupply_task(Unit *unit, int m)
2702 {
2703     Task *task = create_task(TASK_RESUPPLY);
2704 
2705     task->args[0] = m;
2706     return task;
2707 }
2708 
2709 void
set_resupply_task(Unit * unit,int m)2710 set_resupply_task(Unit *unit, int m)
2711 {
2712     add_task(unit, CLEAR_AGENDA, create_resupply_task(unit, m));
2713 }
2714 
2715 Task *
create_sentry_task(Unit * unit,int n)2716 create_sentry_task(Unit *unit, int n)
2717 {
2718     Task *task = create_task(TASK_SENTRY);
2719 
2720     task->args[0] = n;
2721     return task;
2722 }
2723 
2724 void
set_sentry_task(Unit * unit,int n)2725 set_sentry_task(Unit *unit, int n)
2726 {
2727     add_task(unit, CLEAR_AGENDA, create_sentry_task(unit, n));
2728 }
2729 
2730 void
push_sentry_task(Unit * unit,int n)2731 push_sentry_task(Unit *unit, int n)
2732 {
2733     add_task(unit, 0, create_sentry_task(unit, n));
2734 }
2735 
2736 extern int parse_location(Side *side, char *arg, int *xp, int *yp);
2737 
2738 extern Unit *parse_unit(Side *side, char *arg);
2739 
2740 /* Find a unit with the given name, either alive or dead. */
2741 
2742 Unit *
parse_unit(Side * side,char * nm)2743 parse_unit(Side *side, char *nm)
2744 {
2745     Unit *unit;
2746 
2747     if (empty_string(nm))
2748       return NULL;
2749     for_all_side_units(side, unit) {
2750 	if (alive(unit) && unit->name != NULL && strcmp(unit->name, nm) == 0)
2751 	  return unit;
2752     }
2753     /* Under some circumstances, we can refer to other sides' units by name. */
2754     for_all_units(unit) {
2755 	if (alive(unit)
2756 	    && unit->side != side
2757 	    && unit->name != NULL
2758 	    && strcmp(unit->name, nm) == 0
2759 	    && side_sees_image(side, unit))
2760 	  return unit;
2761     }
2762     return NULL;
2763 }
2764 
2765 /* Given a textual description of a location, compute an x,y for it
2766    if possible. */
2767 
2768 int
parse_location(Side * side,char * arg,int * xp,int * yp)2769 parse_location(Side *side, char *arg, int *xp, int *yp)
2770 {
2771     char *arg2;
2772     Unit *unit;
2773 
2774     *xp = strtol(arg, &arg2, 10);
2775     if (arg != arg2 && *arg2 == ',') {
2776 	*yp = strtol(arg2 + 1, &arg, 10);
2777 	if (arg2 + 1 != arg)
2778 	    return TRUE;
2779     } else if ((unit = parse_unit(side, arg)) != NULL) {
2780 	*xp = unit->x;  *yp = unit->y;
2781 	return TRUE;
2782     }
2783     notify(side, "location \"%s\" not recognized", arg);
2784     return FALSE;
2785 }
2786 
2787 /* Given a string describing a task that has been entered in
2788    by a player, generate a task object and return the rest
2789    of the string, if NULL if failure. */
2790 
2791 char *
parse_task(Side * side,char * str,Task ** taskp)2792 parse_task(Side *side, char *str, Task **taskp)
2793 {
2794     int tasktype, i, x, y, n, dir, u, taskargs[MAXTASKARGS], numargs;
2795     char *arg, *arg2, substr[BUFSIZE], *rest, *argtypes;
2796     Unit *unit;
2797 
2798     *taskp = NULL;
2799     rest = get_next_arg(str, substr, &arg);
2800     /* Recognize special cases of task types first. */
2801     if (strcmp(arg, "nil") == 0 || strcmp(arg, "nothing") == 0) {
2802 	/* NULL task with non-NULL return indicates order cancellation. */
2803 	*taskp = NULL;
2804 	return rest;
2805     } else if (strcmp(arg, "move-near") == 0) {
2806 	rest = get_next_arg(rest, substr, &arg);
2807 	if (parse_location(side, arg, &x, &y)) {
2808 	    rest = get_next_arg(rest, substr, &arg);
2809 	    n = strtol(arg, &arg2, 10);
2810 	    *taskp = create_move_to_task(NULL, x, y, n);
2811 	    return rest;
2812 	}
2813     }
2814     tasktype = lookup_task_type(arg);
2815     if (tasktype < 0) {
2816 	notify(side, "task type \"%s\" not recognized", arg);
2817 	return NULL;
2818     }
2819     switch (tasktype) {
2820       case TASK_MOVE_TO:
2821 	rest = get_next_arg(rest, substr, &arg);
2822 	if (parse_location(side, arg, &x, &y)) {
2823 	    *taskp = create_move_to_task(NULL, x, y, 0);
2824 	    return rest;
2825 	} else {
2826 	    return NULL;
2827 	}
2828 	break;
2829       default:
2830 	argtypes = taskdefns[tasktype].argtypes;
2831 	numargs = strlen(argtypes);
2832 	for (i = 0; i < numargs; ++i)
2833 	  taskargs[i] = 0;
2834 	rest = get_next_arg(rest, substr, &arg);
2835 	for (i = 0; i < numargs; ++i) {
2836 	    if (argtypes[i] == 'x' && argtypes[i+1] == 'y') {
2837 		/* If there are two arguments that are together a position,
2838 		   interpret both together. */
2839 		if (parse_location(side, arg, &x, &y)) {
2840 		    taskargs[i] = x;  taskargs[i + 1] = y;
2841 		    ++i;
2842 		} else {
2843 		    return NULL;
2844 		}
2845 	    } else if (argtypes[i] == 'd') {
2846 		char *mydirchars = "ulnbhy"; /* (a local copy of ui.c thing) */
2847 		/* Match on names or chars for directions. */
2848 		for_all_directions(dir) {
2849 		    if (strcmp(arg, dirnames[dir]) == 0) {
2850 			taskargs[i] = dir;
2851 			goto nextarg;
2852 		    }
2853 		    if (strlen(arg) == 1 && arg[0] == mydirchars[dir]) {
2854 			taskargs[i] = dir;
2855 			goto nextarg;
2856 		    }
2857 		}
2858 		notify(side, "direction \"%s\" not recognized", arg);
2859 	    } else if (argtypes[i] == 'u') {
2860 		u = utype_from_name(arg);
2861 		if (u != NONUTYPE) {
2862 		    taskargs[i] = u;
2863 		} else {
2864 		    notify(side, "unit type \"%s\" not recognized", arg);
2865 		}
2866 	    } else if (argtypes[i] == 'U') {
2867 		unit = parse_unit(side, arg);
2868 		if (unit != NULL) {
2869 		    taskargs[i] = unit->id;
2870 		} else {
2871 		    notify(side, "unit called \"%s\" not recognized", arg);
2872 		}
2873 	    } else {
2874 		/* Just collect an integer and stuff it. */
2875 		taskargs[i] = strtol(arg, &arg2, 10);
2876 		if (arg == arg2) {
2877 		    notify(side, "argument \"%s\" not recognized", arg);
2878 		}
2879 	    }
2880 	  nextarg:
2881 	    rest = get_next_arg(str, substr, &arg);
2882 	    /* (should check for end of command or not?) */
2883 	}
2884 	*taskp = create_task((TaskType)tasktype);
2885 	for (i = 0; i < numargs; ++i) {
2886 	    (*taskp)->args[i] = taskargs[i];
2887 	}
2888 	return rest;
2889     }
2890 }
2891 
2892 /* Describe a task succinctly - use for debugging only. */
2893 
2894 char *
task_desig(Task * task)2895 task_desig(Task *task)
2896 {
2897     int i, slen;
2898     char *argtypes;
2899 
2900     if (taskbuf == NULL)
2901       taskbuf = (char *)xmalloc(BUFSIZE);
2902     if (task) {
2903 	sprintf(taskbuf, "{%s", taskdefns[task->type].name);
2904 	argtypes = taskdefns[task->type].argtypes;
2905 	slen = strlen(argtypes);
2906 	for (i = 0; i < slen; ++i) {
2907 	    tprintf(taskbuf, "%c%d", (i == 0 ? ' ' : ','), task->args[i]);
2908 	}
2909 	tprintf(taskbuf, " x %d", task->execnum);
2910 	if (task->retrynum > 0) {
2911 	    tprintf(taskbuf, " fail %d", task->retrynum);
2912 	}
2913 	strcat(taskbuf, "}");
2914     } else {
2915 	sprintf(taskbuf, "no task");
2916     }
2917     return taskbuf;
2918 }
2919 
2920