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 / task.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  51.0 KB  |  2,056 lines  |  [TEXT/R*ch]

  1. /* Unit task execution and general task functions.
  2.    Copyright (C) 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. /* This is the number of tasks to allocate initially.  More will always be
  12.    allocated as needed, so this should be a "reasonable" value. */
  13.  
  14. #ifndef INITMAXTASKS
  15. #define INITMAXTASKS 100
  16. #endif
  17.  
  18. #define CLEAR_AGENDA 99
  19.  
  20. static int compare_directions PARAMS ((const void *a0, const void *a1));
  21. static int test_for_buildable PARAMS ((int x, int y));
  22.  
  23. /* Declare all the task functions. */
  24.  
  25. #undef  DEF_TASK
  26. #define DEF_TASK(name,code,argtypes,FN)  \
  27.   static TaskOutcome FN PARAMS ((Unit *unit, Task *task));
  28.  
  29. #include "task.def"
  30.  
  31. /* Array of descriptions of task types. */
  32.  
  33. TaskDefn taskdefns[] = {
  34.  
  35. #undef  DEF_TASK
  36. #define DEF_TASK(NAME,code,ARGTYPES,FN) { NAME, ARGTYPES, FN },
  37.  
  38. #include "task.def"
  39.  
  40.     { NULL, NULL, NULL }
  41. };
  42.  
  43. /* The list of available task objects. */
  44.  
  45. Task *freetasks;
  46.  
  47. /* Pointer to a buffer that task debug info goes into. */
  48.  
  49. char *taskbuf;
  50.  
  51. static int tmpbuildutype;
  52.  
  53. static Unit *tmpbuilder, *tmpbuildunit;
  54.  
  55. /* Allocate an initial collection of task objects. */
  56.  
  57. void
  58. init_tasks()
  59. {
  60.     allocate_task_block();
  61. }
  62.  
  63. /* Allocate a new block of tasks. */
  64.  
  65. void
  66. allocate_task_block()
  67. {
  68.     int i;
  69.  
  70.     freetasks = (Task *) xmalloc(INITMAXTASKS * sizeof(Task));
  71.     /* Chain the tasks together. */
  72.     for (i = 0; i < INITMAXTASKS; ++i) {
  73.     freetasks[i].next = &freetasks[i+1];
  74.     }
  75.     freetasks[INITMAXTASKS-1].next = NULL;
  76. }
  77.  
  78. /* Create and return a new task. */
  79.  
  80. Task *
  81. create_task(type)
  82. TaskType type;
  83. {
  84.     int i;
  85.     Task *task;
  86.  
  87.     /* Scarf up some more memory if we need it. */
  88.     if (freetasks == NULL) {
  89.     allocate_task_block();
  90.     }
  91.     /* Peel off a task from the free list. */
  92.     task = freetasks;
  93.     freetasks = task->next;
  94.     /* Reset its slots. */
  95.     task->type = type;
  96.     task->execnum = 0;
  97.     task->retrynum = 0;
  98.     for (i = 0; i < MAXTASKARGS; ++i)
  99.       task->args[i] = 0;
  100.     task->next = NULL;
  101.     return task;
  102. }
  103.  
  104. Task *
  105. clone_task(oldtask)
  106. Task *oldtask;
  107. {
  108.     int i;
  109.     Task *newtask;
  110.  
  111.     newtask = create_task(oldtask->type);
  112.     /* Probably not a good idea to copy exec/retry counts, skip them. */
  113.     for (i = 0; i < MAXTASKARGS; ++i)
  114.       newtask->args[i] = oldtask->args[i];
  115.     return newtask;
  116. }
  117.  
  118. /* The empty task always succeeds immediately. */
  119.  
  120. static TaskOutcome
  121. do_none_task(unit, task)
  122. Unit *unit;
  123. Task *task;
  124. {
  125.     return TASK_IS_COMPLETE;
  126. }
  127.  
  128. static int
  129. test_for_buildable(x, y)
  130. int x, y;
  131. {
  132.     Unit *unit;
  133.  
  134.     for_all_stack(x, y, unit) {
  135.     if (in_play(unit)
  136.         && !fullsized(unit)
  137.         && unit->type == tmpbuildutype
  138.         && unit->side == tmpbuilder->side) {
  139.         tmpbuildunit = unit;
  140.         return TRUE;
  141.     }
  142.     }
  143.     return FALSE;
  144. }
  145.  
  146. /* The build task handles the research, tooling up, creation, and completion
  147.    for a given number of units of a given type. */
  148.  
  149. static TaskOutcome
  150. do_build_task(unit, task)
  151. Unit *unit;
  152. Task *task;
  153. {
  154.     int u = unit->type, dir, nx, ny, tp;
  155.     int x = unit->x, y = unit->y;
  156.     int u2 = task->args[0], run = task->args[3];
  157.     Unit *unit2 = NULL;
  158.     Side *us = unit->side;
  159.  
  160.     /* First see if we've already built all the units requested. */
  161.     if (task->args[2] >= run) {
  162.         return TASK_IS_COMPLETE;
  163.     }
  164.     /* See if our technology needs improvement in order to build this type. */
  165.     if (is_unit_type(u2)
  166.     && u_tech_to_build(u2) > 0
  167.         && us->tech[u2] < u_tech_to_build(u2)) {
  168.         if (uu_acp_to_research(u, u2) > 0) {
  169.         if (valid(check_research_action(unit, unit, u2))) {
  170.         prep_research_action(unit, unit, u2);
  171.         return TASK_PREPPED_ACTION;
  172.         } else {
  173.         /* We get three trys to research before giving up. */
  174.             return (task->execnum < 3 ? TASK_IS_INCOMPLETE : TASK_FAILED);
  175.         }
  176.         } else {
  177.         /* Can't do the necessary research. */
  178.         return TASK_FAILED;
  179.         }
  180.     }
  181.     /* See if we need to toolup to work on this type. */
  182.     if (is_unit_type(u2)) {
  183.     tp = (unit->tooling ? unit->tooling[u2] : 0);
  184.     if (tp < uu_tp_to_build(u, u2)) {
  185.         if (uu_acp_to_toolup(u, u2) > 0) {
  186.         if (valid(check_toolup_action(unit, unit, u2))) {
  187.             prep_toolup_action(unit, unit, u2);
  188.             return TASK_PREPPED_ACTION;
  189.         } else {
  190.             /* We get three trys to toolup before giving up. */
  191.             return (task->execnum < 3 ? TASK_IS_INCOMPLETE : TASK_FAILED);
  192.         }
  193.         } else {
  194.         /* Can't do the necessary toolup. */
  195.         return TASK_FAILED;
  196.         }
  197.     }
  198.     }
  199.     /* Check out the unit supposedly in progress. */
  200.     if (task->args[1] != 0) {
  201.     unit2 = find_unit(task->args[1]);
  202.     if (in_play(unit2) && unit2->type == u2) {
  203.         if (fullsized(unit2)) {
  204.         ++(task->args[2]);
  205.         if (task->args[2] >= run) {
  206.             return TASK_IS_COMPLETE;
  207.         }
  208.         }
  209.     }
  210.     }
  211.  
  212.     /* Find something to work on */
  213.     unit2 = find_unit_to_complete(unit, task);
  214.  
  215.     /* No incomplete unit found, so try to create one. */
  216.     if (unit2 == NULL) {
  217.     if (valid(check_create_in_action(unit, unit, u2, unit))) {
  218.         prep_create_in_action(unit, unit, u2, unit);
  219.         return TASK_PREPPED_ACTION;
  220.     } else if (valid(check_create_at_action(unit, unit, u2, x, y, 0))) {
  221.         prep_create_at_action(unit, unit, u2, x, y, 0);
  222.         return TASK_PREPPED_ACTION;
  223.     } else {
  224.         /* Try creating in an adjacent cell. */
  225.         for_all_directions(dir) {
  226.         if (interior_point_in_dir(x, y, dir, &nx, &ny)
  227.             && valid(check_create_at_action(unit, unit, u2, nx, ny, 0))) {
  228.             prep_create_at_action(unit, unit, u2, nx, ny, 0);
  229.             return TASK_PREPPED_ACTION;
  230.         }
  231.         }
  232.         return TASK_FAILED;
  233.     }
  234.     } else {
  235.     /* Record the unit's id for use the next time around. */
  236.     task->args[1] = unit2->id;
  237.     }
  238.     /* We have an incomplete unit to work on, try to do a build action. */
  239.     if (valid(check_build_action(unit, unit, unit2))) {
  240.     prep_build_action(unit, unit, unit2);
  241.     return TASK_PREPPED_ACTION;
  242.     } else {
  243.     /* Try three times before giving up. */
  244.     return (task->execnum < 3 ? TASK_IS_INCOMPLETE : TASK_FAILED);
  245.     }
  246. }
  247.  
  248. Unit *
  249. find_unit_to_complete(unit, task)
  250. Unit *unit;
  251. Task *task;
  252. {
  253.     Unit *occ;
  254.     int u = unit->type, nx, ny, range;
  255.     int u2 = task->args[0];
  256.     int x = unit->x, y = unit->y;
  257.  
  258.     /* Check out the unit supposedly in progress. */
  259.     if (task->args[1] != 0) {
  260.     occ = find_unit(task->args[1]);
  261.     if (in_play(occ) && occ->type == u2 && !fullsized(occ)) 
  262.       return occ;
  263.     }
  264.     /* Maybe search for any appropriate incomplete occupants. */
  265.     for_all_occupants(unit, occ) {
  266.     if (in_play(occ)
  267.         && !fullsized(occ)
  268.         && occ->type == u2
  269.         && occ->side == unit->side) 
  270.       return(occ);
  271.     }
  272.     /* Or else search for any appropriate incomplete units in this cell. */
  273.     for_all_stack(x, y, occ) {
  274.     if (in_play(occ)
  275.         && !fullsized(occ)
  276.         && occ->type == u2
  277.         && occ->side == unit->side) {
  278.         return (occ);
  279.         }
  280.     }
  281.     /* Or else search nearby area. */
  282.     if (is_unit_type(u2)) {
  283.     range = uu_build_range(u, u2);
  284.     if (range > 0) {
  285.         tmpbuilder = unit;
  286.         tmpbuildutype = u2;
  287.         if (search_around(x, y, range, test_for_buildable, &nx, &ny, 1)) {
  288.             return(tmpbuildunit);
  289.         }
  290.     }
  291.     }
  292.     /* nothing found */
  293.     return NULL;
  294. }
  295.  
  296. /* This is a "pure research" task, with the sole objective of increasing
  297.    technology. */
  298.  
  299. static TaskOutcome
  300. do_research_task(unit, task)
  301. Unit *unit;
  302. Task *task;
  303. {
  304.     int u = unit->type;
  305.     int u2 = task->args[0], lev = task->args[1];
  306.     Side *us = unit->side;
  307.  
  308.     /* Independents can never ever do research. */
  309.     if (us == NULL)
  310.       return TASK_FAILED;
  311.     if (us->tech[u2] > u_tech_max(u2))
  312.       return TASK_FAILED; /* actually an error */
  313.     if (us->tech[u2] >= lev)
  314.       return TASK_IS_COMPLETE;
  315.     if (uu_acp_to_research(u, u2) <= 0)
  316.       return TASK_FAILED;
  317.     if (valid(check_research_action(unit, unit, u2))) {
  318.     prep_research_action(unit, unit, u2);
  319.     return TASK_PREPPED_ACTION;
  320.     } else {
  321.     /* We get three tries to research before giving up. */
  322.     return (task->execnum < 3 ? TASK_IS_INCOMPLETE : TASK_FAILED);
  323.     }
  324. }
  325.  
  326. /* This is to capture a given type/side of unit at a given place. */
  327.  
  328. static TaskOutcome
  329. do_capture_task(unit, task)
  330. Unit *unit;
  331. Task *task;
  332. {
  333.     int u = unit->type, tx, ty, tu2, ts2, dist, movedist, rslt;
  334.     Unit *unit2;
  335.     Side *us = unit->side;
  336.  
  337.     /* (should be able to say how hard to try) */
  338.     tx = task->args[0];  ty = task->args[1];
  339.     tu2 = task->args[2];
  340.     ts2 = task->args[3];
  341.     dist = distance(tx, ty, unit->x, unit->y);
  342.     switch (dist) {
  343.       case 0:
  344.       case 1:
  345.     for_all_stack(tx, ty, unit2) {
  346.         if ((ts2 >= 0 ?
  347.          (side_number(unit2->side) == ts2) :
  348.          (unit2->side != us /* should be "not a friendly side" */))
  349.         && (tu2 == NONUTYPE || tu2 == unit->type)) {
  350.         if (valid(check_capture_action(unit, unit, unit2))) {
  351.             prep_capture_action(unit, unit, unit2);
  352.             return TASK_PREPPED_ACTION;
  353.         } else if (valid(check_attack_action(unit, unit, unit2, 100))) {
  354.             prep_attack_action(unit, unit, unit2, 100);
  355.             return TASK_PREPPED_ACTION;
  356.         } else {
  357.             /* We get several tries to capture before giving up. */
  358.             unit->plan->reserve = TRUE;
  359.             return (task->execnum < 5 ? TASK_IS_INCOMPLETE : TASK_FAILED);
  360.         }
  361.         }
  362.     }
  363.     /* Nothing was here to capture. */
  364.     return TASK_IS_COMPLETE;
  365.       default:
  366.     /* If on mobile transport, let it handle things. */
  367.     if (unit->transport != NULL
  368.         && mobile(unit->transport->type)
  369.         /* and the transport is not blocked */
  370.         && flip_coin()) {
  371.         return TASK_IS_INCOMPLETE;
  372.     }
  373.     /* If out of range and can move, push a task to get closer (maybe). */
  374.     if (mobile(u) && flip_coin()) {
  375.         movedist = max(1 /* attack range */, u_range(u));
  376.         if (dist > movedist + u_acp(u) /* or dist that could be covered in 1-2 turns */) {
  377.         movedist = dist - max(1, (dist - movedist) / 4);
  378.         /* We're too far away to capture directly, add a move-to
  379.            task. */
  380.         push_move_near_task(unit, tx, ty, movedist);
  381.         return TASK_IS_INCOMPLETE;
  382.         }
  383.     }
  384.     return TASK_FAILED;
  385.     }
  386. }
  387.  
  388. /* The disband task's purpose is to make the unit disappear, so just keep doing
  389.    actions; when the unit goes away, so will the task. */
  390.  
  391. static TaskOutcome
  392. do_disband_task(unit, task)
  393. Unit *unit;
  394. Task *task;
  395. {
  396.     if (valid(check_disband_action(unit, unit))) {
  397.     prep_disband_action(unit, unit);
  398.     return TASK_PREPPED_ACTION;
  399.     } else {
  400.     /* (should try to find a nearby unit to do it?) */
  401.     return (task->execnum < 5 ? TASK_IS_INCOMPLETE : TASK_FAILED);
  402.     }
  403. }
  404.  
  405. /* This task just attempts to do the explicitly specified action repeatedly. */
  406.  
  407. static TaskOutcome
  408. do_action_task(unit, task)
  409. Unit *unit;
  410. Task *task;
  411. {
  412.     int i;
  413.  
  414.     if (task->args[0] > 0) {
  415.     --(task->args[0]);
  416.         if (unit->act == NULL)
  417.           return TASK_FAILED;
  418.         unit->act->nextaction.type = task->args[1];
  419.         for (i = 0; i < MAXACTIONARGS; ++i) {
  420.         unit->act->nextaction.args[i] = task->args[i + 2];
  421.         }
  422.         /* act on self always? */
  423.         unit->act->nextaction.actee = unit->id;
  424.     return TASK_PREPPED_ACTION;
  425.     } else {
  426.     return TASK_IS_COMPLETE;
  427.     }
  428. }
  429.  
  430. static TaskOutcome
  431. do_hit_position_task(unit, task)
  432. Unit *unit;
  433. Task *task;
  434. {
  435.     int u = unit->type, tx, ty, dist;
  436.  
  437.     /* This is to hit a given place. */
  438.     /* (ask for a number of hits?) */
  439.     tx = task->args[0];  ty = task->args[1];
  440.     dist = distance(tx, ty, unit->x, unit->y);
  441.     if (valid(check_fire_into_action(unit, unit, tx, ty, 0, -1))) {
  442.     prep_fire_into_action(unit, unit, tx, ty, 0, -1);
  443.     return TASK_PREPPED_ACTION;
  444.     } else if (mobile(u) && flip_coin()) {
  445.     /* We're too far away to shoot directly, add a move-to task. */
  446.     push_move_near_task(unit, tx, ty, max(1 /* attack range */, u_range(u)));
  447.     return TASK_IS_INCOMPLETE;
  448.     }
  449.     return TASK_FAILED;
  450. }
  451.  
  452. static TaskOutcome
  453. do_hit_unit_task(unit, task)
  454. Unit *unit;
  455. Task *task;
  456. {
  457.     int u = unit->type, tx, ty, dist, movedist, enemythere, uview, tu, ts;
  458.     Unit *unit2;
  459.     Side *us = unit->side;
  460.  
  461.     /* This is to hit a (given type/side of) unit at a given place. */
  462.     /* (should add spec for number of hits to attempt?) */
  463.     tx = task->args[0];  ty = task->args[1];
  464.     tu = task->args[2];  ts = task->args[3];
  465.     dist = distance(tx, ty, unit->x, unit->y);
  466.     if (dist <= 1 /* direct attack range */) {
  467.     for_all_stack(tx, ty, unit2) {
  468.         if (!trusted_side(us, unit2->side)
  469.             && (tu == NONUTYPE || unit2->type == tu)
  470.             /* (should check designated side to hit, if defined) */
  471.             ) {
  472.         if (valid(check_attack_action(unit, unit, unit2, 100))) {
  473.             prep_attack_action(unit, unit, unit2, 100);
  474.             return TASK_PREPPED_ACTION;
  475.         }
  476.         }
  477.     }
  478.     /* but might still be able to fire! */
  479.     return TASK_FAILED;
  480.     }
  481.     if (dist < u_range_min(u)) {
  482.     /* should move further away */
  483.     return TASK_FAILED;
  484.     }
  485.     if (dist < u_range(u)) {
  486.     if (units_visible(us, tx, ty)) {
  487.       for_all_stack(tx, ty, unit2) {
  488.         if (!trusted_side(us, unit2->side)
  489.             && (tu == NONUTYPE || unit2->type == tu)
  490.             /* (should check designated side to hit, if defined) */
  491.             ) {
  492.         if (valid(check_fire_at_action(unit, unit, unit2, -1))
  493.             && fire_can_damage(unit, unit2)) {
  494.             prep_fire_at_action(unit, unit, unit2, -1);
  495.             return TASK_PREPPED_ACTION;
  496.         }
  497.         }
  498.       }
  499.     }
  500.     return TASK_FAILED;        
  501.     }
  502.     if (units_visible(us, tx, ty)) {
  503.     enemythere = FALSE;
  504.     for_all_stack(tx, ty, unit2) {
  505.         if (!trusted_side(us, unit2->side)
  506.             && (tu == NONUTYPE || unit2->type == tu)
  507.             /* (should check designated side to hit, if defined) */
  508.             ) {
  509.             enemythere = TRUE;
  510.             break;
  511.         }
  512.     }
  513.     if (!enemythere) {
  514.         if (tu != NONUTYPE) {
  515.         return TASK_FAILED;
  516.         } else {
  517.         return TASK_IS_COMPLETE;
  518.         }
  519.     }
  520.     } else {
  521.     /* Have to assess old image or non-image. */
  522.     uview = unit_view(us, tx, ty);
  523.     if (uview != EMPTY) {
  524.         if (tu == NONUTYPE) {
  525.             /* Just keep going. */
  526.         }
  527.     } else {
  528.         /* Not clear if disappearance of target means success or failure,
  529.            but go with failure. */
  530.         return TASK_FAILED;
  531.     }
  532.     }
  533.     /* If on mobile transport, let it handle things. */
  534.     if (unit->transport != NULL
  535.         && mobile(unit->transport->type)
  536.     /* and the transport is not blocked */
  537.         && flip_coin()) {
  538.         return TASK_IS_INCOMPLETE;
  539.     }
  540.     /* If out of range and can move, push a task to get closer (maybe). */
  541.     if (mobile(u) && flip_coin()) {
  542.     movedist = max(1 /* attack range */, u_range(u));
  543.     if (dist > movedist + u_acp(u) /* or dist that could be covered in 1-2 turns */) {
  544.         movedist = dist - max(1, (dist - movedist) / 4);
  545.     }
  546.     push_move_near_task(unit, tx, ty, movedist);
  547.     return TASK_IS_INCOMPLETE;
  548.     }
  549.     return TASK_FAILED;
  550. }
  551.  
  552. /* Return true if the unit can actually damage the other unit. */
  553.  
  554. int
  555. fire_can_damage(unit, unit2)
  556. Unit *unit, *unit2;
  557. {
  558.     if (!alive(unit) || !alive(unit2))
  559.       return FALSE;
  560.     /* (should check for right kind of ammo) */
  561.     if (uu_hit(unit->type, unit2->type) <= 0)
  562.       return FALSE;
  563.     /* (this is dubious - a no-damage attack could still consume acp) */
  564.     if (uu_damage(unit->type, unit2->type) <= 0)
  565.       return FALSE;
  566.     /* (should check if victim hp might be under damage low bounds) */
  567.     return TRUE;
  568. }
  569.  
  570. static TaskOutcome
  571. do_move_dir_task(unit, task)
  572. Unit *unit;
  573. Task *task;
  574. {
  575.     int dir, tx, ty;
  576.     Unit *unit2;
  577.  
  578.     if ((task->args[1])-- > 0) {
  579.     dir = task->args[0];
  580.     if (!point_in_dir(unit->x, unit->y, dir, &tx, &ty)) {
  581.         return TASK_FAILED;
  582.     }
  583.     if (unit_at(tx, ty)) {
  584.         for_all_stack(tx, ty, unit2) {
  585.         }
  586.         return TASK_FAILED;
  587.     } else if (valid(check_move_action(unit, unit, tx, ty, 0))) {
  588.         prep_move_action(unit, unit, tx, ty, 0);
  589.         return TASK_PREPPED_ACTION;
  590.     } else {
  591.         return TASK_FAILED;
  592.     }
  593.     } else {
  594.     return TASK_IS_COMPLETE;
  595.     }
  596. }
  597.  
  598. enum choicestate {
  599.     eitherway,
  600.     leftthenright,
  601.     rightthenleft,
  602.     leftonly,
  603.     rightonly
  604. };
  605.  
  606. static TaskOutcome do_approach_subtask PARAMS ((Unit *unit, Task *task, int tx, int ty, short *statep));
  607.  
  608. /* The move-to task is the main way for units to get from point A to point B.
  609.    In addition to the destination, the task has a required distance, so it will
  610.    succeed if the unit is within that distance to the nominal destination. */
  611.  
  612. static TaskOutcome
  613. do_move_to_task(unit, task)
  614. Unit *unit;
  615. Task *task;
  616. {
  617.     int dist, tx, ty;
  618.     Unit *unit2, *occ;
  619.  
  620.     /* This task is to get to a designated location somehow. */
  621.     tx = task->args[0];  ty = task->args[1];
  622.     dist = distance(tx, ty, unit->x, unit->y);
  623.     if (dist <= task->args[2]) {
  624.     return TASK_IS_COMPLETE;
  625.     }
  626.     switch (dist) {
  627.       case 0:
  628.     /* We're there already, nothing more to do. */
  629.     return TASK_IS_COMPLETE;
  630.       case 1:
  631.     /* Adjacent cell, do a single move. */
  632.     if (unit_at(tx, ty)) {
  633.         for_all_stack(tx, ty, unit2) {
  634.         if (can_occupy(unit, unit2)) {
  635.             if (valid(check_enter_action(unit, unit, unit2))) {
  636.             prep_enter_action(unit, unit, unit2);
  637.             return TASK_PREPPED_ACTION;
  638.             } else {
  639.             continue;
  640.             }
  641.         } else if (!trusted_side(unit->side, unit2->side)) {
  642.             /* This is probably not a good idea, combat odds not
  643.                taken into account. */
  644.             if (valid(check_attack_action(unit, unit, unit2, 100))) {
  645.             prep_attack_action(unit, unit, unit2, 100);
  646.             return TASK_PREPPED_ACTION;
  647.             } else {
  648.             continue;
  649.             }
  650.         } else {
  651.             /* We could find room in an occupant... */
  652.             for_all_occupants(unit2, occ) {
  653.             if (can_occupy(unit, occ)) {
  654.                 if (valid(check_enter_action(unit, unit, occ))) {
  655.                 prep_enter_action(unit, unit, occ);
  656.                 return TASK_PREPPED_ACTION;
  657.                 }
  658.             }
  659.             }
  660.         }
  661.         }
  662.         return TASK_FAILED;
  663.     }
  664.     if (valid(check_move_action(unit, unit, tx, ty, unit->z))) {
  665.         /* Moving into an empty cell. */
  666.         prep_move_action(unit, unit, tx, ty, unit->z);
  667.         return TASK_PREPPED_ACTION;
  668.     } else {
  669.         return TASK_FAILED;
  670.     }
  671.     break;
  672.       default:
  673.     /* Still some distance away, pick a way to go. */
  674.     return do_approach_subtask(unit, task, tx, ty, &(task->args[4]));
  675.     }
  676.     return TASK_FAILED;
  677. }
  678.  
  679. static TaskOutcome
  680. do_approach_subtask(unit, task, tx, ty, statep)
  681. Unit *unit;
  682. Task *task;
  683. int tx, ty;
  684. short *statep;
  685. {
  686.     int nx, ny, dirs[NUMDIRS], numdirs, i, numdirs2;
  687.     Unit *unit2;
  688.  
  689.     /* If on mobile transport, let it handle things. */
  690.     if (unit->transport != NULL
  691.     && mobile(unit->transport->type)
  692.     /* and the transport is not blocked */
  693.     && flip_coin()) {
  694.     unit->plan->reserve = TRUE;
  695.     return TASK_IS_INCOMPLETE;
  696.     }
  697.     numdirs = choose_move_dirs(unit, tx, ty, TRUE,
  698.                    plausible_move_dir, sort_directions, dirs);
  699.     for (i = 0; i < numdirs; ++i) {
  700.     point_in_dir(unit->x, unit->y, dirs[i], &nx, &ny);
  701.     for_all_stack(nx, ny, unit2) {
  702.         if (can_occupy(unit, unit2)) {
  703.         if (valid(check_enter_action(unit, unit, unit2))) {
  704.             prep_enter_action(unit, unit, unit2);
  705.             /* We (probably) made forward progress, so reopen choice of dirs. */
  706.             *statep = eitherway;
  707.             return TASK_PREPPED_ACTION;
  708.         } else {
  709.             continue;
  710.         }
  711.         } else if (!trusted_side(unit->side, unit2->side)) {
  712.         if (unit->occupant) {
  713.             /* More important to find a way through. */
  714.             continue;
  715.         } else {
  716.             /* This will encourage some re-evaluation. */
  717.             return TASK_FAILED;
  718.         }
  719. #if 0 /* the following is rarely a good idea */
  720.         if (valid(check_attack_action(unit, unit, unit2, 100))) {
  721.             prep_attack_action(unit, unit, unit2, 100);
  722.             /* We (probably) made forward progress, so reopen choice of dirs. */
  723.             *statep = eitherway;
  724.             return TASK_PREPPED_ACTION;
  725.         } else {
  726.             continue;
  727.         }
  728. #endif
  729.         }
  730.     }
  731.     if (valid(check_move_action(unit, unit, nx, ny, unit->z))) {
  732.         prep_move_action(unit, unit, nx, ny, unit->z);
  733.         /* We (probably) made forward progress, so reopen choice of dirs. */
  734.         *statep = eitherway;
  735.         return TASK_PREPPED_ACTION;
  736.     }
  737.     }
  738.     /* Get both right and left non-decreasing dirs. */
  739.     numdirs  = choose_move_dirs(unit, tx, ty, TRUE, NULL, NULL, dirs);
  740.     numdirs2 = choose_move_dirs(unit, tx, ty, FALSE, NULL, NULL, dirs);
  741.     for (i = numdirs; i < numdirs2; ++i) {
  742.     if (plausible_move_dir(unit, dirs[i])) {
  743.         switch (*statep) {
  744.           case eitherway:
  745.         if (i == numdirs)
  746.           *statep = leftonly /* leftthenright */;
  747.         if (i == numdirs+1)
  748.           *statep = rightonly /* rightthenleft */;
  749.         break;
  750. #if 0
  751.           case leftthenright:
  752.         if (i == numdirs)
  753.           *statep = rightonly;
  754.         if (i == numdirs+1)
  755.           *statep = rightonly;
  756.         continue;
  757.         break;
  758.           case rightthenleft:
  759.         if (i == numdirs+1)
  760.           *statep = leftonly;
  761.         continue;
  762.         break;
  763. #endif
  764.           case leftonly:
  765.         if (i == numdirs+1)
  766.           continue;
  767.         break;
  768.           case rightonly:
  769.         if (i == numdirs)
  770.           continue;
  771.         break;
  772.           default:
  773.         run_warning("Weird right/left state %d", *statep);
  774.         *statep = leftonly;
  775.         break;
  776.         }
  777.     } else {
  778.         switch (*statep) {
  779.           case eitherway:
  780.         if (i == numdirs)
  781.           *statep = rightonly;
  782.         if (i == numdirs+1)
  783.           *statep = leftonly;
  784.         continue;
  785.         break;
  786. #if 0
  787.           case leftthenright:
  788.         if (i == numdirs)
  789.           *statep = rightonly;
  790.         if (i == numdirs+1)
  791.           *statep = rightonly;
  792.         continue;
  793.         break;
  794.           case rightthenleft:
  795.         if (i == numdirs+1)
  796.           *statep = leftonly;
  797.         continue;
  798.         break;
  799. #endif
  800.           case leftonly:
  801.         if (i == numdirs)
  802.           return TASK_FAILED;
  803.         if (i == numdirs+1)
  804.           continue;
  805.         break;
  806.           case rightonly:
  807.         if (i == numdirs)
  808.           continue;
  809.         if (i == numdirs+1)
  810.           return TASK_FAILED;
  811.         break;
  812.           default:
  813.         run_warning("Weird right/left state %d", *statep);
  814.         *statep = leftonly;
  815.         break;
  816.         }
  817.     }
  818.     point_in_dir(unit->x, unit->y, dirs[i], &nx, &ny);
  819.     for_all_stack(nx, ny, unit2) {
  820.         if (can_occupy(unit, unit2)) {
  821.         if (valid(check_enter_action(unit, unit, unit2))) {
  822.             prep_enter_action(unit, unit, unit2);
  823.             return TASK_PREPPED_ACTION;
  824.         } else {
  825.             continue;
  826.         }
  827.         } else if (!trusted_side(unit->side, unit2->side)) {
  828.         if (unit->occupant) {
  829.             /* More important to find a way through. */
  830.             continue;
  831.         } else {
  832.             /* This will encourage some re-evaluation. */
  833.             return TASK_FAILED;
  834.         }
  835. #if 0                /* the following is rarely a good idea */
  836.         if (valid(check_attack_action(unit, unit, unit2, 100))) {
  837.             prep_attack_action(unit, unit, unit2, 100);
  838.             return TASK_PREPPED_ACTION;
  839.         } else {
  840.             continue;
  841.         }
  842. #endif
  843.         }
  844.     }
  845.     if (valid(check_move_action(unit, unit, nx, ny, unit->z))) {
  846.         prep_move_action(unit, unit, nx, ny, unit->z);
  847.         return TASK_PREPPED_ACTION;
  848.     }
  849.     }
  850.     return TASK_FAILED;
  851. }
  852.  
  853. static TaskOutcome
  854. do_occupy_task(unit, task)
  855.      Unit *unit;
  856.      Task *task;
  857. {
  858.     int dist;
  859.     Unit *transport = find_unit(task->args[0]);
  860.  
  861.     if (!in_play(transport))
  862.       return TASK_FAILED;
  863.     /* (should also fail if we don't know where transport is anymore) */
  864.     if (unit->transport == transport) {
  865.     return TASK_IS_COMPLETE;
  866.     }
  867.     dist = distance(unit->x, unit->y, transport->x, transport->y);
  868.     if (dist <= 1) {
  869.     if (valid(check_enter_action(unit, unit, transport))) {
  870.         prep_enter_action(unit, unit, transport);
  871.         return TASK_PREPPED_ACTION;
  872.     } else {
  873.         /* Try a couple times, then fail if not working. */
  874.         return (task->execnum < 3 ? TASK_IS_INCOMPLETE : TASK_FAILED);
  875.     }
  876.     } else {
  877.     /* Still some distance away, pick a way to go. */
  878.     return do_approach_subtask(unit, task, transport->x, transport->y, &(task->args[1]));
  879.     }
  880. }
  881.  
  882. /* Wait around for a particular unit.  Give up if the unit is not forthcoming. */
  883.  
  884. static TaskOutcome
  885. do_pickup_task(unit, task)
  886. Unit *unit;
  887. Task *task;
  888. {
  889.     Unit *occupant = find_unit(task->args[0]);
  890.  
  891.     if (!in_play(occupant))
  892.       return TASK_FAILED;
  893.     wake_unit(occupant, FALSE, 0, NULL);
  894.     if (occupant->transport == unit) {
  895.     return TASK_IS_COMPLETE;
  896.     } else if (task->execnum > 10) {
  897.     /* Waiting around isn't working for us, give up.  If the
  898.        prospective occupant still needs us, we'll get another
  899.        call. */
  900.     return TASK_FAILED;
  901.     } else {
  902.     if (valid(check_enter_action(occupant, occupant, unit))) {
  903.         prep_enter_action(occupant, occupant, unit);
  904.         return TASK_PREPPED_ACTION;
  905.     } else if (valid(check_enter_action(unit, occupant, unit))) {
  906.         prep_enter_action(unit, occupant, unit);
  907.         return TASK_PREPPED_ACTION;
  908.     } else {
  909.         return (task->execnum < 5 ? TASK_IS_INCOMPLETE : TASK_FAILED);
  910.     }
  911.     }
  912. }
  913.  
  914. static TaskOutcome
  915. do_produce_task(unit, task)
  916. Unit *unit;
  917. Task *task;
  918. {
  919.     int m, tot, sofar, amt;
  920.  
  921.     m = task->args[0];
  922.     tot = task->args[1];
  923.     sofar = task->args[2];
  924.     if (sofar >= tot)
  925.       return TASK_IS_COMPLETE;
  926.     amt = um_material_per_production(unit->type, m);
  927.     if (valid(check_produce_action(unit, unit, m, amt))) {
  928.     prep_produce_action(unit, unit, m, amt);
  929.     return TASK_PREPPED_ACTION;
  930.     }
  931.     return TASK_FAILED;
  932. }
  933.  
  934. Unit *
  935. repair_here(x, y)
  936. int x, y;
  937. {
  938.     Unit *unit;
  939.  
  940.     for_all_stack(x, y, unit) {
  941.     /* what about allies? */
  942.     if (unit->side == tmpside && can_carry(unit, tmpunit)) {
  943.         /* this should be controlled by doctrine? */
  944.         /* shouldn't wake up, should get a new task to "wait up"
  945.            or even approach if possible */
  946.     /*    wake_unit(unit, FALSE, WAKEOWNER, NULL);  */
  947.         return unit;
  948.     }
  949.     /* should look at occupants in stack too */
  950.     }
  951.     return NULL;
  952. }
  953.  
  954. int
  955. repair_test(x, y)
  956. int x, y;
  957. {
  958.     return (repair_here(x, y) != NULL);
  959. }
  960.  
  961. static TaskOutcome
  962. do_repair_task(unit, task)
  963. Unit *unit;
  964. Task *task;
  965. {
  966.     int x, y, u = unit->type, m, range = area.maxdim;
  967.     int ux = unit->x, uy = unit->y;
  968.     Unit *unit2;
  969.  
  970.     for_all_material_types(m) {
  971.     if (um_consumption_per_move(u, m) > 0) {
  972.         range = min(range, unit->supply[m] / um_consumption_per_move(u, m));
  973.     }
  974.     }
  975.     tmpside = unit->side;
  976.     tmpunit = unit;
  977.     if (unit->hp == u_hp(u)) {  /* what if unit is multi-part? */
  978.         return TASK_IS_COMPLETE;
  979.     } else if (unit->transport != NULL) {
  980.     set_unit_reserve(unit->side, unit, TRUE, FALSE);
  981.         return TASK_IS_INCOMPLETE;
  982.     } else if ((unit2 = repair_here(ux, uy)) != NULL
  983.         && unit2 != unit->transport) {    
  984.         prep_enter_action(unit, unit, unit2);
  985.     return TASK_PREPPED_ACTION;
  986.     } else if (search_around(ux, uy, range, repair_test, &x, &y, 1)) {
  987.         /* (should collect actual unit and chase it directly) */
  988.     push_move_to_task(unit, x, y);
  989.     return TASK_IS_INCOMPLETE;
  990.     } else {
  991.         /* (should be able to signal interface usefully somehow) */
  992.     return TASK_FAILED;
  993.     }
  994. }
  995.  
  996. static int *lowm = NULL, numlow; 
  997.  
  998. Unit *
  999. aux_resupply_here(unit)
  1000. Unit *unit;
  1001. {
  1002.     int i, enough = TRUE;
  1003.     Unit *occ;
  1004.  
  1005.     /* what about allies? */
  1006.     if (unit_trusts_unit(unit, tmpunit)
  1007.     && can_carry(unit, tmpunit)) {
  1008.     for (i = 0; i < numlow; ++i) {
  1009.         if (unit->supply[lowm[i]] == 0)
  1010.           enough = FALSE;
  1011.     }
  1012.     /* this should be controlled by doctrine? */
  1013.     /* shouldn't wake up, should get a new task to "wait up"
  1014.        or even approach if possible */
  1015.     /*    wake_unit(unit, FALSE, WAKEOWNER, NULL);  */
  1016.     if (enough)
  1017.       return unit;
  1018.     }
  1019.     for_all_occupants(unit, occ) {
  1020.     if (aux_resupply_here(occ)) {
  1021.         return occ;
  1022.     }
  1023.     }
  1024.     return NULL;
  1025. }
  1026.  
  1027. Unit *
  1028. resupply_here(x, y)
  1029. int x, y;
  1030. {
  1031.     Unit *unit, *resupplier;
  1032.  
  1033.     for_all_stack(x, y, unit) {
  1034.         resupplier = aux_resupply_here(unit);
  1035.         if (resupplier)
  1036.           return resupplier;
  1037.     }
  1038.     return NULL;
  1039. }
  1040.  
  1041. int
  1042. resupply_test(x, y)
  1043. int x, y;
  1044. {
  1045.     return (resupply_here(x, y) != NULL);
  1046. }
  1047.  
  1048. /* Replenish our supplies, using one of several strategies, which as usual
  1049.    depends on the game, unit, terrain, etc.  Strategies include 1) wait for
  1050.    supply line or own production to replenish, 2) move to productive terrain
  1051.    and then wait, 3) move within range of a supplier, and 4) request a supplier
  1052.    to approach. */
  1053.  
  1054. /* (should see if production actions would resupply, prep those actions) */
  1055.  
  1056. static TaskOutcome
  1057. do_resupply_task(unit, task)
  1058. Unit *unit;
  1059. Task *task;
  1060. {
  1061.     int x, y, u = unit->type, m, range;
  1062.     int ux = unit->x, uy = unit->y;
  1063.     Unit *unit2;
  1064.  
  1065.     tmpside = unit->side;
  1066.     tmpunit = unit;
  1067.     if (lowm == NULL)
  1068.       lowm = (int *) xmalloc(nummtypes * sizeof(int));
  1069.     numlow = 0;
  1070.     if (task->args[0] == NONMTYPE) {
  1071.     for_all_material_types(m) {
  1072.         if (unit->supply[m] < um_storage_x(u, m)) {
  1073.         lowm[numlow++] = m;
  1074.         }
  1075.     }
  1076.     } else {
  1077.     m = task->args[0];
  1078.     if (unit->supply[m] < um_storage_x(u, m)) {
  1079.         lowm[numlow++] = m;
  1080.     }
  1081.     }
  1082.     /* We're all full up, must be OK. */
  1083.     if (numlow == 0) {
  1084.         return TASK_IS_COMPLETE;
  1085.     } else if (can_auto_resupply_self(unit, lowm, numlow)) {
  1086.     set_unit_reserve(unit->side, unit, TRUE, FALSE);
  1087.         return (probability(10) ? TASK_FAILED : TASK_IS_INCOMPLETE);
  1088.     } else if (unit->transport != NULL) {
  1089.     /* (should fix this test, transport is not necessarily of any help) */
  1090.         /* (could attempt to resupply via direct action) */
  1091.     set_unit_reserve(unit->side, unit, TRUE, FALSE);
  1092.         return (probability(10) ? TASK_FAILED : TASK_IS_INCOMPLETE);
  1093.     } else if ((unit2 = resupply_here(ux, uy)) != NULL
  1094.         && unit2 != unit->transport) {    
  1095.         prep_enter_action(unit, unit, unit2);
  1096.     return TASK_PREPPED_ACTION;
  1097.     } else {
  1098.     /* Compute how far out to look for a resupply point; be a little
  1099.        optimistic. */
  1100.     range = operating_range_best(u);
  1101.     /* (should reduce range if materials are really low) */
  1102.     if (search_around(ux, uy, range, resupply_test, &x, &y, 1)) {
  1103.             /* (should collect actual unit and chase it directly) */
  1104.             /* (should only need to get within outlength of needed supplies) */
  1105.         push_move_to_task(unit, x, y);
  1106.         return TASK_IS_INCOMPLETE;
  1107.     } else {
  1108.         /* Failure - sometimes just sit, but usually try something else. */
  1109.         if (probability(10))
  1110.           set_unit_reserve(unit->side, unit, TRUE, FALSE);
  1111.             /* (should be able to signal interface usefully somehow) */
  1112.         return TASK_FAILED;
  1113.     }
  1114.     }
  1115. }
  1116.  
  1117.  
  1118. /* Return true if our own automatic material production is *greater*
  1119.    than our consumption, for the given list of materials. */
  1120.  
  1121. int
  1122. can_auto_resupply_self(unit, materials, numtypes)
  1123. Unit *unit;
  1124. int *materials, numtypes;
  1125. {
  1126.     int u = unit->type, i, m, rslt = TRUE, t = terrain_at(unit->x, unit->y);
  1127.  
  1128.     for (i = 0; i < numtypes; ++i) {
  1129.     m = materials[i];
  1130.     if (um_base_production(u, m) * ut_productivity(u, t) <= um_base_consumption(u, m))
  1131.       rslt = FALSE;
  1132.     }
  1133.     return rslt;
  1134. }
  1135.  
  1136. static TaskOutcome
  1137. do_sentry_task(unit, task)
  1138. Unit *unit;
  1139. Task *task;
  1140. {
  1141.     if (task->args[0] > 0) {
  1142.     unit->plan->reserve = TRUE;
  1143.     --(task->args[0]);
  1144.     return TASK_IS_INCOMPLETE;
  1145.     } else {
  1146.     /* Unit won't necessarily wake up, may just replan and
  1147.        continue sleeping. */
  1148.     return TASK_IS_COMPLETE;
  1149.     }
  1150. }
  1151.  
  1152. /* This is the main routine for a unit to execute a task.  It basically
  1153.    consists of a dispatch to the execution code for each task type, and
  1154.    handling for a task's several possible outcomes.  Note that a task
  1155.    does *not* directly invoke any actions; instead it will schedule
  1156.    ("prep") an action, which will be executed later by execute_action.
  1157.    Therefore, it is possible for a task to succeed but the action to
  1158.    fail, although each task type's code tries to reduce the chances
  1159.    of this happening (not possible to prevent entirely - unit may
  1160.    become damaged and unable to do perform an action after the task
  1161.    had decided on that action). */
  1162.  
  1163. TaskOutcome
  1164. execute_task(unit)
  1165. Unit *unit;
  1166. {
  1167.     Plan *plan = unit->plan;
  1168.     TaskOutcome rslt;
  1169.     Task *task;
  1170.  
  1171.     /* This should never happen. */
  1172.     if (unit->plan == NULL)
  1173.       run_error("???");
  1174.     task = plan->tasks;
  1175.     rslt = execute_task_aux(unit, task);
  1176.     DMprintf("%s did task %s: ", unit_desig(unit), task_desig(task));
  1177.     /* Now look at what happened with task execution. */
  1178.     switch (rslt) {
  1179.       case TASK_UNKNOWN:
  1180.     DMprintf("???unknown outcome???");
  1181.     break;
  1182.       case TASK_FAILED:
  1183.         ++task->retrynum;
  1184.     DMprintf("failed try %d, ", task->retrynum);
  1185.     if (probability(20) || task->retrynum > 5) {
  1186.         pop_task(plan);
  1187.         DMprintf("removed it");
  1188.         /* We might be buzzing, so maybe go into reserve. */
  1189.         if (probability(20)) {
  1190.             plan->reserve = TRUE;
  1191.             DMprintf(" and went into reserve");
  1192.         }
  1193.     } else {
  1194.         DMprintf("will retry");
  1195.     }
  1196.     break;
  1197.       case TASK_IS_INCOMPLETE:
  1198.     /* Leave the task alone. */
  1199.     DMprintf("incomplete");
  1200.     break;
  1201.       case TASK_PREPPED_ACTION:
  1202.     /* Mention the action that was prepared to execute. */
  1203.     DMprintf("prepped action %s", action_desig(&(unit->act->nextaction)));
  1204.     break;
  1205.       case TASK_IS_COMPLETE:
  1206.     DMprintf("completed after %d executions", task->execnum);
  1207.     pop_task(plan);
  1208.     break;
  1209.       default:
  1210.     break;
  1211.     }
  1212.     DMprintf("\n");
  1213.     /* Give AIs a chance to decide what to do with the result of a task. */
  1214.     if (unit->side != NULL && side_has_ai(unit->side)) {
  1215.         ai_react_to_task_result(unit->side, unit, task, rslt);
  1216.     }
  1217.     return rslt;
  1218. }
  1219.  
  1220. /* Perform a single given task. */
  1221.  
  1222. TaskOutcome
  1223. execute_task_aux(unit, task)
  1224. Unit *unit;
  1225. Task *task;
  1226. {
  1227.     if (!alive(unit) || task == NULL)
  1228.       return TASK_UNKNOWN;
  1229.     DMprintf("%s doing task %s\n", unit_desig(unit), task_desig(task));
  1230.     /* Count this execution. */
  1231.     ++task->execnum;
  1232.     /* (should use function pointer table...) */
  1233.     switch (task->type) {
  1234.       case TASK_NONE:
  1235.     /* This is a no-op, useful as a placeholder.  Always "succeeds". */
  1236.     return TASK_IS_COMPLETE;
  1237.       case TASK_BUILD:
  1238.     return do_build_task(unit, task);
  1239.       case TASK_CAPTURE:
  1240.     return do_capture_task(unit, task);
  1241.       case TASK_DISBAND:
  1242.     return do_disband_task(unit, task);
  1243.       case TASK_DO_ACTION:
  1244.     return do_action_task(unit, task);
  1245.       case TASK_HIT_POSITION:
  1246.     return do_hit_position_task(unit, task);
  1247.       case TASK_HIT_UNIT:
  1248.     return do_hit_unit_task(unit, task);
  1249.       case TASK_MOVE_DIR:
  1250.     return do_move_dir_task(unit, task);
  1251.       case TASK_MOVE_TO:
  1252.     return do_move_to_task(unit, task);
  1253.       case TASK_OCCUPY:
  1254.         return do_occupy_task(unit, task);
  1255.       case TASK_PICKUP:
  1256.         return do_pickup_task(unit, task);
  1257.       case TASK_PRODUCE:
  1258.         return do_produce_task(unit, task);
  1259.       case TASK_REPAIR:
  1260.         return do_repair_task(unit, task);
  1261.       case TASK_RESEARCH:
  1262.     return do_research_task(unit, task);
  1263.       case TASK_RESUPPLY:
  1264.         return do_resupply_task(unit, task);
  1265.       case TASK_SENTRY:
  1266.         return do_sentry_task(unit, task);
  1267.       default:
  1268.     /* This is bad, but not necessarily a reason to die instantly. */
  1269.     run_warning("Unknown task type %d", task->type);
  1270.         return TASK_FAILED;
  1271.     }
  1272. }
  1273.  
  1274. /* This weird-looking routine computes next directions for moving to a
  1275.    given spot.  The number of directions ranges from 1 to 4, depending
  1276.    on whether there is a straight-line path to the dest, and whether we are
  1277.    required to take a direct path or are allowed to move in dirs that don't
  1278.    the unit any closer (we never increase our distance though).
  1279.    Some trickinesses:  if area wraps, must resolve ambiguity about
  1280.    getting to the same place going either direction (we pick shortest). */
  1281.  
  1282. int
  1283. choose_move_dirs(unit, tx, ty, shortest, dirtest, dirsort, dirs)
  1284. Unit *unit;
  1285. int tx, ty, shortest, *dirs;
  1286. int (*dirtest) PARAMS ((Unit *, int));
  1287. void (*dirsort) PARAMS ((Unit *, int *, int));
  1288. {
  1289.     int dx, dxa, dy, dist, d1, d2, d3, d4, axis = -1, hextant = -1;
  1290.     int numdirs = 0, shortestnumdirs;
  1291.  
  1292.     dist = distance(unit->x, unit->y, tx, ty);
  1293.     dx = tx - unit->x;  dy = ty - unit->y;
  1294.  
  1295.     if (area.xwrap) {
  1296.     dxa = (tx + area.width) - unit->x;
  1297.     if (ABS(dx) > ABS(dxa))
  1298.       dx = dxa;
  1299.     dxa = (tx - area.width) - unit->x;
  1300.     if (ABS(dx) > ABS(dxa))
  1301.       dx = dxa;
  1302.     }
  1303.     if (dx == 0 && dy == 0) {
  1304.     return -1;
  1305.     }
  1306.     axis = hextant = -1;
  1307.     if (dx == 0) {
  1308.     axis = (dy > 0 ? NORTHEAST : SOUTHWEST);
  1309.     } else if (dy == 0) {
  1310.     axis = (dx > 0 ? EAST : WEST);
  1311.     } else if (dx == (0 - dy)) {
  1312.     axis = (dy > 0 ? NORTHWEST : SOUTHEAST);
  1313.     } else if (dx > 0) {
  1314.     hextant = (dy > 0 ? EAST :
  1315.            (ABS(dx) > ABS(dy) ? SOUTHEAST : SOUTHWEST));
  1316.     } else {
  1317.     hextant = (dy < 0 ? WEST :
  1318.            (ABS(dx) > ABS(dy) ? NORTHWEST : NORTHEAST));
  1319.     }
  1320.     if (axis >= 0) {
  1321.     d1 = d2 = axis;
  1322.     if (dirtest == NULL || (*dirtest)(unit, d1)) {
  1323.         dirs[numdirs++] = d1;
  1324.     }
  1325.     }
  1326.     if (hextant >= 0) {
  1327.     d1 = left_dir(hextant);
  1328.     d2 = hextant;
  1329.     if (dirtest == NULL || (*dirtest)(unit, d1)) {
  1330.         dirs[numdirs++] = d1;
  1331.     }
  1332.     if (dirtest == NULL || (*dirtest)(unit, d2)) {
  1333.         dirs[numdirs++] = d2;
  1334.     }
  1335.     }
  1336.     /* Check on other properties of the two choices. */
  1337.     if (numdirs > 1 && dirsort != NULL) {
  1338.         (*dirsort)(unit, dirs, numdirs);
  1339.     }
  1340.     if (dist > 1 && !shortest) {
  1341.     shortestnumdirs = numdirs;
  1342.         d3 = left_dir(d1);
  1343.         d4 = right_dir(d2);
  1344.     if (dirtest == NULL || (*dirtest)(unit, d3)) {
  1345.         dirs[numdirs++] = d3;
  1346.     }
  1347.     if (dirtest == NULL || (*dirtest)(unit, d4)) {
  1348.         dirs[numdirs++] = d4;
  1349.     }
  1350.     if (numdirs > shortestnumdirs + 1 && dirsort != NULL) {
  1351.         (*dirsort)(unit, dirs + shortestnumdirs, numdirs - shortestnumdirs);
  1352.     }
  1353.     }
  1354.     return numdirs;
  1355. }
  1356.  
  1357. /* A heuristic test for whether the given direction is a good one
  1358.    to move in. */
  1359.  
  1360. int
  1361. plausible_move_dir(unit, dir)
  1362. Unit *unit;
  1363. int dir;
  1364. {
  1365.     int u = unit->type, ux = unit->x, uy = unit->y, nx, ny, t, c;
  1366.  
  1367.     point_in_dir(ux, uy, dir, &nx, &ny);
  1368.     if (unit_at(nx, ny))
  1369.       return TRUE;
  1370.     t = terrain_at(nx, ny);
  1371.     if ((ut_vanishes_on(u, t)
  1372.          || ut_wrecks_on(u, t))
  1373.         && !can_move_via_conn(unit, nx, ny))
  1374.       return FALSE;
  1375.     if (ut_mp_to_enter(u, t) <= u_acp(u))
  1376.       return TRUE;
  1377.     if (numconntypes > 0) {
  1378.     /* Try each connection type to see if it works. */
  1379.     for_all_terrain_types(c) {
  1380.         if (t_is_connection(c)
  1381.         && aux_terrain_defined(c)
  1382.         && connection_at(ux, uy, dir, c)) {
  1383.         if ((ut_mp_to_enter(u, c)
  1384.              + ut_mp_to_traverse(u, c)
  1385.              + ut_mp_to_leave(u, c)) <= u_acp(u))
  1386.           return TRUE;
  1387.         }
  1388.     }
  1389.     }
  1390.     return FALSE;
  1391. }
  1392.  
  1393. /* This compares the desirability of two different directions.  This is
  1394.    somewhat tricky, because it should return < 0 if i0 designates a BETTER
  1395.    direction than i1. */
  1396.  
  1397. int xs[NUMDIRS];
  1398. int ys[NUMDIRS];
  1399. int terrs[NUMDIRS];
  1400.  
  1401. static int
  1402. compare_directions(a0, a1)
  1403. CONST void *a0, *a1;
  1404. {
  1405.     int i0, i1;
  1406.     int u = tmputype, t0, t1;
  1407.     int ux = tmpunit->x, uy = tmpunit->y, u2 = NONUTYPE;
  1408.     int cost0 = 0, cost1 = 0, s, ps0, ps1, surr0, surr1, rslt;
  1409.     extern int *any_people_surrenders;
  1410.  
  1411.     i0 = *((int *) a0);  i1 = *((int *) a1);
  1412.     t0 = terrs[i0];  t1 = terrs[i1];
  1413.     if (tmpunit->transport)
  1414.       u2 = tmpunit->transport->type;
  1415.     /* Check the overall movement cost of each direction. */
  1416.     cost0 = total_move_cost(u, u2, ux, uy, 0, xs[i0], ys[i0], 0);
  1417.     cost1 = total_move_cost(u, u2, ux, uy, 0, xs[i1], ys[i1], 0);
  1418.     if (cost0 != cost1) {
  1419.     return cost0 - cost1;
  1420.     }
  1421.     if (1 /* not in supply */) {
  1422.     if ((rslt = ut_productivity(u, t1) - ut_productivity(u, t0)) != 0) {
  1423.         return rslt;
  1424.     }
  1425.     }
  1426.     if ((rslt = ut_mp_to_leave(u, t1) - ut_mp_to_leave(u, t0)) != 0) {
  1427.     return rslt;
  1428.     }
  1429.     /* Chooser the safer terrain. */
  1430.     if ((rslt = ut_accident_hit(u, t1) - ut_accident_hit(u, t0)) != 0) {
  1431.     return rslt;
  1432.     }
  1433.     /* Choose the better-concealing terrain. */
  1434.     /* (should only do if limited visibility) */
  1435.     if ((rslt = ut_visibility(u, t1) - ut_visibility(u, t0)) != 0) {
  1436.     return rslt;
  1437.     }
  1438.     /* Prefer to go over cells that we can change to our side. */
  1439.     if (any_people_surrenders != NULL && any_people_surrenders[u]) {
  1440.         s = side_number(tmpunit->side);
  1441.         ps0 = people_side_at(xs[i0], ys[i0]);
  1442.         ps1 = people_side_at(xs[i1], ys[i1]);
  1443.         surr0 = ut_people_surrender(u, t0)
  1444.       * ((ps0 != NOBODY && s != ps0) ? 1 : 0);
  1445.         surr1 = ut_people_surrender(u, t1)
  1446.       * ((ps1 != NOBODY && s != ps1) ? 1 : 0);
  1447.         if (surr0 != surr1) {
  1448.         return surr1 - surr0;
  1449.         }
  1450.     }
  1451.     return 0;
  1452. }
  1453.  
  1454. void
  1455. sort_directions(unit, dirs, numdirs)
  1456. Unit *unit;
  1457. int *dirs, numdirs;
  1458. {
  1459.     int i, tmp, i0 = 0, i1 = 1, compar;
  1460.  
  1461.     for (i = 0; i < numdirs; ++i) { 
  1462.     point_in_dir(unit->x, unit->y, dirs[i], &(xs[i]), &(ys[i]));
  1463.     terrs[i] = terrain_at(xs[i], ys[i]);
  1464.     }
  1465.     tmpunit = unit;
  1466.     tmputype = unit->type;
  1467.     if (numdirs == 2) {
  1468.     compar = compare_directions(&i0, &i1);
  1469.         if (compar > 0 || (compar == 0 && flip_coin())) {
  1470.             tmp = dirs[0];  dirs[0] = dirs[1];  dirs[1] = tmp;
  1471.         }
  1472.     } else if (numdirs > 2) {
  1473.         qsort(dirs, numdirs, sizeof(int), compare_directions);
  1474.     if (compare_directions(&i0, &i1) == 0 && flip_coin()) {
  1475.         tmp = dirs[0];  dirs[0] = dirs[1];  dirs[1] = tmp;
  1476.     }
  1477.     }
  1478. }
  1479.  
  1480. /* Put the given task back onto the list of free tasks. */
  1481.  
  1482. void 
  1483. free_task(task)
  1484. Task *task;
  1485. {
  1486.     task->next = freetasks;
  1487.     freetasks = task;
  1488. }
  1489.  
  1490. void
  1491. add_task(unit, pos, task)
  1492. Unit *unit;
  1493. int pos;
  1494. Task *task;
  1495. {
  1496.     int numcleared;
  1497.  
  1498.     if (!in_play(unit) || unit->plan == NULL) {
  1499.     run_warning("Trying to do %s task with bad %s",
  1500.             task_desig(task), unit_desig(unit));
  1501.     return;
  1502.     }
  1503.     Dprintf("To %s task agenda, add %s",
  1504.         unit_desig(unit), task_desig(task));
  1505.     if (pos == CLEAR_AGENDA) {
  1506.     numcleared = clear_task_agenda(unit->plan);
  1507.     Dprintf(" (cleared %d existing tasks)", numcleared);
  1508.     }
  1509.     Dprintf("\n");
  1510.     switch (pos) {
  1511.       case 0:
  1512.       case CLEAR_AGENDA:
  1513.     /* Put the task on the front of the agenda. */
  1514.     task->next = unit->plan->tasks;
  1515.     unit->plan->tasks = task;
  1516.     break;
  1517.       default:
  1518.     run_error("can't do this yet");
  1519.     break;
  1520.     }
  1521.     /* Shouldn't be asleep any longer. */
  1522.     unit->plan->asleep = FALSE;
  1523.     /* We're not in reserve. */
  1524.     unit->plan->reserve = FALSE;
  1525.     /* Presumably we're no longer waiting to be told what to do. */
  1526.     if (unit->plan->waitingfortasks && unit->side)
  1527.       --(unit->side->numwaiting);
  1528.     unit->plan->waitingfortasks = FALSE;
  1529.     /* Reflect all this on displays. */
  1530.     update_unit_display(unit->side, unit, FALSE);
  1531. }
  1532.  
  1533. Task *
  1534. create_move_to_task(x, y)
  1535. int x, y;
  1536. {
  1537.     Task *task = create_task(TASK_MOVE_TO);
  1538.  
  1539.     task->args[0] = x;  task->args[1] = y;
  1540.     task->args[2] = 0;
  1541.     task->args[3] = 0;
  1542.     task->args[4] = eitherway;
  1543.     return task;
  1544. }
  1545.  
  1546. void
  1547. push_move_to_task(unit, x, y)
  1548. Unit *unit;
  1549. int x, y;
  1550. {
  1551.     if (!in_area(x, y)) {
  1552.         run_warning("Trying to move %s to %d,%d", unit_desig(unit), x, y);
  1553.         return;
  1554.     }
  1555.     add_task(unit, 0, create_move_to_task(x, y));
  1556. }
  1557.  
  1558. /* Give the unit a task to move to a given place, erasing every other task. */
  1559.  
  1560. void
  1561. set_move_to_task(unit, x, y)
  1562. Unit *unit;
  1563. int x, y;
  1564. {
  1565.     add_task(unit, CLEAR_AGENDA, create_move_to_task(x, y));
  1566. }
  1567.  
  1568. Task *
  1569. create_move_near_task(x, y, dist)
  1570. int x, y, dist;
  1571. {
  1572.     Task *task = create_task(TASK_MOVE_TO);
  1573.  
  1574.     task->args[0] = x;  task->args[1] = y;
  1575.     task->args[2] = 0;
  1576.     task->args[3] = dist;
  1577.     task->args[4] = eitherway;
  1578.     return task;
  1579. }
  1580.  
  1581. void
  1582. set_move_near_task(unit, x, y, dist)
  1583. Unit *unit;
  1584. int x, y, dist;
  1585. {
  1586.     add_task(unit, CLEAR_AGENDA, create_move_near_task(x, y, dist));
  1587. }
  1588.  
  1589. void
  1590. push_move_near_task(unit, x, y, dist)
  1591. Unit *unit;
  1592. int x, y, dist;
  1593. {
  1594.     add_task(unit, 0, create_move_near_task(x, y, dist));
  1595. }
  1596.  
  1597. /* Create a task to move in a given direction for a given distance. */
  1598.  
  1599. Task *
  1600. create_move_dir_task(dir, n)
  1601. int dir, n;
  1602. {
  1603.     Task *task = create_task(TASK_MOVE_DIR);
  1604.  
  1605.     task->args[0] = dir;
  1606.     task->args[1] = n;
  1607.     return task;
  1608. }
  1609.  
  1610. /* Fill in the given unit with direction-moving orders. */
  1611.  
  1612. void
  1613. set_move_dir_task(unit, dir, n)
  1614. Unit *unit;
  1615. int dir, n;
  1616. {
  1617.     add_task(unit, CLEAR_AGENDA, create_move_dir_task(dir, n));
  1618. }
  1619.  
  1620. /* This routine sets up a task to build a unit of the given type. */
  1621.  
  1622. Task *
  1623. create_build_task(u2, run)
  1624. int u2, run;
  1625. {
  1626.     Task *task = create_task(TASK_BUILD);
  1627.  
  1628.     task->args[0] = u2;
  1629.     task->args[3] = run;
  1630.     return task;
  1631. }
  1632.  
  1633. void
  1634. push_build_task(unit, u2, run)
  1635. Unit *unit;
  1636. int u2, run;
  1637. {
  1638.     add_task(unit, 0, create_build_task(u2, run));
  1639. }
  1640.  
  1641. /* This routine sets up a task to research a unit of the given type. */
  1642.  
  1643. Task *
  1644. create_research_task(u2, n)
  1645. int u2, n;
  1646. {
  1647.     Task *task = create_task(TASK_RESEARCH);
  1648.  
  1649.     task->args[0] = u2;
  1650.     task->args[1] = n;
  1651.     return task;
  1652. }
  1653.  
  1654. void
  1655. push_research_task(unit, u2, n)
  1656. Unit *unit;
  1657. int u2, n;
  1658. {
  1659.     add_task(unit, 0, create_research_task(u2, n));
  1660. }
  1661.  
  1662. void
  1663. set_hit_task(unit, x, y)
  1664. Unit *unit;
  1665. int x, y;
  1666. {
  1667.     Task *task = create_task(TASK_HIT_UNIT);
  1668.  
  1669.     task->args[0] = x;  task->args[1] = y;
  1670.     task->args[2] = NONUTYPE;
  1671.     task->args[3] = -1;
  1672.     add_task(unit, CLEAR_AGENDA, task);
  1673. }
  1674.  
  1675. void
  1676. push_specific_hit_task(unit, x, y, u, s)
  1677. Unit *unit;
  1678. int x, y, u, s;
  1679. {
  1680.     Task *task = create_task(TASK_HIT_UNIT);
  1681.  
  1682.     task->args[0] = x;  task->args[1] = y;
  1683.     task->args[2] = u;
  1684.     task->args[3] = s;
  1685.     add_task(unit, 0, task);
  1686. }
  1687.  
  1688. void
  1689. set_specific_hit_task(unit, x, y, u, s)
  1690. Unit *unit;
  1691. int x, y, u, s;
  1692. {
  1693.     Task *task = create_task(TASK_HIT_UNIT);
  1694.  
  1695.     task->args[0] = x;  task->args[1] = y;
  1696.     task->args[2] = u;
  1697.     task->args[3] = s;
  1698.     add_task(unit, CLEAR_AGENDA, task);
  1699. }
  1700.  
  1701. void
  1702. push_hit_task(unit, x, y)
  1703. Unit *unit;
  1704. int x, y;
  1705. {
  1706.     Task *task = create_task(TASK_HIT_UNIT);
  1707.  
  1708.     task->args[0] = x;  task->args[1] = y;
  1709.     task->args[2] = NONUTYPE;
  1710.     task->args[3] = -1;
  1711.     add_task(unit, 0, task);
  1712. }
  1713.  
  1714. Task *
  1715. create_capture_task(x, y)
  1716. int x, y;
  1717. {
  1718.     Task *task = create_task(TASK_CAPTURE);
  1719.  
  1720.     task->args[0] = x;  task->args[1] = y;
  1721.     task->args[2] = NONUTYPE;
  1722.     task->args[3] = -1;
  1723.     return task;
  1724. }
  1725.  
  1726. void
  1727. set_capture_task(unit, x, y)
  1728. Unit *unit;
  1729. int x, y;
  1730. {
  1731.     add_task(unit, CLEAR_AGENDA, create_capture_task(x, y));
  1732. }
  1733.  
  1734. void
  1735. push_capture_task(unit, x, y)
  1736. Unit *unit;
  1737. int x, y;
  1738. {
  1739.     add_task(unit, 0, create_capture_task(x, y));
  1740. }
  1741.  
  1742. void
  1743. set_disband_task(unit)
  1744. Unit *unit;
  1745. {
  1746.     add_task(unit, CLEAR_AGENDA, create_task(TASK_DISBAND));
  1747. }
  1748.  
  1749. Task *
  1750. create_resupply_task(m)
  1751. int m;
  1752. {
  1753.     Task *task = create_task(TASK_RESUPPLY);
  1754.  
  1755.     task->args[0] = m;
  1756.     return task;
  1757. }
  1758.  
  1759. void
  1760. set_resupply_task(unit, m)
  1761. Unit *unit;
  1762. int m;
  1763. {
  1764.     add_task(unit, CLEAR_AGENDA, create_resupply_task(m));
  1765. }
  1766.  
  1767. Task *
  1768. create_occupy_task(transport)
  1769. Unit *transport;
  1770. {
  1771.     Task *task = create_task(TASK_OCCUPY);
  1772.  
  1773.     task->args[0] = transport->id;
  1774.     task->args[1] = eitherway;
  1775.     /* add a waiting period also? */
  1776.     return task;
  1777. }
  1778.  
  1779. void
  1780. push_occupy_task(unit, transport)
  1781. Unit *unit, *transport;
  1782. {
  1783.     add_task(unit, 0, create_occupy_task(transport));
  1784. }
  1785.  
  1786. Task *
  1787. create_pickup_task(occ)
  1788. Unit *occ;
  1789. {
  1790.     Task *task = create_task(TASK_PICKUP);
  1791.  
  1792.     task->args[0] = occ->id;
  1793.     /* add a waiting period also? */
  1794.     return task;
  1795. }
  1796.  
  1797. void
  1798. push_pickup_task(unit, occ)
  1799. Unit *unit, *occ;
  1800. {
  1801.     add_task(unit, 0, create_pickup_task(occ));
  1802. }
  1803.  
  1804. Task *
  1805. create_produce_task(m, n)
  1806. int m, n;
  1807. {
  1808.     Task *task = create_task(TASK_PRODUCE);
  1809.  
  1810.     task->args[0] = m;
  1811.     task->args[1] = n;
  1812.     /* Third arg is amount produced, which starts at 0. */
  1813.     return task;
  1814. }
  1815.  
  1816. void
  1817. push_produce_task(unit, m, n)
  1818. Unit *unit;
  1819. int m, n;
  1820. {
  1821.     add_task(unit, 0, create_produce_task(m, n));
  1822. }
  1823.  
  1824. Task *
  1825. create_sentry_task(n)
  1826. int n;
  1827. {
  1828.     Task *task = create_task(TASK_SENTRY);
  1829.  
  1830.     task->args[0] = n;
  1831.     return task;
  1832. }
  1833.  
  1834. void
  1835. set_sentry_task(unit, n)
  1836. Unit *unit;
  1837. int n;
  1838. {
  1839.     add_task(unit, CLEAR_AGENDA, create_sentry_task(n));
  1840. }
  1841.  
  1842. void
  1843. push_sentry_task(unit, n)
  1844. Unit *unit;
  1845. int n;
  1846. {
  1847.     add_task(unit, 0, create_sentry_task(n));
  1848. }
  1849.  
  1850. extern int parse_location PARAMS ((Side *side, char *arg, int *xp, int *yp));
  1851.  
  1852. extern Unit *parse_unit PARAMS ((Side *side, char *arg));
  1853.  
  1854. /* Find a unit with the given name, either alive or dead. */
  1855.  
  1856. Unit *
  1857. parse_unit(side, nm)
  1858. Side *side;
  1859. char *nm;
  1860. {
  1861.     Unit *unit;
  1862.  
  1863.     if (empty_string(nm))
  1864.       return NULL;
  1865.     for_all_side_units(side, unit) {
  1866.     if (alive(unit) && unit->name != NULL && strcmp(unit->name, nm) == 0)
  1867.       return unit;
  1868.     }
  1869.     /* Under some circumstances, we can refer to other sides' units by name. */
  1870.     for_all_units(unit) {
  1871.     if (alive(unit)
  1872.         && unit->side != side
  1873.         && unit->name != NULL
  1874.         && strcmp(unit->name, nm) == 0
  1875.         && (side->see_all
  1876.         || side_sees_image(side, unit)))
  1877.       return unit;
  1878.     }
  1879.     return NULL;
  1880. }
  1881.  
  1882. /* Given a textual description of a location, compute an x,y for it
  1883.    if possible. */
  1884.  
  1885. int
  1886. parse_location(side, arg, xp, yp)
  1887. Side *side;
  1888. char *arg;
  1889. int *xp, *yp;
  1890. {
  1891.     char *arg2;
  1892.     Unit *unit;
  1893.  
  1894.     *xp = strtol(arg, &arg2, 10);
  1895.     if (arg != arg2 && *arg2 == ',') {
  1896.     *yp = strtol(arg2 + 1, &arg, 10);
  1897.     if (arg2 + 1 != arg) {
  1898.         return TRUE;
  1899.     } else if ((unit = parse_unit(side, arg)) != NULL) {
  1900.         *xp = unit->x;  *yp = unit->y;
  1901.         return TRUE;
  1902.     }
  1903.     }
  1904.     notify(side, "location \"%s\" not recognized", arg);
  1905.     return FALSE;
  1906. }
  1907.  
  1908. /* Given a string describing a task that has been entered in
  1909.    by a player, generate a task object and return the rest
  1910.    of the string, if NULL if failure. */
  1911.  
  1912. char *
  1913. parse_task(side, str, taskp)
  1914. Side *side;
  1915. char *str;
  1916. Task **taskp;
  1917. {
  1918.     int tasktype, i, x, y, n, dir, u, taskargs[MAXTASKARGS], numargs, rslt;
  1919.     char *arg, *arg2, substr[BUFSIZE], *rest, *argtypes;
  1920.     Unit *unit;
  1921.  
  1922.     rest = get_next_arg(str, substr, &arg);
  1923.     /* Recognize special cases of task types first. */
  1924.     if (strcmp(arg, "nil") == 0 || strcmp(arg, "nothing") == 0) {
  1925.     /* NULL task but non-NULL return indicates order cancellation. */
  1926.     *taskp = NULL;
  1927.     return rest;
  1928.     } else if (strcmp(arg, "move-near") == 0) {
  1929.     rest = get_next_arg(rest, substr, &arg);
  1930.     if (parse_location(side, arg, &x, &y)) {
  1931.         rest = get_next_arg(rest, substr, &arg);
  1932.         n = strtol(arg, &arg2, 10);
  1933.         *taskp = create_move_near_task(x, y, n);
  1934.         return rest;
  1935.     }
  1936.     }
  1937.     tasktype = lookup_task_type(arg);
  1938.     if (tasktype < 0) {
  1939.     notify(side, "task type \"%s\" not recognized", arg);
  1940.     return NULL;
  1941.     }
  1942.     switch (tasktype) {
  1943.       case TASK_MOVE_TO:
  1944.     rest = get_next_arg(rest, substr, &arg);
  1945.     if (parse_location(side, arg, &x, &y)) {
  1946.         *taskp = create_move_to_task(x, y);
  1947.         return rest;
  1948.     } else {
  1949.         return NULL;
  1950.     }
  1951.     break;
  1952.       default:
  1953.     argtypes = taskdefns[tasktype].argtypes;
  1954.     numargs = strlen(argtypes);
  1955.     for (i = 0; i < numargs; ++i)
  1956.       taskargs[i] = 0;
  1957.     rest = get_next_arg(rest, substr, &arg);
  1958.     for (i = 0; i < numargs; ++i) {
  1959.         if (argtypes[i] == 'x' && argtypes[i+1] == 'y') {
  1960.         /* If there are two arguments that are together a position,
  1961.            interpret both together. */
  1962.         if (parse_location(side, arg, &x, &y)) {
  1963.             taskargs[i] = x;  taskargs[i + 1] = y;
  1964.             ++i;
  1965.         } else {
  1966.             return NULL;
  1967.         }
  1968.         } else if (argtypes[i] == 'd') {
  1969.         char *mydirchars = "ulnbhy"; /* (a local copy of ui.c thing) */
  1970.         /* Match on names or chars for directions. */
  1971.         for_all_directions(dir) {
  1972.             if (strcmp(arg, dirnames[dir]) == 0) {
  1973.             taskargs[i] = dir;
  1974.             goto nextarg;
  1975.             }
  1976.             if (strlen(arg) == 1 && arg[0] == mydirchars[dir]) {
  1977.             taskargs[i] = dir;
  1978.             goto nextarg;
  1979.             }
  1980.         }
  1981.         notify(side, "direction \"%s\" not recognized", arg);
  1982.         } else if (argtypes[i] == 'u') {
  1983.         u = utype_from_name(arg);
  1984.         if (u != NONUTYPE) {
  1985.             taskargs[i] = u;
  1986.         } else {
  1987.             notify(side, "unit type \"%s\" not recognized", arg);
  1988.         }
  1989.         } else if (argtypes[i] == 'U') {
  1990.         unit = parse_unit(side, arg);
  1991.         if (unit != NULL) {
  1992.             taskargs[i] = unit->id;
  1993.         } else {
  1994.             notify(side, "unit called \"%s\" not recognized", arg);
  1995.         }
  1996.         } else {
  1997.         /* Just collect an integer and stuff it. */
  1998.         taskargs[i] = strtol(arg, &arg2, 10);
  1999.         if (arg == arg2) {
  2000.             notify(side, "argument \"%s\" not recognized", arg);
  2001.         }
  2002.         }
  2003.       nextarg:
  2004.         rest = get_next_arg(str, substr, &arg);
  2005.         /* (should check for end of command or not?) */
  2006.     }
  2007.     *taskp = create_task(tasktype);
  2008.     for (i = 0; i < numargs; ++i) {
  2009.         (*taskp)->args[i] = taskargs[i];
  2010.     }
  2011.     return rest;
  2012.     }
  2013. }
  2014.  
  2015. int
  2016. lookup_task_type(name)
  2017. char *name;
  2018. {
  2019.     int i;
  2020.  
  2021.     for (i = 0; taskdefns[i].name != NULL; ++i)
  2022.       if (strcmp(name, taskdefns[i].name) == 0)
  2023.     return i; /* should get real enum? */
  2024.     return -1;
  2025. }
  2026.  
  2027. /* Describe a task succinctly - use for debugging only. */
  2028.  
  2029. char *
  2030. task_desig(task)
  2031. Task *task;
  2032. {
  2033.     int i, slen;
  2034.     char *argtypes;
  2035.  
  2036.     if (taskbuf == NULL)
  2037.       taskbuf = xmalloc(BUFSIZE);
  2038.     if (task) {
  2039.     sprintf(taskbuf, "{%s", taskdefns[task->type].name);
  2040.     argtypes = taskdefns[task->type].argtypes;
  2041.     slen = strlen(argtypes);
  2042.     for (i = 0; i < slen; ++i) {
  2043.         tprintf(taskbuf, "%c%d", (i == 0 ? ' ' : ','), task->args[i]);
  2044.     }
  2045.     tprintf(taskbuf, " x %d", task->execnum);
  2046.     if (task->retrynum > 0) {
  2047.         tprintf(taskbuf, " fail %d", task->retrynum);
  2048.     }
  2049.     strcat(taskbuf, "}");
  2050.     } else {
  2051.     sprintf(taskbuf, "no task");
  2052.     }
  2053.     return taskbuf;
  2054. }
  2055.  
  2056.