home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Xconq 7.1.0 / src / xconq-7.1.0 / kernel / plan.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  55.6 KB  |  2,406 lines  |  [TEXT/R*ch]

  1. /* Unit plan handling for Xconq.
  2.    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. #include "conq.h"
  10.  
  11. static void wake_at PARAMS ((int x, int y));
  12.  
  13. #define CLEAR_AGENDA 99
  14.  
  15. /* (should have a generic struct for all plan type attrs) */
  16.  
  17. char *plantypenames[] = {
  18.  
  19. #undef  DEF_PLAN
  20. #define DEF_PLAN(NAME,code) NAME,
  21.  
  22. #include "plan.def"
  23.  
  24.     NULL
  25. };
  26.  
  27. /* Every unit that can act needs a plan object, types that can't act
  28.    should have it cleared out. */
  29.  
  30. void
  31. init_unit_plan(unit)
  32. Unit *unit;
  33. {
  34.     if (u_acp(unit->type) > 0 && unit->cp > 0) {
  35.     /* Might already have a plan, so don't always realloc. */
  36.     if (unit->plan == NULL) {
  37.         unit->plan = create_plan();
  38.     }
  39.     /* Put the plan into a default state, side will work it up later. */
  40.     unit->plan->type = PLAN_NONE;
  41.     unit->plan->creation_turn = g_turn();
  42.     unit->plan->asleep = FALSE;
  43.     unit->plan->reserve = FALSE;
  44.     unit->plan->delayed = FALSE;
  45.     clear_task_agenda(unit->plan);
  46.     /* Allow AIs to make this unit do things. */
  47.     unit->plan->aicontrol = TRUE;
  48.     /* Enable supply alarms by default. */
  49.     unit->plan->supply_alarm = TRUE;
  50.     } else {
  51.     /* Brainless units don't need anything, can free up plan. */
  52.     if (unit->plan != NULL) {
  53.         free_plan(unit->plan);
  54.     }
  55.     unit->plan = NULL;
  56.     }
  57. }
  58.  
  59. void
  60. set_unit_plan_type(side, unit, type)
  61. Side *side;
  62. Unit *unit;
  63. int type;
  64. {
  65.     int oldtype;
  66.  
  67.     if (unit->plan) {
  68.     oldtype = unit->plan->type;
  69.     if (type != oldtype) {
  70.         unit->plan->type = type;
  71.         if (side != NULL)
  72.           update_unit_display(side, unit, TRUE);
  73.     }
  74.     }
  75. }
  76.  
  77. void
  78. set_unit_asleep(side, unit, flag, recurse)
  79. Side *side;
  80. Unit *unit;
  81. int flag, recurse;
  82. {
  83.     int oldflag;
  84.     Unit *occ;
  85.  
  86.     if (unit->plan) {
  87.     oldflag = unit->plan->asleep;
  88.     if (flag != oldflag) {
  89.         unit->plan->asleep = flag;
  90.         if (side != NULL)
  91.           update_unit_display(side, unit, TRUE);
  92.     }
  93.     }
  94.     if (recurse) {
  95.         for_all_occupants(unit, occ) {
  96.         set_unit_asleep(side, occ, flag, recurse);
  97.         }
  98.     }
  99. }
  100.  
  101. void
  102. set_unit_reserve(side, unit, flag, recurse)
  103. Side *side;
  104. Unit *unit;
  105. int flag, recurse;
  106. {
  107.     int oldflag;
  108.     Unit *occ;
  109.  
  110.     if (unit->plan) {
  111.     oldflag = unit->plan->reserve;
  112.     if (flag != oldflag) {
  113.         unit->plan->reserve = flag;
  114.         if (side != NULL)
  115.           update_unit_display(side, unit, TRUE);
  116.     }
  117.     }
  118.     if (recurse) {
  119.         for_all_occupants(unit, occ) {
  120.         set_unit_reserve(side, occ, flag, recurse);
  121.         }
  122.     }
  123. }
  124.  
  125. void
  126. set_unit_ai_control(side, unit, flag, recurse)
  127. Side *side;
  128. Unit *unit;
  129. int flag, recurse;
  130. {
  131.     int oldflag;
  132.     Unit *occ;
  133.  
  134.     if (unit->plan) {
  135.     oldflag = unit->plan->aicontrol;
  136.     if (flag != oldflag) {
  137.         unit->plan->aicontrol = flag;
  138.         if (side != NULL)
  139.           update_unit_display(side, unit, TRUE);
  140.     }
  141.     }
  142.     if (recurse) {
  143.         for_all_occupants(unit, occ) {
  144.         set_unit_ai_control(side, occ, flag, recurse);
  145.         }
  146.     }
  147. }
  148.  
  149. /* Execute the plan. */
  150.  
  151. void
  152. execute_plan(unit, try)
  153. Unit *unit;
  154. int try;
  155. {
  156.     Plan *plan = unit->plan;
  157.  
  158.     if (!in_play(unit) || !completed(unit)) {
  159.     DMprintf("%s shouldn't be planning yet\n", unit_desig(unit));
  160.     return; 
  161.     }
  162.     DMprintf("%s using plan %s", unit_desig(unit), plan_desig(plan));
  163.     if (try > 1)
  164.       DMprintf(" (try #%d)", try);
  165.     DMprintf("\n");
  166.     /* Units that are asleep or in reserve do nothing. */
  167.     if (plan->asleep || plan->reserve)
  168.       return;
  169.     if (try > 5) {
  170.     DMprintf("%s redoing plan too often, going into reserve\n",
  171.          unit_desig(unit));
  172.     plan->reserve = TRUE;
  173.     return;
  174.     }
  175.     if (plan->execs_this_turn > 1000) {
  176.     DMprintf("%s executed plan 1000 times this turn, going into reserve\n",
  177.          unit_desig(unit));
  178.     plan->reserve = TRUE;
  179.     return;
  180.     }
  181.     /* Unit actually has a plan, dispatch on its type. */
  182.     switch (plan->type) {
  183.       case PLAN_NONE:
  184.     /* We get one chance to form a plan, putting the unit to sleep
  185.        if it doesn't work. */
  186.     decide_plan(unit->side, unit);
  187.     if (plan->type != PLAN_NONE) {
  188.         execute_plan(unit, ++try);
  189.     } else {
  190.         DMprintf("%s could not form a plan, going to sleep\n",
  191.              unit_desig(unit));
  192.         plan->asleep = TRUE;
  193.     }
  194.     break;
  195.       case PLAN_PASSIVE:
  196.     /* Passive units just work from the task queue or wait
  197.        to be told what to do. */
  198.     if (plan->supply_is_low && plan->supply_alarm) {
  199.         plan->supply_alarm = FALSE;
  200.         if (0 /* auto resupply */) {
  201.         set_resupply_task(unit, NONMTYPE);
  202.         } else if (plan->tasks
  203.                    && (plan->tasks->type == TASK_RESUPPLY
  204.                        || (plan->tasks->type == TASK_MOVE_TO
  205.                            && plan->tasks->next
  206.                            && plan->tasks->next->type == TASK_RESUPPLY))) {
  207.         /* do nothing */
  208.         } else {           
  209.         clear_task_agenda(plan);
  210.         wait_for_orders(unit);
  211.         }
  212.     }
  213.     if (plan->tasks) {
  214.         /* (should check that doctrine being followed correctly) */
  215.         execute_task(unit);
  216.     } else if (unit->side && unit->side->orders && execute_standing_order(unit, TRUE)) {
  217.         execute_task(unit);
  218.     } else if (plan->formation && move_into_formation(unit)) {
  219.         execute_task(unit);
  220.     } else if (unit->side && side_has_ai(unit->side)) {
  221.         /* Give AI a chance to dream up a more interesting plan. */
  222.         decide_plan(unit->side, unit);
  223.         execute_plan(unit, ++try);
  224.     } else if (doctrine_allows_wait(unit)) {
  225.         /* Our goal is now to get guidance from the side. */
  226.         wait_for_orders(unit);
  227.     } else {
  228.         /* We just are not getting any guidance at all... */
  229.         DMprintf("%s passive plan not working, going to sleep\n",
  230.              unit_desig(unit));
  231.         plan->asleep = TRUE;
  232.     }
  233.     break;
  234.       case PLAN_OFFENSIVE:
  235.     plan_offense(unit);
  236.     break;
  237.       case PLAN_DEFENSIVE:
  238.     plan_defense(unit);
  239.     break;
  240.       case PLAN_EXPLORATORY:
  241.     plan_exploration(unit);
  242.     break;
  243.       case PLAN_RANDOM:
  244.     plan_random(unit);
  245.     break;
  246.       default:
  247.     case_panic("plan type", plan->type);
  248.     break;
  249.     }
  250.     ++(plan->execs_this_turn);
  251. }
  252.  
  253. /* See if we're too far away from an assigned position, set a task
  254.    to move back if so. */
  255.  
  256. int
  257. move_into_formation(unit)
  258. Unit *unit;
  259. {
  260.     int nx, ny, dist; 
  261.     Plan *plan = unit->plan;
  262.     Goal *goal;
  263.     Unit *leader;
  264.  
  265.     leader = plan->funit;
  266.     /* (should doublecheck against leader id) */
  267.     if (leader != NULL) {
  268.     goal = plan->formation;
  269.     nx = leader->x + goal->args[1];  ny = leader->y + goal->args[2];
  270.     dist = goal->args[3];
  271.     if (distance(unit->x, unit->y, nx, ny) > dist) {
  272.         /* (should perhaps insert after current task?) */
  273.         set_move_near_task(unit, nx, ny, dist);
  274.         return TRUE;
  275.     }
  276.     }
  277.     return FALSE;
  278. }
  279.  
  280. int task_is_in_agenda PARAMS ((Plan *plan, Task *task));
  281.  
  282. /* See if there are any standing orders that currently apply to the given unit,
  283.    and schedule a task if so.  Return TRUE if a task was added. */
  284.  
  285. int
  286. execute_standing_order(unit, addtask)
  287. Unit *unit;
  288. int addtask;
  289. {
  290.     Unit *transport;
  291.     Side *side;
  292.     StandingOrder *sorder;
  293.  
  294.     side = unit->side;
  295.     if (side == NULL)
  296.       return FALSE;
  297.     for (sorder = side->orders; sorder != NULL; sorder = sorder->next) {
  298.     if (sorder->types[unit->type] && unit->plan) {
  299.         switch (sorder->etype) {
  300.           case 1:
  301.         if (unit->x == sorder->a1 && unit->y == sorder->a2) {
  302.             /* If the task is already in the plan, don't do
  303.                anything. */
  304.             if (task_is_in_agenda(unit->plan, sorder->task))
  305.               return FALSE;
  306.             if (addtask)
  307.               add_task(unit, 0, clone_task(sorder->task));
  308.             return TRUE;
  309.         }
  310.         break;
  311.           case 2:
  312.         transport = unit->transport;
  313.         if (transport != NULL && transport->id == sorder->a1) {
  314.             /* If the task is already in the plan, don't do
  315.                anything. */
  316.             if (task_is_in_agenda(unit->plan, sorder->task))
  317.               return FALSE;
  318.             if (addtask)
  319.               add_task(unit, 0, clone_task(sorder->task));
  320.             return TRUE;
  321.         }
  322.         break;
  323.           case 3:
  324.         if (distance(unit->x, unit->y, sorder->a1, sorder->a2) <= sorder->a3) {
  325.             /* If the task is already in the plan, don't do
  326.                anything. */
  327.             if (task_is_in_agenda(unit->plan, sorder->task))
  328.               return FALSE;
  329.             if (addtask)
  330.               add_task(unit, 0, clone_task(sorder->task));
  331.             return TRUE;
  332.         }
  333.         break;
  334.           default:
  335.         break;
  336.         }
  337.     }
  338.     }
  339.     return FALSE;
  340. }
  341.  
  342. int tasks_match PARAMS ((Task *task1, Task *task2));
  343.  
  344. int
  345. task_is_in_agenda(plan, task)
  346. Plan *plan;
  347. Task *task;
  348. {
  349.     Task *task2;
  350.  
  351.     for (task2 = plan->tasks; task2 != NULL; task2 = task2->next) {
  352.     if (tasks_match(task, task2))
  353.       return TRUE;
  354.     }
  355.     return FALSE;
  356. }
  357.  
  358. int
  359. tasks_match(task1, task2)
  360. Task *task1, *task2;
  361. {
  362.     int i;
  363.  
  364.     if (task1->type != task2->type)
  365.       return FALSE;
  366.     for (i = 0; i < MAXTASKARGS; ++i)
  367.       if (task1->args[i] != task2->args[i])
  368.     return FALSE;
  369.     return TRUE;
  370. }
  371.  
  372. /* A unit operating offensively advances and attacks when possible. */
  373.  
  374. void
  375. plan_offense(unit)
  376. Unit *unit;
  377. {
  378.     int u = unit->type;
  379.     int x, y, w, h, range, x1, y1;
  380.     Plan *plan = unit->plan;
  381.  
  382.     if (resupply_if_low(unit)) {
  383.     if (plan->tasks)
  384.       execute_task(unit);
  385.     return;
  386.     }
  387.     if (rearm_if_low(unit)) {
  388.     if (plan->tasks)
  389.       execute_task(unit);
  390.     return;
  391.     }
  392.     if (plan->tasks) {
  393.         execute_task(unit);
  394.         return;
  395.     }
  396.     if (plan->maingoal && mobile(u)) {
  397.     switch (plan->maingoal->type) {
  398.       case GOAL_VICINITY_HELD:
  399.         x = plan->maingoal->args[0];  y = plan->maingoal->args[1];
  400.         w = plan->maingoal->args[2];  h = plan->maingoal->args[3];
  401.         if (distance(x, y, unit->x, unit->y) > max(w, h)) {
  402.         /* Outside the goal area - move in towards it. */
  403.             if (random_point_near(x, y, w / 2, &x1, &y1)) {
  404.             x = x1;  y = y1;
  405.             }
  406.         DMprintf("%s to go on offensive to %d,%d\n",
  407.              unit_desig(unit), x, y);
  408.         set_move_near_task(unit, x, y, max(w, h) / 2);
  409.         if (unit->transport
  410.             && mobile(unit->transport->type)
  411.             && unit->transport->plan) {
  412.             set_move_near_task(unit->transport, x, y, max(w, h) / 2);
  413.         }
  414.         } else {
  415.         range = max(w, h);
  416.         /* No special goal, look for something to fight with. */
  417.         /* Sometimes be willing to look a little farther out. */
  418.         if (probability(50))
  419.           range *= 2;
  420.         if (do_for_occupants(unit)) {
  421.             /* Occupants have decided for us, fall through. */
  422.         } else if (go_after_victim(unit, range)) {
  423.             /* Found a victim to go after, fall through. */
  424.         } else if (probability(20) && self_build_base_for_self(unit)) {
  425.         } else if (!all_see_all) {
  426.             DMprintf("%s will explore instead\n", unit_desig(unit));
  427.             plan_exploration(unit); /* or patrol */
  428.             /* Running under exploration rules now. */
  429.             return;
  430.         }
  431.         }
  432.         break;
  433.       default:
  434.         DMprintf("offensive unit has some goal\n");
  435.         break;
  436.     }
  437.     } else if (mobile(u)) {
  438.     range = operating_range_best(u);
  439.     if (probability(50))
  440.       range = min(range, 2 * u_acp(u));
  441.     if (do_for_occupants(unit)) {
  442.     } else if (go_after_victim(unit, range)) {
  443.         /* No special goal, but found something to fight with. */
  444.     } else if (!all_see_all) {
  445.         DMprintf("%s will explore instead\n", unit_desig(unit));
  446.         plan_exploration(unit); /* or patrol */
  447.         /* Running under exploration rules now. */
  448.         return;
  449.     } else {
  450.         /* should go to a "best location" if possible. */
  451.         /* (should do a sentry task) */
  452.     }
  453.     } else if (can_fire(unit) && fire_at_opportunity(unit)) {
  454.     } else {
  455.     plan_offense_support(unit);
  456.     }
  457.     if (plan->tasks) {
  458.         execute_task(unit);
  459.     } else {
  460.         DMprintf("%s found nothing to do offensively", unit_desig(unit));
  461.         if (flip_coin()) {
  462.             DMprintf("- going into reserve");
  463.             plan->reserve = TRUE;
  464.         } else if (probability(5)) {
  465.             DMprintf("- going to sleep");
  466.             plan->asleep = TRUE;
  467.         }
  468.         DMprintf("\n");
  469.     }
  470. }
  471.  
  472. /* Look through list of occupants to see if an occupant needs the transport to do
  473.    something. */
  474.  
  475. int
  476. do_for_occupants(unit)
  477. Unit *unit;
  478. {
  479.     Unit *occ;
  480.     Goal *goal;
  481.     Task *task;
  482.  
  483.     for_all_occupants(unit, occ) {
  484.     if (occ->plan) {
  485.         /* Get the unit towards its goal, if it has one. */
  486.         goal = occ->plan->maingoal;
  487.         if (goal != NULL
  488.         && goal->type == GOAL_VICINITY_HELD
  489.         && distance(goal->args[0], goal->args[1], unit->x, unit->y)
  490.         > goal->args[2]) {
  491.         set_move_near_task(unit, goal->args[0], goal->args[1],
  492.                   max(goal->args[2] / 2, 1));
  493.         DMprintf("%s will go where occupant %s wants to go (goal %s)\n",
  494.              unit_desig(unit), unit_desig(occ), goal_desig(goal));
  495.         return TRUE;
  496.         }
  497.         /* If the unit does not have a goal, see if it has a task. */
  498.         for_all_tasks(occ->plan, task) {
  499.         if ((task->type == TASK_MOVE_TO
  500.              || task->type == TASK_HIT_UNIT)
  501.             && (task->args[0] != unit->x
  502.             || task->args[1] != unit->y)
  503.             && distance(task->args[0], task->args[1], unit->x, unit->y) > 1
  504.             ) {
  505.             /* Note that we assume the transport is mobile, which is OK currently
  506.                because of where this routine is called from. */
  507.             set_move_near_task(unit, task->args[0], task->args[1], 1);
  508.             DMprintf("%s will go where occupant %s wants to go (task %s)\n",
  509.                  unit_desig(unit), unit_desig(occ), task_desig(task));
  510.             return TRUE;
  511.         }
  512.         }
  513.     }
  514.     }
  515.     return FALSE;
  516. }
  517.  
  518. int
  519. self_build_base_for_self(unit)
  520. Unit *unit;
  521. {
  522.     int u = unit->type, u2, cando = FALSE;
  523.  
  524.     for_all_unit_types(u2) {
  525.     if (uu_acp_to_create(u, u2) > 0
  526.         && (uu_creation_cp(u, u2) >= u_cp(u2)
  527.             || uu_acp_to_build(u, u2) > 0)
  528.         /* (should check if any advantage to building) */
  529.        ) {
  530.        cando = TRUE;
  531.        break;
  532.     }
  533.     }
  534.     if (cando) {
  535.     DMprintf("%s building %s as a base for itself\n",
  536.              unit_desig(unit), u_type_name(u2));
  537.     set_construction(unit, u2, 1);
  538.     return TRUE;
  539.     }
  540.     return FALSE;
  541. }
  542.  
  543. void
  544. plan_offense_support(unit)
  545. Unit *unit;
  546. {
  547.     int u = unit->type, u2, u3 = NONUTYPE, backup = NONUTYPE;
  548.     Task *task;
  549.  
  550.     if (side_has_ai(unit->side)) {
  551.     u3 = ai_preferred_build_type(unit->side, unit, PLAN_OFFENSIVE);
  552.     } else {
  553.     for_all_unit_types(u2) {
  554.         if (mobile(u2)
  555.         && (type_can_attack(u2) || type_can_fire(u2))
  556.         && uu_acp_to_create(u, u2) > 0) {
  557.         backup = u2;
  558.         if (flip_coin()) {
  559.             u3 = u2;
  560.             break;
  561.         }
  562.         }
  563.     }
  564.     }
  565.     if (u3 == NONUTYPE) u3 = backup;
  566.     if (is_unit_type(u3)) {
  567.     task = unit->plan->tasks;
  568.         if (task == NULL || task->type != TASK_BUILD) {
  569.         DMprintf("%s supporting offense by building %s\n",
  570.              unit_desig(unit), u_type_name(u3));
  571.         set_construction(unit, u3, 2);
  572.     } else {
  573.         DMprintf("%s already building, leaving alone\n",
  574.              unit_desig(unit));
  575.     }
  576.     } else {
  577.         DMprintf("%s has no way to support an offensive\n", unit_desig(unit));
  578.     }
  579. }
  580.  
  581. void
  582. set_construction(unit, u, num)
  583. Unit *unit;
  584. int u, num;
  585. {
  586.     Task *task = unit->plan->tasks;
  587.  
  588.     if (task != NULL && task->type == TASK_BUILD) {
  589.     task->args[0] = u;
  590.     task->args[1] = num;
  591.     task->args[2] = 0;
  592.     } else {
  593.     push_build_task(unit, u, num);
  594.     }
  595. }
  596.  
  597. /* Defensive units don't go out looking for trouble, but they should
  598.    react strongly to threats. */
  599.  
  600. void
  601. plan_defense(unit)
  602. Unit *unit;
  603. {
  604.     if (resupply_if_low(unit)) {
  605.     if (unit->plan->tasks)
  606.       execute_task(unit);
  607.     return;
  608.     }
  609.     if (rearm_if_low(unit)) {
  610.     if (unit->plan->tasks)
  611.       execute_task(unit);
  612.     return;
  613.     }
  614.     if (unit->plan->tasks) {
  615.         /* (should analyze and maybe decide to change task) */
  616.         execute_task(unit);
  617.         return;
  618.     }
  619.     if (0 /* has specific goal */) {
  620.     } else if (can_fire(unit)) {
  621.     /* No special goal, look for something to shoot at. */
  622.     if (fire_at_opportunity(unit)) {
  623.         execute_task(unit);
  624.         return;
  625.     }
  626.     } else if (can_attack(unit)) {
  627.     /* can move a short ways to attack an interloper */
  628.     }
  629.     /* (might be able to defend by interposing self?) */
  630.     if (!unit->plan->reserve) {
  631.     /* Just stay in reserve for now. */
  632.     DMprintf("%s going into defensive reserve\n", unit_desig(unit));
  633.     unit->plan->reserve = TRUE;
  634.     }
  635. }
  636.  
  637. void
  638. plan_exploration(unit)
  639. Unit *unit;
  640. {
  641.     Plan *plan = unit->plan;
  642.     int u = unit->type;
  643.     int x, y, w, h, range, x1, y1;
  644.     Side *us = unit->side;
  645.  
  646.     /* If the world has no secrets, exploration is sort of pointless. */
  647.     if (all_see_all) {
  648.         plan->reserve = TRUE;
  649.         return;
  650.     }
  651.     if (resupply_if_low(unit)) {
  652.     if (plan->tasks)
  653.       execute_task(unit);
  654.     return;
  655.     }
  656.     if (capture_indep_if_nearby(unit))
  657.       return;
  658.     if (capture_useful_if_nearby(unit))
  659.       return;
  660.     if (plan->tasks) {
  661.         /* (should see if a change of task is worthwhile) */
  662.         execute_task(unit);
  663.         return;
  664.     }
  665.     if (plan->maingoal) {
  666.     switch (plan->maingoal->type) {
  667.       case GOAL_VICINITY_KNOWN:
  668.       case GOAL_VICINITY_HELD:
  669.         if (mobile(u)) {
  670.         x = plan->maingoal->args[0];  y = plan->maingoal->args[1];
  671.         w = plan->maingoal->args[2];  h = plan->maingoal->args[3];
  672.         if (distance(x, y, unit->x, unit->y) > max(w, h)) {
  673.                 if (random_point_near(x, y, max(w, h) / 2, &x1, &y1)) {
  674.                 x = x1;  y = y1;
  675.                 }
  676.             DMprintf("%s to explore towards %d,%d\n",
  677.                  unit_desig(unit), x, y);
  678.             set_move_near_task(unit, x, y, max(w, h) / 2);
  679.         } else {
  680.             if (explore_reachable_cell(unit, max(w, h) + 2)) {
  681.             } else if (us != NULL && side_has_ai(us) && ai_guide_explorer(us, unit)) {
  682.             } else {
  683.                 if (flip_coin()) {
  684.                 DMprintf("%s clearing goal\n", unit_desig(unit));
  685.                 plan->maingoal = NULL;
  686.                 }
  687.             DMprintf("%s to walk randomly\n", unit_desig(unit));
  688.             random_walk(unit);
  689.             }
  690.         }
  691.         } else {
  692.         plan_explorer_support(unit);
  693.         }
  694.         break;
  695.       case GOAL_WORLD_KNOWN:
  696.         if (mobile(u)) {
  697.         if (explore_reachable_cell(unit, area.maxdim)) {
  698.         } else if (us != NULL && side_has_ai(us)
  699.                && ai_guide_explorer(us, unit)) {
  700.         } else {
  701.             DMprintf("%s to walk randomly\n", unit_desig(unit));
  702.             random_walk(unit);
  703.         }
  704.         } else {
  705.         plan_explorer_support(unit);
  706.         }
  707.         break;
  708.       default:
  709.         DMprintf("%s goal %s?\n",
  710.              unit_desig(unit), goal_desig(unit->plan->maingoal));
  711.         break;
  712.     }
  713.     } else {
  714.     /* No specific goal, just poke around. */
  715.     if (mobile(u)) {
  716.         range = area.maxdim / 2;
  717.         if (explore_reachable_cell(unit, range)) {
  718.         } else if (us != NULL && side_has_ai(us) && ai_guide_explorer(us, unit)) {
  719.         } else {
  720.             if (flip_coin()) {
  721.                 /* (should call a plan eraser) */
  722.                 unit->plan->type = PLAN_NONE;
  723.             }
  724.         DMprintf("%s to walk randomly\n", unit_desig(unit));
  725.         random_walk(unit);
  726.         }
  727.     } else {
  728.         plan_explorer_support(unit);
  729.     }
  730.     }
  731.     if (plan->tasks) {
  732.         execute_task(unit);
  733.     } else {
  734.         if (probability(10)) {
  735.             DMprintf("no tasks, going to sleep (dunno why)\n");
  736.             plan->asleep = TRUE;
  737.         }
  738.     }
  739. }
  740.  
  741. void
  742. plan_explorer_support(unit)
  743. Unit *unit;
  744. {
  745.     int u = unit->type, u2, u3, backup;
  746.     Task *task;
  747.  
  748.     if (side_has_ai(unit->side)) {
  749.     u3 = ai_preferred_build_type(unit->side, unit, PLAN_EXPLORATORY);
  750.     } else {
  751.     for_all_unit_types(u2) {
  752.         if (mobile(u2)
  753.         && 1 /* better on more kinds of terrain? */
  754.         && uu_acp_to_create(u, u2) > 0) {
  755.         backup = u2;
  756.         if (flip_coin()) {
  757.             u3 = u2;
  758.             break;
  759.         }
  760.         }
  761.     }
  762.     }
  763.     if (u3 == NONUTYPE)
  764.       u3 = backup;
  765.     if (u3 != NONUTYPE) {
  766.     task = unit->plan->tasks;
  767.         if (task == NULL || task->type != TASK_BUILD) {
  768.         DMprintf("%s supporting exploration by building %s\n",
  769.              unit_desig(unit), u_type_name(u3));
  770.         push_build_task(unit, u3, 2);
  771.     } else {
  772.         DMprintf("%s already building, leaving alone\n",
  773.              unit_desig(unit));
  774.     }
  775.     } else {
  776.         DMprintf("%s has no way to support exploration\n", unit_desig(unit));
  777.     }
  778. }
  779.  
  780. int victimx, victimy, victimrating;
  781.  
  782. int
  783. victim_here(x, y)
  784. int x, y;
  785. {
  786.     int u2 = NONUTYPE, uview, rating, dist;
  787.     Unit *unit2;
  788.     Side *side = tmpunit->side, *oside = NULL;
  789.  
  790.     if (units_visible(side, x, y)) {
  791.     if ((unit2 = unit_at(x, y)) != NULL) {
  792.         u2 = unit2->type;
  793.         oside = unit2->side;
  794.     } else {
  795.         return FALSE;
  796.     }
  797.     } else if (terrain_view(side, x, y) != UNSEEN
  798.            && (uview = unit_view(side, x, y)) != EMPTY) {
  799.     u2 = vtype(uview);
  800.     oside = side_n(vside(uview));
  801.     } else {
  802.     return FALSE;
  803.     }
  804.     if (is_unit_type(u2)
  805.     && enemy_side(side, oside)
  806.     && ((could_hit(tmpunit->type, u2)
  807.         && uu_damage(tmpunit->type, u2) > 0
  808.         && (!worth_capturing(side, u2, oside, x, y)
  809.             || uu_capture(tmpunit->type, u2) > 0))
  810.         || uu_capture(tmpunit->type, u2) > 0)
  811.     ) {
  812.     /* If our unit can't capture the prospective victim, but somebody
  813.        else is planning to do so, leave it alone and keep looking for
  814.        a victim. */
  815.     if ((uu_acp_to_attack(tmpunit->type, u2) < 1
  816.          || capture_chance(tmpunit->type, u2, oside) <= 0)
  817.         && ai_planning_to_capture(side, u2, x, y)) {
  818.         return FALSE;
  819.     }
  820.     if (capture_chance(tmpunit->type, u2, oside) > 0) {
  821.         return TRUE;
  822.     }
  823.     if (tmpunit->occupant != NULL
  824.         && could_hit(u2, tmpunit->type)
  825.         && uu_damage(u2, tmpunit->type) > 0
  826.         /* and valuable occupants not protected... */
  827.         ) {
  828.         return FALSE;
  829.     }
  830.     rating = uu_zz_bhw(tmpunit->type, u2);
  831.     /* Further-away units are less interesting than closer ones. */
  832.     dist = distance(tmpunit->x, tmpunit->y, x, y);
  833.     if (dist > u_acp(tmpunit->type)) {
  834.         rating /= max(1, isqrt(dist - u_acp(tmpunit->type)));
  835.     }
  836.     if (rating > victimrating || (rating == victimrating && flip_coin())) {
  837.         victimx = x;  victimy = y;
  838.         victimrating = rating;
  839.     }
  840.     }
  841.     return FALSE;
  842. }
  843.  
  844. /* This decides whether a given unit type seen at a given location is worth
  845.    trying to capture. */
  846.  
  847. int
  848. worth_capturing(side, u2, side2, x, y)
  849. Side *side, *side2;
  850. int u2, x, y;
  851. {
  852.     int u, bestchance = 0;
  853.  
  854.     /* See how likely we are to be able to capture the type. */
  855.     for_all_unit_types(u) {
  856.     bestchance = max(capture_chance(u, u2, side2), bestchance);
  857.     }
  858.     if (bestchance == 0)
  859.       return FALSE;
  860.     /* (should account for other considerations too, like which types of units we have) */
  861.     return TRUE;
  862. }
  863.  
  864. /* This routine looks for somebody, anybody to attack. */
  865.  
  866. int
  867. go_after_victim(unit, range)
  868. Unit *unit;
  869. int range;
  870. {
  871.     int x, y, rslt;
  872.  
  873.     tmpunit = unit;
  874.     DMprintf("%s seeking victim within %d; found ",
  875.          unit_desig(unit), range);
  876.     victimrating = -9999;
  877.     rslt = search_around(unit->x, unit->y, range, victim_here, &x, &y, 1);
  878.     if (rslt) {
  879.     DMprintf("one at %d,%d\n", x, y);
  880.     /* Set up a task to go after the unit found. */
  881.     /* (should be able to set capture task if better) */
  882.     set_hit_task(unit, x, y);
  883.     if (unit->transport != NULL
  884.         && mobile(unit->transport->type)
  885.         && unit->transport->plan) {
  886.         set_move_near_task(unit->transport, x, y, 1);
  887.     }
  888.     } else if (victimrating > -9999) {
  889.     DMprintf("one (rated %d) at %d,%d\n", victimrating, victimx, victimy);
  890.     /* Set up a task to go after the unit found. */
  891.     /* (should be able to set capture task if better) */
  892.     set_hit_task(unit, victimx, victimy);
  893.     if (unit->transport != NULL
  894.         && mobile(unit->transport->type)
  895.         && unit->transport->plan) {
  896.         set_move_near_task(unit->transport, victimx, victimy, 1);
  897.     }
  898.     } else {
  899.     DMprintf("nothing\n");
  900.     }
  901.     return rslt;
  902. }
  903.  
  904. static int targetx, targety, targetrating;
  905.  
  906. int
  907. target_here(x, y)
  908. int x, y;
  909. {
  910.     int u2 = NONUTYPE, uview, rating, dist;
  911.     Unit *unit2;
  912.     Side *side = tmpunit->side, *oside = NULL;
  913.  
  914.     if (units_visible(side, x, y)) {
  915.     if ((unit2 = unit_at(x, y)) != NULL) {
  916.         u2 = unit2->type;
  917.         oside = unit2->side;
  918.     } else {
  919.         /* Nothing to shoot at here. */
  920.         return FALSE;
  921.     }
  922.     } else if (terrain_view(side, x, y) != UNSEEN
  923.            && (uview = unit_view(side, x, y)) != EMPTY) {
  924.     u2 = vtype(uview);
  925.     oside = side_n(vside(uview));
  926.     } else {
  927.     /* Nothing (or at least nothing visible) to shoot at here. */
  928.     return FALSE;
  929.     }
  930.     if (is_unit_type(u2)
  931.     && enemy_side(side, oside)
  932.     && could_hit(tmpunit->type, u2)
  933.     && uu_damage(tmpunit->type, u2) > 0
  934.     /* and have correct ammo */
  935.     && !ai_planning_to_capture(side, u2, x, y)
  936.     ) {
  937.         rating = uu_zz_bfw(tmpunit->type, u2);
  938.     /* Further-away units are less interesting than closer ones. */
  939.     dist = distance(tmpunit->x, tmpunit->y, x, y);
  940.     if (dist > 0)
  941.       rating /= dist;
  942.     if (rating > targetrating || (rating == targetrating && flip_coin())) {
  943.         targetx = x;  targety = y;
  944.         targetrating = rating;
  945.     }
  946.     }
  947.     return FALSE;
  948. }
  949.  
  950. int
  951. fire_at_opportunity(unit)
  952. Unit *unit;
  953. {
  954.     int x, y, range, rslt;
  955.  
  956.     tmpunit = unit;
  957.     range = u_range(unit->type);
  958.     targetrating = -9999;
  959.     DMprintf("%s seeking target within %d; found ",
  960.              unit_desig(unit), range);
  961.     rslt = search_around(unit->x, unit->y, range, target_here, &x, &y, 1);
  962.     if (rslt) {
  963.     DMprintf("one at %d,%d\n", x, y);
  964.     /* Set up a task to shoot at the unit found. */
  965.     set_hit_task(unit, x, y);
  966.     } else if (targetrating > -9999) {
  967.     DMprintf("one (rated %d) at %d,%d\n", targetrating, x, y);
  968.     /* Set up a task to shoot at the unit found. */
  969.     set_hit_task(unit, targetx, targety);
  970.     } else {
  971.     DMprintf("nothing\n");
  972.     }
  973.     return rslt;
  974. }
  975.  
  976. /* Check to see if our grand plans are at risk of being sideswiped by lack of
  977.    supply, and set up a resupply task if so. */
  978.  
  979. int
  980. resupply_if_low(unit)
  981. Unit *unit;
  982. {
  983.     int u = unit->type, lowm;
  984.     Task *curtask = unit->plan->tasks;
  985.  
  986.     if (!mobile(u))
  987.       return FALSE;
  988.     lowm = low_on_supplies_one(unit);
  989.     if (lowm != NONMTYPE) {
  990.     /* See if we're already moving to a supply source. */
  991.     if (curtask != NULL
  992.         && curtask->type == TASK_MOVE_TO /* or other types? */
  993.         && supplies_here(unit, curtask->args[0], curtask->args[1], lowm))
  994.       /* Let the movement task execute. */
  995.       return FALSE;
  996.     /* Otherwise set up a task. */
  997.     DMprintf("%s low on %s, looking for source\n",
  998.          unit_desig(unit), m_type_name(lowm));
  999.     set_resupply_task(unit, lowm);
  1000.     return (execute_task(unit) != TASK_FAILED);
  1001.     }
  1002.     return FALSE;
  1003. }
  1004.  
  1005. /* Return a type of essential material that the unit is running out of. */
  1006.  
  1007. int
  1008. low_on_supplies_one(unit)
  1009. Unit *unit;
  1010. {
  1011.     int u = unit->type, m;
  1012.  
  1013.     for_all_material_types(m) {
  1014.     if ((um_base_consumption(u, m) > 0 || um_consumption_per_move(u, m) > 0)
  1015.         && 2 * unit->supply[m] <= um_storage_x(u, m)) {
  1016.         return m;
  1017.     }
  1018.     }
  1019.     return NONMTYPE;
  1020. }
  1021.  
  1022. int
  1023. rearm_if_low(unit)
  1024. Unit *unit;
  1025. {
  1026.     int u = unit->type, lowm;
  1027.     Task *curtask = unit->plan->tasks;
  1028.  
  1029.     if (!mobile(u))
  1030.       return FALSE;
  1031.     lowm = low_on_ammo_one(unit);
  1032.     if (lowm != NONMTYPE) {
  1033.     if (curtask != NULL
  1034.         && curtask->type == TASK_MOVE_TO /* or other types? */
  1035.         && supplies_here(unit, curtask->args[0], curtask->args[1], lowm))
  1036.       /* Let the movement task execute. */
  1037.       return FALSE;
  1038.     /* Otherwise set up a task. */
  1039.     DMprintf("%s low on %s, looking for source\n",
  1040.          unit_desig(unit), m_type_name(lowm));
  1041.     set_resupply_task(unit, lowm);
  1042.     return (execute_task(unit) != TASK_FAILED);
  1043.     }
  1044.     return FALSE;
  1045. }
  1046.  
  1047. /* Return a type of material that we want to use in combat. */
  1048.  
  1049. int
  1050. low_on_ammo_one(unit)
  1051. Unit *unit;
  1052. {
  1053.     int u = unit->type, m;
  1054.  
  1055.     for_all_material_types(m) {
  1056.     if (um_consumption_per_attack(u, m) > 0
  1057.         && unit->supply[m] == 0
  1058.         && um_storage_x(u, m) > 0) {
  1059.         return m;
  1060.     }
  1061.     }
  1062.     return NONMTYPE;
  1063. }
  1064.  
  1065. int
  1066. supplies_here(unit, x, y, m)
  1067. Unit *unit;
  1068. int x, y, m;
  1069. {
  1070.     Unit *unit2;
  1071.  
  1072.     for_all_stack(x, y, unit2) {
  1073.     if (unit2 != unit
  1074.         && unit_trusts_unit(unit2, unit)
  1075.         && unit2->supply[m] > 0
  1076.         && um_outlength(unit2->type, m) >= 0) {
  1077.         return TRUE;
  1078.     }
  1079.     }
  1080.     return FALSE;
  1081. }
  1082.  
  1083. int
  1084. indep_captureable_here(x, y)
  1085. int x, y;
  1086. {
  1087.     int u2 = NONUTYPE, uview;
  1088.     Unit *unit2;
  1089.     Side *side = tmpunit->side, *side2 = NULL;
  1090.  
  1091.     if (units_visible(side, x, y)) {
  1092.     if ((unit2 = unit_at(x, y)) != NULL) {
  1093.         u2 = unit2->type;
  1094.         side2 = unit2->side;
  1095.     } else {
  1096.         return FALSE;
  1097.     }
  1098.     } else if (terrain_view(side, x, y) != UNSEEN
  1099.            && (uview = unit_view(side, x, y)) != EMPTY) {
  1100.     u2 = vtype(uview);
  1101.     side2 = side_n(vside(uview));
  1102.     } else {
  1103.     return FALSE;
  1104.     }
  1105.     return (is_unit_type(u2)
  1106.             && side2 == NULL
  1107.         && capture_chance(tmpunit->type, u2, side2) > 10);
  1108. }
  1109.  
  1110. /*  */
  1111.  
  1112. int
  1113. capture_indep_if_nearby(unit)
  1114. Unit *unit;
  1115. {
  1116.     int u = unit->type, range = 5;
  1117.     int x, y, rslt;
  1118.  
  1119.     if (!mobile(u))
  1120.       return FALSE;
  1121.     if (!could_capture_any(unit->type))
  1122.       return FALSE;
  1123.     tmpunit = unit;
  1124.     DMprintf("%s searching for easy capture within %d; found ",
  1125.          unit_desig(unit), range);
  1126.     rslt = search_around(unit->x, unit->y, range, indep_captureable_here,
  1127.              &x, &y, 1);
  1128.     if (rslt) {
  1129.     DMprintf("one at %d,%d\n", x, y);
  1130.     /* Set up a task to go after the unit found. */
  1131.     set_capture_task(unit, x, y);
  1132.     if (unit->transport
  1133.         && mobile(unit->transport->type)
  1134.         && unit->transport->plan) {
  1135.         set_move_near_task(unit->transport, x, y, 1);
  1136.     }
  1137.     return (execute_task(unit) != TASK_FAILED);
  1138.     } else {
  1139.     DMprintf("nothing\n");
  1140.     }
  1141.     return FALSE;
  1142. }
  1143.  
  1144. int
  1145. useful_captureable_here(x, y)
  1146. int x, y;
  1147. {
  1148.     int u2 = NONUTYPE, uview;
  1149.     Unit *unit2;
  1150.     Side *side = tmpunit->side, *oside = NULL;
  1151.  
  1152.     if (units_visible(side, x, y)) {
  1153.     for_all_stack(x, y, unit2) {
  1154.         u2 = unit2->type;
  1155.         oside = unit2->side;
  1156.             if (is_unit_type(u2)
  1157.         && !trusted_side(side, oside)
  1158.         && capture_chance(tmpunit->type, u2, oside) > 0
  1159.         && useful_type(side, u2)
  1160.         ) {
  1161.         tmputype = u2;
  1162.         return TRUE;
  1163.         }
  1164.     }
  1165.     } else if (terrain_view(side, x, y) != UNSEEN
  1166.            && (uview = unit_view(side, x, y)) != EMPTY) {
  1167.     u2 = vtype(uview);
  1168.     oside = side_n(vside(uview));
  1169.         if (is_unit_type(u2)
  1170.             && !trusted_side(side, oside)
  1171.         && capture_chance(tmpunit->type, u2, oside) > 0
  1172.         && useful_type(side, u2)
  1173.         ) {
  1174.         tmputype = u2;
  1175.         return TRUE;
  1176.     }
  1177.     }
  1178.     return FALSE;
  1179. }
  1180.  
  1181. /* Return true if the given type of unit is useful in some way to the
  1182.    given side.  This is almost always true. */
  1183.  
  1184. int
  1185. useful_type(side, u)
  1186. Side *side;
  1187. int u;
  1188. {
  1189.     if (!type_allowed_on_side(u, side))
  1190.       return FALSE;
  1191.     return TRUE;
  1192. }
  1193.  
  1194. /*  */
  1195.  
  1196. int
  1197. capture_useful_if_nearby(unit)
  1198. Unit *unit;
  1199. {
  1200.     int u = unit->type, range = 2;
  1201.     int x, y, rslt;
  1202.  
  1203.     if (!mobile(u))
  1204.       return FALSE;
  1205.     if (!could_capture_any(unit->type))
  1206.       return FALSE;
  1207.     tmpunit = unit;
  1208.     DMprintf("%s searching for useful capture within %d; found ",
  1209.          unit_desig(unit), range);
  1210.     rslt = search_around(unit->x, unit->y, range, useful_captureable_here,
  1211.              &x, &y, 1);
  1212.     if (rslt) {
  1213.     DMprintf("one at %d,%d\n", x, y);
  1214.     /* Set up a task to go after the unit found. */
  1215.     set_capture_task(unit, x, y);
  1216.     if (unit->transport
  1217.         && mobile(unit->transport->type)
  1218.         && unit->transport->plan) {
  1219.         set_move_near_task(unit->transport, x, y, 1);
  1220.     }
  1221.     return (execute_task(unit) != TASK_FAILED);
  1222.     } else {
  1223.     DMprintf("nothing\n");
  1224.     }
  1225.     return FALSE;
  1226. }
  1227.  
  1228. int
  1229. could_capture_any(u)
  1230. int u;
  1231. {
  1232.     int u2;
  1233.  
  1234.     for_all_unit_types(u2) {
  1235.     if (uu_capture(u, u2) > 0 || uu_indep_capture(u, u2) > 0)
  1236.       return TRUE;
  1237.     /* also check if u2 in game, on other side, etc? */
  1238.     }
  1239.     return FALSE;
  1240. }
  1241.  
  1242. /* This is a semi-testing routine that basically picks something for the
  1243.    unit to do without worrying about its validity.  The rest of the
  1244.    system should function correctly no matter what this thing comes up with.
  1245.    Piles of warnings are likely, but that's OK. */
  1246.  
  1247. /* (should actually have two modes for this - testing, which allows bad data,
  1248.    and normal usage with no garbage generated, which is used with unintelligent
  1249.    AIs) */
  1250.  
  1251. void
  1252. plan_random(unit)
  1253. Unit *unit;
  1254. {
  1255.     int dir, x1, y1, n;
  1256.     TaskType tasktype;
  1257.     Task *task;
  1258.     Action action;
  1259.     char *argtypestr;
  1260.  
  1261.     if (flip_coin()) {
  1262.     if (unit->plan->tasks) {
  1263.         execute_task(unit);
  1264.         return;
  1265.     }
  1266.     /* Pick a random task. */
  1267.     tasktype = xrandom((int) NUMTASKTYPES);
  1268.     switch (tasktype) {
  1269.       case TASK_NONE:
  1270.         task = create_task(tasktype);
  1271.         add_task(unit, CLEAR_AGENDA, task);
  1272.         break;
  1273.       case TASK_BUILD:
  1274.         task = create_build_task(xrandom(numutypes), xrandom(99));
  1275.         add_task(unit, CLEAR_AGENDA, task);
  1276.         break;
  1277.       case TASK_RESEARCH:
  1278.         task = create_task(tasktype);
  1279.         add_task(unit, CLEAR_AGENDA, task);
  1280.         break;
  1281.       case TASK_CAPTURE:
  1282.         dir = random_dir();
  1283.         point_in_dir(unit->x, unit->y, dir, &x1, &y1);
  1284.         set_capture_task(unit, x1, y1);
  1285.         break;
  1286.       case TASK_DO_ACTION:
  1287.         task = create_task(tasktype);
  1288.         add_task(unit, CLEAR_AGENDA, task);
  1289.         break;
  1290.       case TASK_HIT_POSITION:
  1291.         task = create_task(tasktype);
  1292.         add_task(unit, CLEAR_AGENDA, task);
  1293.         break;
  1294.       case TASK_HIT_UNIT:
  1295.         task = create_task(tasktype);
  1296.         add_task(unit, CLEAR_AGENDA, task);
  1297.         break;
  1298.       case TASK_MOVE_DIR:
  1299.         dir = random_dir();
  1300.         n = xrandom(10);
  1301.         set_move_dir_task(unit, dir, n);
  1302.         break;
  1303.       case TASK_MOVE_TO:
  1304.         dir = random_dir();
  1305.         point_in_dir(unit->x, unit->y, dir, &x1, &y1);
  1306.         set_move_to_task(unit, x1, y1);
  1307.         break;
  1308.       case TASK_OCCUPY:
  1309.         task = create_task(tasktype);
  1310.         add_task(unit, CLEAR_AGENDA, task);
  1311.         break;
  1312.       case TASK_PICKUP:
  1313.         task = create_task(tasktype);
  1314.         add_task(unit, CLEAR_AGENDA, task);
  1315.         break;
  1316.       case TASK_PRODUCE:
  1317.         if (nummtypes > 0) {
  1318.         task = create_produce_task(xrandom(nummtypes), xrandom(100));
  1319.         add_task(unit, CLEAR_AGENDA, task);
  1320.         }
  1321.         break;
  1322.       case TASK_REPAIR:
  1323.         task = create_task(tasktype);
  1324.         add_task(unit, CLEAR_AGENDA, task);
  1325.         break;
  1326.       case TASK_DISBAND:
  1327.         set_disband_task(unit);
  1328.         break;
  1329.       case TASK_RESUPPLY:
  1330.         set_resupply_task(unit, (flip_coin() ? xrandom(nummtypes) : NONMTYPE));
  1331.         break;
  1332.       case TASK_SENTRY:
  1333.         set_sentry_task(unit, xrandom(5));
  1334.         break;
  1335.       default:
  1336.         case_panic("task type", tasktype);
  1337.         break;
  1338.     }
  1339.     }
  1340.     if (unit->plan && unit->plan->tasks)
  1341.       return;
  1342.     /* Otherwise go for a random action. */
  1343.     memset(&action, 0, sizeof(Action));
  1344.     action.type = (ActionType) xrandom((int) NUMACTIONTYPES);
  1345.     argtypestr = actiondefns[(int) action.type].argtypes;
  1346.     make_plausible_random_args(argtypestr, 0, &(action.args[0]), unit);
  1347.     if (flip_coin()) {
  1348.     action.actee = unit->id;
  1349.     } else {
  1350.     while (find_unit(action.actee = xrandom(numunits)+1) == NULL
  1351.            && probability(98));
  1352.     }
  1353.     unit->act->nextaction = action;
  1354.     DMprintf("%s will randomly try %s\n",
  1355.          unit_desig(unit), action_desig(&action));
  1356. }
  1357.  
  1358. /* This attempts to make some vaguely plausible arguments for an action,
  1359.    using the types of each arg as a guide.  It also generates *invalid*
  1360.    arguments occasionally, which tests error checking in the actions' code. */
  1361.  
  1362. void
  1363. make_plausible_random_args(argtypestr, i, args, unit)
  1364. char *argtypestr;
  1365. int i;
  1366. short *args;
  1367. Unit *unit;
  1368. {
  1369.     char argch;
  1370.     int    slen, arg;
  1371.  
  1372.     slen = strlen(argtypestr);
  1373.     while (i < slen && i < 10) {
  1374.     argch = argtypestr[i];
  1375.     switch (argch) {
  1376.       case 'n':
  1377.         arg = (flip_coin() ? xrandom(10) :
  1378.            (flip_coin() ? xrandom(100) :
  1379.             (xrandom(20000) - 10000)));
  1380.         break;
  1381.       case 'u':
  1382.         /* Go a little outside range, so as to get some invalid types. */
  1383.         arg = xrandom(numutypes + 2) - 1;
  1384.         break;
  1385.       case 'm':
  1386.         arg = xrandom(nummtypes + 2) - 1;
  1387.         break;
  1388.       case 't':
  1389.         arg = xrandom(numttypes + 2) - 1;
  1390.         break;
  1391.       case 'x':
  1392.         arg = (unit != NULL && flip_coin() ? (unit->x + xrandom(5) - 2) :
  1393.            (xrandom(area.width + 4) - 2));
  1394.         break;
  1395.       case 'y':
  1396.         arg = (unit != NULL && flip_coin() ? (unit->y + xrandom(5) - 2) :
  1397.            (xrandom(area.height + 4) - 2));
  1398.         break;
  1399.       case 'z':
  1400.         arg = (flip_coin() ? 0 : xrandom(10));
  1401.         break;
  1402.       case 'd':
  1403.         arg = random_dir();
  1404.         break;
  1405.       case 'U':
  1406.         /* Cast around for a valid unit. */
  1407.         while (find_unit(arg = xrandom(numunits)+1) == NULL
  1408.            && probability(98));
  1409.         break;
  1410.       case 'S':
  1411.         arg = xrandom(numsides + 3) - 1;
  1412.         break;
  1413.       default:
  1414.         run_warning("Garbled action arg type '%c'\n", argch);
  1415.         arg = 0;
  1416.         break;
  1417.     }
  1418.     args[i++] = arg;
  1419.     }
  1420. }
  1421.  
  1422. /* This routine calculates a basic plan for the given unit. */
  1423.  
  1424. void
  1425. decide_plan(side, unit)
  1426. Side *side;
  1427. Unit *unit;
  1428. {
  1429.     /* (should be able to make plan object if missing) */
  1430.     if (side == NULL)
  1431.       return;
  1432.     DMprintf("%s deciding its plan", unit_desig(unit));
  1433.     if (side_has_ai(side)) {
  1434.         DMprintf(", using %s AI", side_desig(side));
  1435.         ai_decide_plan(side, unit);
  1436.         DMprintf(" - plan is now %s", plan_desig(unit->plan));
  1437.     }
  1438.     /* If the AI didn't decide anything, or if this is a human-run
  1439.        unit, then just say the unit will be following orders. */
  1440.     /* (doctrine should be able to ask for assortment of plans.) */
  1441.     if (unit->plan->type == PLAN_NONE) {
  1442.     if (side_has_display(side))  {
  1443.         DMprintf(", but will just be following orders");
  1444.         unit->plan->type = PLAN_PASSIVE;
  1445.         clear_task_agenda(unit->plan);
  1446.         /* Special-case cities in the intro game to automatically
  1447.            start producing infantry initially. */
  1448.         if (g_turn() <= 1
  1449.         && mainmodule != NULL
  1450.         && mainmodule->name != NULL
  1451.         && strcmp(mainmodule->name, "intro") == 0
  1452.         && strcmp(u_type_name(unit->type), "city") == 0) {
  1453.         push_build_task(unit, 0, 99);
  1454.         }
  1455.     } else {
  1456.         /* or PLAN_NONE? */
  1457.         unit->plan->type = PLAN_PASSIVE;
  1458.         clear_task_agenda(unit->plan);
  1459.         unit->plan->asleep = TRUE;
  1460.     }
  1461.     }
  1462.     DMprintf("\n");
  1463. }
  1464.  
  1465. int
  1466. doctrine_allows_wait(unit)
  1467. Unit *unit;
  1468. {
  1469.     int everask = 1 /* units_doctrine(unit, everaskside) */;
  1470.  
  1471.     return (everask);
  1472. }
  1473.  
  1474. /* Record the unit as waiting for orders about what to do. */
  1475.  
  1476. void
  1477. wait_for_orders(unit)
  1478. Unit *unit;
  1479. {
  1480.     if (!unit->plan->waitingfortasks)
  1481.       ++(unit->side->numwaiting);
  1482.     unit->plan->waitingfortasks = TRUE;
  1483. }
  1484.  
  1485. /* Random walking just attempts to move around. */
  1486.  
  1487. void
  1488. random_walk(unit)
  1489. Unit *unit;
  1490. {
  1491.     int dir = random_dir(), x1, y1, tries = 0;
  1492.  
  1493.     while (!interior_point_in_dir(unit->x, unit->y, dir, &x1, &y1)) {
  1494.         if (++tries > 500) {
  1495.         run_warning("something is wrong");
  1496.         break;
  1497.     }
  1498.     dir = random_dir();
  1499.     }
  1500.     set_move_to_task(unit, x1, y1);
  1501. }
  1502.  
  1503. /* Put a unit in reserve. */
  1504.  
  1505. void
  1506. reserve_unit(side, unit)
  1507. Side *side;
  1508. Unit *unit;
  1509. {
  1510.     if (unit->plan) {
  1511.     unit->plan->reserve = TRUE;
  1512.     if (unit->plan->waitingfortasks)
  1513.       --(unit->side->numwaiting);
  1514.     unit->plan->waitingfortasks = FALSE;
  1515.     update_unit_display(side, unit, TRUE);
  1516.     }
  1517. }
  1518.  
  1519. /* General routine to wake a unit up (and maybe all its cargo). */
  1520.  
  1521. void
  1522. wake_unit(unit, wakeocc, reason, unit2)
  1523. Unit *unit, *unit2;
  1524. int wakeocc, reason;
  1525. {
  1526.     Unit *occ;
  1527.  
  1528.     if (unit->plan) {
  1529.     unit->plan->asleep = FALSE;
  1530.     unit->plan->reserve = FALSE;
  1531.     /* (echo to interface?) */
  1532.     }
  1533.     if (wakeocc) {
  1534.     for_all_occupants(unit, occ)
  1535.       wake_unit(occ, wakeocc, reason, unit2);
  1536.     }
  1537.     /* (should do something with other args) */
  1538. }
  1539.  
  1540. /* The area wakeup. */
  1541.  
  1542. static int tmpflag;
  1543.  
  1544. static void
  1545. wake_at(x, y)
  1546. int x, y;
  1547. {
  1548.     Unit *unit;
  1549.  
  1550.     for_all_stack(x, y, unit) {
  1551.     if (side_controls_unit(tmpside, unit)) {
  1552.         wake_unit(unit, tmpflag, 0, NULL);
  1553.     }
  1554.     }
  1555. }
  1556.  
  1557. void
  1558. wake_area(side, x, y, n, occs)
  1559. Side *side;
  1560. int x, y, n, occs;
  1561. {
  1562.     tmpside = side;
  1563.     tmpflag = occs;
  1564.     apply_to_area(x, y, n, wake_at);
  1565. }
  1566.  
  1567. void
  1568. set_formation(unit, leader, x, y, dist, flex)
  1569. Unit *unit, *leader;
  1570. int x, y, dist, flex;
  1571. {
  1572.     Plan *plan = unit->plan;
  1573.     Goal *goal;
  1574.  
  1575.     if (plan == NULL)
  1576.       return;
  1577.     if (!in_play(unit))
  1578.       return;
  1579.     if (leader != NULL) {
  1580.     if (!in_play(leader))
  1581.       return;
  1582.     goal = create_goal(GOAL_KEEP_FORMATION, unit->side, TRUE);
  1583.     goal->args[0] = leader->id;
  1584.     } else {
  1585.     if (!inside_area(x, y))
  1586.       return;
  1587.     goal = create_goal(GOAL_KEEP_FORMATION, unit->side, TRUE);
  1588.     goal->args[0] = 0;
  1589.     }
  1590.     goal->args[1] = x;  goal->args[2] = y;
  1591.     goal->args[3] = dist;
  1592.     goal->args[4] = flex;
  1593.     plan->formation = goal;
  1594.     plan->funit = leader;
  1595. }
  1596.  
  1597. void
  1598. delay_unit(unit, flag)
  1599. Unit *unit;
  1600. int flag;
  1601. {
  1602.     if (in_play(unit) && unit->plan) {
  1603.     unit->plan->delayed = TRUE;
  1604.     }
  1605. }
  1606.  
  1607.  
  1608. /* Return the distance that we can go by shortest path before running out
  1609.    of important supplies.  Will return at least 1, since we can *always*
  1610.    move one cell to safety.  This is a worst-case routine, too complicated
  1611.    to worry about units getting refreshed by terrain or whatever. */
  1612.  
  1613. int
  1614. range_left(unit)
  1615. Unit *unit;
  1616. {
  1617.     int u = unit->type, m, least = 12345; /* bigger than any real value */
  1618.     
  1619.     for_all_material_types(m) {
  1620.     if (um_consumption_per_move(u, m) > 0) {
  1621.         least = min(least, unit->supply[m] / um_consumption_per_move(u, m));
  1622.     }
  1623. #if 0
  1624.     /* This code is too pessimistic if no account taken of supply line or
  1625.        production, so leave out for now. */
  1626.     if (um_base_consumption(u, m) > 0) {
  1627.         tmp = (u_speed(u) * unit->supply[m]) / um_base_consumption(u, m);
  1628.         least = min(least, tmp);
  1629.     }
  1630. #endif
  1631.     }
  1632.     return (least == 12345 ? 1 : least);
  1633. }
  1634.  
  1635. /* Estimate the goodness and badness of cells in the immediate vicinity. */
  1636.  
  1637. int
  1638. find_worths(range)
  1639. int range;
  1640. {
  1641.     return 0;
  1642. }
  1643.  
  1644. /* This is a heuristic estimation of the value of one unit type hitting */
  1645. /* on another.  Should take cost of production into account as well as the */
  1646. /* chance and significance of any effect. */
  1647.  
  1648. int
  1649. attack_worth(unit, e)
  1650. Unit *unit;
  1651. int e;
  1652. {
  1653.     int u = unit->type, worth;
  1654.  
  1655.     worth = uu_zz_bhw(u, e);
  1656.     /* Risk of death? */
  1657. /*    if (uu_damage(e, u) >= unit->hp)
  1658.     worth /= (could_capture(u, e) ? 1 : 4);
  1659.     if (could_capture(u, e)) worth *= 4; */
  1660.     return worth;
  1661. }
  1662.  
  1663. /* Support functions. */
  1664.  
  1665. /* Return true if the given position is threatened by the given unit type. */
  1666.  
  1667. int
  1668. threat(side, u, x0, y0)
  1669. Side *side;
  1670. int u, x0, y0;
  1671. {
  1672.     int d, x, y, thr = 0;
  1673.     Side *side2;
  1674.     int view;
  1675.  
  1676.     for_all_directions(d) {
  1677.         point_in_dir(x0, y0, d, &x, &y);
  1678.     view = 0 /* side_view(side, x, y) */;
  1679.     if (view != UNSEEN && view != EMPTY) {
  1680.         side2 = side_n(vside(view));
  1681.         if (allied_side(side, side2)) {
  1682.         if (uu_capture(u, vtype(view)) > 0) thr += 1000;
  1683.         if (uu_zz_bhw(u, vtype(view)) > 0) thr += 100;
  1684.         }
  1685.     }
  1686.     }
  1687.     return thr;
  1688. }
  1689.  
  1690. void
  1691. pop_task(plan)
  1692. Plan *plan;
  1693. {
  1694.     Task *oldtask;
  1695.  
  1696.     if (plan->tasks) {
  1697.     oldtask = plan->tasks;
  1698.     plan->tasks = plan->tasks->next;
  1699.     free_task(oldtask);
  1700.     }
  1701. }
  1702.  
  1703. int
  1704. react_to_enemies(unit)
  1705. Unit *unit;
  1706. {
  1707.     return (unit->plan ? TRUE : FALSE);
  1708. }
  1709.  
  1710. /* Patrol just does move_to, but cycling waypoints around when the first */
  1711. /* one has been reached. */
  1712.  
  1713. int
  1714. move_patrol(unit)
  1715. Unit *unit;
  1716. {
  1717. #if 0
  1718.     int tx, ty;
  1719.  
  1720.     if (unit->plan->orders.rept-- > 0) {
  1721.     if (unit->x == unit->plan->orders.p.pt[0].x &&
  1722.         unit->y == unit->plan->orders.p.pt[0].y) {
  1723.         tx = unit->plan->orders.p.pt[0].x;
  1724.         ty = unit->plan->orders.p.pt[0].y;
  1725.         unit->plan->orders.p.pt[0].x = unit->plan->orders.p.pt[1].x;
  1726.         unit->plan->orders.p.pt[0].y = unit->plan->orders.p.pt[1].y;
  1727.         unit->plan->orders.p.pt[1].x = tx;
  1728.         unit->plan->orders.p.pt[1].y = ty;
  1729.     }
  1730.     return move_to(unit, unit->plan->orders.p.pt[0].x, unit->plan->orders.p.pt[0].y,
  1731.                (unit->plan->orders.flags & SHORTESTPATH));
  1732.     }
  1733. #endif
  1734.     return TRUE;
  1735. }
  1736.  
  1737. /* Basic routine to compute how long a unit will take to build something. */
  1738.  
  1739. int
  1740. build_time(unit, prod)
  1741. Unit *unit;
  1742. int prod;
  1743. {
  1744.     int schedule = 1 /* uu_make(unit->type, prod) */;
  1745.     int u, research_delay = 0;
  1746.  
  1747.     /* Add penalty (or unpenalty!) for first unit of a type. */
  1748.     /* is "counts" a reliable way to test? */
  1749.     if (unit->side->counts[prod] <= 1) {
  1750. /*    research_delay = ((schedule * u_research(prod)) / 100);  */
  1751.     for_all_unit_types(u) {
  1752.         if (unit->side->counts[u] > 1) {
  1753.         research_delay -=
  1754.           (1 /*uu_make(unit->type, u)*/ * 
  1755.            uu_tech_crossover(prod, u)) / 100;
  1756.         }
  1757.         if (research_delay > 0) {
  1758.         schedule += research_delay;
  1759.         }
  1760.     }
  1761.     }
  1762.     return schedule;
  1763. }
  1764.  
  1765. int
  1766. clear_task_agenda(plan)
  1767. Plan *plan;
  1768. {
  1769.     int numcleared;
  1770.     Task *oldtask;
  1771.  
  1772.     if (plan == NULL || plan->tasks == NULL)
  1773.       return 0;
  1774.     numcleared = 0;
  1775.     while (plan->tasks != NULL) {
  1776.         oldtask = plan->tasks;
  1777.         plan->tasks = plan->tasks->next;
  1778.         free_task(oldtask);
  1779.         ++numcleared;
  1780.     }
  1781.     return numcleared;
  1782. }
  1783.  
  1784. Plan *
  1785. create_plan()
  1786. {
  1787.     Plan *plan = (Plan *) xmalloc(sizeof(Plan));
  1788.     return plan;
  1789. }
  1790.  
  1791. void 
  1792. free_plan(plan)
  1793. Plan *plan;
  1794. {
  1795.     if (plan == NULL)
  1796.       run_error("no plan here?");
  1797.     /* Make tasks available for reallocation. */
  1798.     clear_task_agenda(plan);
  1799.     free(plan);
  1800. }
  1801.  
  1802. /* Describe a plan succinctly. */
  1803.  
  1804. char *planbuf = NULL;
  1805.  
  1806. char *
  1807. plan_desig(plan)
  1808. Plan *plan;
  1809. {
  1810.     Task *task;
  1811.     int extra = 0;
  1812.  
  1813.     if (planbuf == NULL) planbuf = xmalloc(1000);
  1814.     if (plan == NULL) {
  1815.     sprintf(planbuf, "no plan");
  1816.     } else if (plan->type == PLAN_NONE) {
  1817.     sprintf(planbuf, "unformed plan");
  1818.     } else {
  1819.     if (plan->tasks) {
  1820.         tmpbuf[0] = '\0';
  1821.         for_all_tasks(plan, task) {
  1822.         if (strlen(tmpbuf) < 100) {
  1823.             strcat(tmpbuf, " ");
  1824.             strcat(tmpbuf, task_desig(task));
  1825.         } else {
  1826.             ++extra;
  1827.         }
  1828.         }
  1829.         if (extra > 0) {
  1830.         tprintf(tmpbuf, " ... %d more ...", extra);
  1831.         }
  1832.     } else {
  1833.         sprintf(tmpbuf, "no tasks");
  1834.     }
  1835.     sprintf(planbuf, "type %s %s",
  1836.         plantypenames[plan->type], goal_desig(plan->maingoal));
  1837.     if (plan->asleep)
  1838.       strcat(planbuf, " [asleep]");
  1839.     if (plan->reserve)
  1840.       strcat(planbuf, " [reserve]");
  1841.     if (plan->delayed)
  1842.       strcat(planbuf, " [delayed]");
  1843.     if (plan->waitingfortasks)
  1844.       strcat(planbuf, " [waiting for tasks]");
  1845.     if (plan->supply_alarm)
  1846.       strcat(planbuf, " [supply alarm]");
  1847.     if (plan->supply_is_low)
  1848.       strcat(planbuf, " [supply is low]");
  1849.     strcat(planbuf, tmpbuf);
  1850.     }
  1851.     return planbuf;
  1852. }
  1853.  
  1854. /* True if unit is in immediate danger of being captured. */
  1855. /* Needs check on capturer transport being seen. */
  1856.  
  1857. int
  1858. might_be_captured(unit)
  1859. Unit *unit;
  1860. {
  1861.     int d, x, y;
  1862.     Unit *unit2;
  1863.  
  1864.     for_all_directions(d) {
  1865.       if (interior_point_in_dir(unit->x, unit->y, d, &x, &y)) {
  1866.     if (((unit2 = unit_at(x, y)) != NULL) &&
  1867.         (enemy_side(unit->side, unit2->side)) &&
  1868.         (uu_capture(unit2->type, unit->type) > 0))
  1869.           return TRUE;
  1870.       }
  1871.     }
  1872.     return FALSE;
  1873. }
  1874.  
  1875. void
  1876. force_global_replan(side)
  1877. Side *side;
  1878. {
  1879.     Unit *unit;
  1880.     
  1881.     for_all_side_units(side, unit) {
  1882.     if (in_play(unit) && unit->plan != NULL) {
  1883.         unit->plan->type = PLAN_NONE;
  1884.         clear_task_agenda(unit->plan);
  1885.         unit->plan->asleep = FALSE;
  1886.         unit->plan->reserve = FALSE;
  1887.         unit->plan->delayed = FALSE;
  1888.     }
  1889.     }
  1890. }
  1891.  
  1892. /* Auxiliary functions for unit planning in Xconq. */
  1893.  
  1894. /* router flags */
  1895.  
  1896. #define SAMEPATH 1
  1897. #define EXPLORE_PATH 2
  1898.  
  1899. /* These macros are a cache used for planning purposes by machines. */
  1900.  
  1901. #define markloc(x, y) (set_tmp1_at(x, y, mark))
  1902.  
  1903. #define markedloc(x, y) (tmp1_at(x, y) == mark)
  1904.  
  1905. #define get_fromdir(x, y) (tmp2_at(x, y))
  1906.  
  1907. #define set_fromdir(x, y, dir) (set_tmp2_at(x, y, dir))
  1908.  
  1909. #define get_dist(x, y) (tmp3_at(x, y))
  1910.  
  1911. #define set_dist(x, y, d) (set_tmp3_at(x, y, d))
  1912.  
  1913. int
  1914. occupant_could_capture(unit, u2)
  1915. Unit *unit;
  1916. int u2;
  1917. {
  1918.     Unit *occ;
  1919.  
  1920.     for_all_occupants(unit, occ)
  1921.       if (uu_capture(occ->type, u2) > 0)
  1922.     return TRUE;
  1923.     return FALSE;
  1924. }
  1925.  
  1926. /* Check to see if there is anyone around to capture. */
  1927.  
  1928. int
  1929. can_capture_neighbor(unit)
  1930. Unit *unit;
  1931. {
  1932.     int d, x, y;
  1933.     int view;
  1934.     Side *side2;
  1935.  
  1936.     for_all_directions(d) {
  1937.       if (interior_point_in_dir(unit->x, unit->y, d, &x, &y)) {
  1938.     view = unit_view(unit->side, x, y);
  1939.     if (view != UNSEEN && view != EMPTY) {
  1940.         side2 = side_n(vside(view));
  1941.         if (!allied_side(unit->side, side2)) {
  1942.         if (uu_capture(unit->type, vtype(view)) > 0) {
  1943.             /* need some other way to change move order quickly */
  1944.             return TRUE;
  1945.         }
  1946.         }
  1947.     }
  1948.       }
  1949.     }
  1950.     return FALSE;
  1951. }
  1952.  
  1953. /* check if our first occupant can capture something.  Doesn't look at
  1954.    other occupants. */
  1955.  
  1956. int
  1957. occupant_can_capture_neighbor(unit)
  1958. Unit *unit;
  1959. {
  1960.     Unit *occ = unit->occupant;
  1961.  
  1962.     if (occ != NULL && occ->act && occ->act->acp > 0 && occ->side == unit->side) {
  1963.     if (can_capture_neighbor(occ)) {
  1964.         return TRUE;
  1965.     }
  1966.     }
  1967.     return FALSE;
  1968. }
  1969.  
  1970. /* Find the closes unit, first prefering bases, and then transports. */
  1971.  
  1972. int
  1973. find_closest_unit(side, x0, y0, maxdist, pred, rxp, ryp)
  1974. Side *side;
  1975. int x0, y0, maxdist, (*pred)(), *rxp, *ryp;
  1976. {
  1977. #if 0    
  1978.     Unit *unit;
  1979.     int u, dist;
  1980.     int found = FALSE;
  1981.  
  1982.     for_all_unit_types(u) {
  1983.     if (u_is_base(u)) {
  1984.         for (unit = NULL /* side_strategy(side)->unitlist[u]*/; unit != NULL; unit = unit->mlist) {
  1985.         if (alive(unit) &&
  1986.             (dist = distance(x0, y0, unit->x, unit->y)) <= maxdist) {
  1987.             if ((*pred)(unit->x, unit->y)) {
  1988.             maxdist = dist - 1;
  1989.             *rxp = unit->x;  *ryp = unit->y;
  1990.             found = TRUE;
  1991.             }
  1992.         }
  1993.         }
  1994.     }
  1995.     }
  1996.     if (found) {
  1997.     return TRUE;
  1998.     }
  1999.     for_all_unit_types(u) {
  2000.     if (!u_is_base(u) && u_is_transport(u)) {
  2001.         for (unit = NULL /*side_strategy(side)->unitlist[u]*/; unit != NULL; unit = unit->mlist) {
  2002.         if (alive(unit)
  2003.             && distance(x0, y0, unit->x, unit->y) <= maxdist) {
  2004.             if ((*pred)(unit->x, unit->y)) {
  2005.             maxdist = dist - 1;
  2006.             *rxp = unit->x;  *ryp = unit->y;
  2007.             found = TRUE;
  2008.             }
  2009.         }
  2010.         }
  2011.     }
  2012.     }
  2013.     if (found) {
  2014.     return TRUE;
  2015.     }
  2016.     /* (What's the point of finding a non-base/non-transport?) */
  2017.     for_all_unit_types(u) {
  2018.     if (!u_is_base(u) && !u_is_transport(u)) {
  2019.         for (unit = NULL/*side_strategy(side)->unitlist[u]*/; unit != NULL; unit = unit->mlist) {
  2020.         if (alive(unit)
  2021.             && distance(x0, y0, unit->x, unit->y) <= maxdist) {
  2022.             if ((*pred)(unit->x, unit->y)) {
  2023.             maxdist = dist - 1;
  2024.             *rxp = unit->x;  *ryp = unit->y;
  2025.             found = TRUE;
  2026.             }
  2027.         }
  2028.         }
  2029.     }
  2030.     }
  2031.     if (found) {
  2032.     return TRUE;
  2033.     }
  2034. #endif
  2035.     return FALSE;
  2036. }
  2037.  
  2038. /* True if the given unit is a sort that can build other units. */
  2039.  
  2040. int
  2041. can_build(unit)
  2042. Unit *unit;
  2043. {
  2044.     int u2;
  2045.  
  2046.     for_all_unit_types(u2) {
  2047.     if (could_create(unit->type, u2))
  2048.       return TRUE;
  2049.     }
  2050.     return FALSE;
  2051. }
  2052.  
  2053. int
  2054. can_build_or_help(unit)
  2055. Unit *unit;
  2056. {
  2057.     int u2;
  2058.  
  2059.     for_all_unit_types(u2) {
  2060.     if (could_create(unit->type, u2)
  2061.         || uu_acp_to_build(unit->type, u2) > 0
  2062.         || uu_acp_to_research(unit->type, u2) > 0)
  2063.       return TRUE;
  2064.     }
  2065.     return FALSE;
  2066. }
  2067.  
  2068. int
  2069. can_produce(unit)
  2070. Unit *unit;
  2071. {
  2072.     int m;
  2073.  
  2074.     for_all_material_types(m) {
  2075.     if (um_acp_to_produce(unit->type, m))
  2076.       return TRUE;
  2077.     }
  2078.     return FALSE;
  2079. }
  2080.  
  2081.  
  2082. /* Test if unit can move out into adjacent cells. */
  2083.  
  2084. int
  2085. can_move(unit)
  2086. Unit *unit;
  2087. {
  2088.     int d, x, y;
  2089.  
  2090.     for_all_directions(d) {
  2091.     if (interior_point_in_dir(unit->x, unit->y, d, &x, &y)) {
  2092.         /* (should account for world-leaving options?) */
  2093.         if (could_live_on(unit->type, terrain_at(x, y)))
  2094.           return TRUE;
  2095.     }
  2096.     }
  2097.     return FALSE;
  2098. }
  2099.  
  2100. /* Returns the type of missing supplies. Not great routine if first */
  2101. /* material is a type of ammo. */
  2102.  
  2103. int
  2104. out_of_ammo(unit)
  2105. Unit *unit;
  2106. {
  2107.     int u = unit->type, r;
  2108.  
  2109.     for_all_material_types(r) {
  2110.     if (um_consumption_per_attack(u, r) > 0 && unit->supply[r] <= 0)
  2111.         return r;
  2112.     }
  2113.     return (-1);
  2114. }
  2115.  
  2116. /* Check how long a unit can sit where it is */
  2117.  
  2118. int
  2119. survival_time(unit)
  2120. Unit *unit;
  2121. {
  2122.     int u = unit->type, m, least = 99999, rate, tmp;
  2123.     int t = terrain_at(unit->x, unit->y);
  2124.  
  2125.     for_all_material_types(m) {
  2126.     rate = (um_base_consumption(u, m)
  2127.         - (um_base_production(u, m) * ut_productivity(u, t)) / 100);
  2128.     if (rate > 0) {
  2129.         tmp = unit->supply[m];
  2130.         if (unit->act) {
  2131.         tmp += unit->act->actualmoves * um_consumption_per_move(u, m);
  2132.         }
  2133.         least = min(least, tmp / rate);
  2134.     }
  2135.     }
  2136.     return least;
  2137. }
  2138.  
  2139. int
  2140. usable_cell(unit, x, y)
  2141. Unit *unit;
  2142. int x, y;
  2143. {
  2144.     int u = unit->type;
  2145.     int view = unit_view(unit->side, x, y);
  2146.     
  2147.     return (((view == EMPTY) || view == UNSEEN ||
  2148.         (allied_side(side_n(vside(view)),unit->side) &&
  2149.          could_carry(vtype(view), u))) &&
  2150.            could_live_on(u, terrain_at(x, y)));
  2151. }
  2152.  
  2153. Task *explorechain;
  2154.  
  2155. int
  2156. explorable_cell(x, y)
  2157. int x, y;
  2158. {
  2159.     return (terrain_view(tmpside, x, y) == UNSEEN);
  2160. }
  2161.  
  2162. int
  2163. reachable_unknown(x, y)
  2164. int x, y;
  2165. {
  2166.     if (!inside_area(x, y))
  2167.       return FALSE;
  2168.     if (terrain_view(tmpside, x, y) == UNSEEN) {
  2169.         if (adj_known_ok_terrain(x, y, tmpside, tmpunit->type)) {
  2170.         return TRUE;
  2171.     } else {
  2172.         return FALSE;
  2173.     }
  2174.     } else {
  2175.     return FALSE;
  2176.     }
  2177. }
  2178.  
  2179. /* Test whether the given location has an adjacent cell that is ok for
  2180.    the given type to be out in the open. */
  2181.  
  2182. int
  2183. adj_known_ok_terrain(x, y, side, u)
  2184. int x, y, u;
  2185. Side *side;
  2186. {
  2187.     int dir, x1, y1, t;
  2188.  
  2189.     if (!inside_area(x, y) || side == NULL)
  2190.       return FALSE;
  2191.     for_all_directions(dir) {
  2192.     if (interior_point_in_dir(x, y, dir, &x1, &y1)) {
  2193.         if (terrain_view(side, x1, y1) == UNSEEN)
  2194.           continue;
  2195.         t = terrain_at(x1, y1);
  2196.         if (!terrain_always_impassable(u, t))
  2197.           return TRUE;
  2198.     }
  2199.     }
  2200.     return FALSE;
  2201. }
  2202.  
  2203. /* Go to the nearest cell that we can see how to get to. */
  2204.  
  2205. int
  2206. explore_reachable_cell(unit, range)
  2207. Unit *unit;
  2208. int range;
  2209. {
  2210.     int x, y;
  2211.  
  2212.     if (all_see_all || g_terrain_seen())
  2213.       return FALSE;
  2214.     tmpunit = unit;
  2215.     tmpside = unit->side;
  2216.     DMprintf("%s searching within %d for cell to explore -", unit_desig(unit), range);
  2217.     if (search_around(unit->x, unit->y, range, reachable_unknown, &x, &y, 1)) {
  2218.     set_move_near_task(unit, x, y, 1);
  2219.     DMprintf("found one at %d,%d\n", x, y);
  2220.     return TRUE;
  2221.     }
  2222.     DMprintf("found nothing\n");
  2223.     return FALSE;
  2224. }
  2225.  
  2226. /* Check for any makers this unit should be capturing. */
  2227.  
  2228. int
  2229. should_capture_maker(unit)
  2230. Unit *unit;
  2231. {
  2232.     return 0;
  2233. }
  2234.  
  2235. #if 0
  2236. /* Returns true if the given unit can't leave its cell for some reason. */
  2237.  
  2238. int
  2239. no_possible_moves(unit)
  2240. Unit *unit;
  2241. {
  2242.     int fx = unit->x, fy = unit->y, ut = unit->type;
  2243.     int d, x, y;
  2244.     int view;
  2245.     Side *side = unit->side;
  2246.  
  2247.     for_all_directions(d) {
  2248.     x = wrapx(fx + dirx[d]);  y = limit(fy + diry[d]);
  2249.     view = unit_view(side, x, y);
  2250.     if (view == EMPTY) {
  2251.         if (could_move(ut, terrain_at(x, y)))
  2252.           return FALSE;
  2253.     } else if (enemy_side(side_n(vside(view)) , side)
  2254.            && could_hit(ut, vtype(view))) {
  2255.         return FALSE;
  2256.     } else if (could_carry(vtype(view), ut) &&
  2257.            allied_side(side_n(vside(view)), side))
  2258.       return FALSE;
  2259.     }
  2260.     return TRUE;
  2261. }
  2262. #endif
  2263.  
  2264. /* Estimate the usual number of turns to finish construction. */
  2265.  
  2266. int
  2267. normal_completion_time(u, u2)
  2268. int u, u2;
  2269. {
  2270.     if (u_acp(u) == 0 || uu_cp_per_build(u, u2) == 0)
  2271.       return (-1);
  2272.     return (u_cp(u2) - uu_creation_cp(u, u2)) /
  2273.       (uu_cp_per_build(u, u2) * u_acp(u));
  2274. }
  2275.  
  2276.  
  2277. /* True if anybody at all is on any adjacent cell. */
  2278.  
  2279. int
  2280. adj_unit(x, y)
  2281. int x, y;
  2282. {
  2283.     int d, x1, y1;
  2284.  
  2285.     for_all_directions(d) {
  2286.     if (interior_point_in_dir(x, y, d, &x1, &y1)) {
  2287.         if (unit_at(x1, y1))
  2288.           return TRUE;
  2289.     }
  2290.     }
  2291.     return FALSE;
  2292. }
  2293.  
  2294. /* A unit runs low on supplies at the halfway point.  Formula is the same
  2295.    no matter how/if occupants eat transports' supplies. */
  2296.  
  2297. int
  2298. past_halfway_point(unit)
  2299. Unit *unit;
  2300. {
  2301.     int u = unit->type, m;
  2302.  
  2303.     for_all_material_types(m) {
  2304.     if (((um_base_consumption(u, m) > 0) || (um_consumption_per_move(u, m) > 0)) &&
  2305.         /* should check that the transport is adequate for supplying the fuel */ 
  2306.         (unit->transport == NULL)) {
  2307.         if (2 * unit->supply[m] <= um_storage_x(u, m))
  2308.           return TRUE;
  2309.     }
  2310.     }
  2311.     return FALSE;
  2312. }
  2313.  
  2314.  
  2315. /* This is the maximum distance from "home" that a unit can expect to get,
  2316.    travelling on its most hostile terrain type. */
  2317.  
  2318. int
  2319. operating_range_worst(u)
  2320. int u;
  2321. {
  2322.     int m, t, prod, range, worstrange = area.maxdim;
  2323.  
  2324.     for_all_material_types(m) {
  2325.         if (um_base_consumption(u, m) > 0) {
  2326.         for_all_terrain_types(t) {
  2327.             if (!terrain_always_impassable(u, t)) {
  2328.                 prod = (um_base_production(u, m) * ut_productivity(u, t)) / 100;
  2329.                 if (prod < um_base_consumption(u, m)) {
  2330.             range = um_storage_x(u, m) / (um_base_consumption(u, m) - prod);
  2331.             if (range < worstrange)
  2332.               worstrange = range;
  2333.             }
  2334.         }
  2335.         }
  2336.     }
  2337.     }
  2338.     return worstrange;
  2339. }
  2340.  
  2341. /* Same, but for best terrain. */
  2342.  
  2343. int
  2344. operating_range_best(u)
  2345. int u;
  2346. {
  2347.     int m, t, prod, range, tbestrange, tbest = 0, bestrange = 0;
  2348.     int moves, consump;
  2349.  
  2350.     for_all_terrain_types(t) {
  2351.     if (!terrain_always_impassable(u, t)) {
  2352.         tbestrange = area.maxdim;
  2353.         for_all_material_types(m) {
  2354.         consump = 0;
  2355.         moves = (u_acp(u) * u_speed(u)) / 100;
  2356.         if (um_consumption_per_move(u, m) > 0) {
  2357.             consump = moves * um_consumption_per_move(u, m);
  2358.         }
  2359.         if (moves <= 0)
  2360.           moves = 1;
  2361.         if (um_base_consumption(u, m) > 0) {
  2362.             consump = max(consump, um_base_consumption(u, m));
  2363.         }
  2364.             prod = (um_base_production(u, m) * ut_productivity(u, t)) / 100;
  2365.             if (prod > 0) {
  2366.             consump = max(0, consump - prod);
  2367.         }
  2368.         if (consump > 0) {
  2369.             range = (um_storage_x(u, m) * moves) / consump;
  2370.             if (range < tbestrange)
  2371.               tbestrange = range;
  2372.         }
  2373.         }
  2374.         if (tbestrange > bestrange) {
  2375.         bestrange = tbestrange;
  2376.         tbest = t;
  2377.         }
  2378.     }
  2379.     }
  2380.     return bestrange;
  2381. }
  2382.  
  2383. int
  2384. terrain_always_impassable(u, t)
  2385. int u, t;
  2386. {
  2387.     if (ut_vanishes_on(u, t))
  2388.       return TRUE;
  2389.     if (ut_wrecks_on(u, t))
  2390.       return TRUE;
  2391.     if (ut_mp_to_enter(u, t) > u_acp(u))
  2392.       return TRUE;
  2393.     return FALSE;
  2394. }
  2395.  
  2396. void
  2397. dispose_of_plan(unit)
  2398. Unit *unit;
  2399. {
  2400.     /* Might not be anything to dispose of. */
  2401.     if (unit->plan == NULL)
  2402.       return;
  2403.     free_plan(unit->plan);
  2404.     unit->plan = NULL;
  2405. }
  2406.