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 / actions.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  81.3 KB  |  3,133 lines  |  [TEXT/R*ch]

  1. /* Implementations of Xconq actions.
  2.    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996
  3.    Stanley T. Shebs.
  4.  
  5. Xconq is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.  See the file COPYING.  */
  9.  
  10. /* The general theory of actions is that interface or AI code calls, for
  11.    an action foo, the routine prep_foo_action, which just records the action
  12.    for later execution.  The action loop in run_game eventually calls
  13.    do_foo_action, which first calls check_foo_action to confirm that the
  14.    action will succeed.  If check_foo_action does not find any errors, then
  15.    the action cannot fail.  The main body of do_foo_action then implements
  16.    the effects of the action.  Interfaces may call check_foo_action freely,
  17.    but should never call do_foo_action directly. */
  18.  
  19. #include "conq.h"
  20. extern int tmphevtdata1;
  21. extern int construction_possible PARAMS ((int u2));
  22. extern void broadcast_next_action PARAMS ((Unit *unit));
  23. extern void low_send PARAMS ((int id, char *buf));
  24. extern void add_to_unit_hp PARAMS ((Unit *unit, int hp));
  25. extern void try_sharing PARAMS ((Unit *from, Unit *to, int m));
  26.  
  27. extern void change_cell PARAMS ((Unit *unit, int x, int y));
  28.  
  29. extern int max_detonate_on_approach_range;
  30. extern int max_u_detonate_effect_range;
  31. extern int max_t_detonate_effect_range;
  32.  
  33. int numremotes;
  34.  
  35. extern int number_member PARAMS ((int x, Obj *lis));
  36. extern int wind_value PARAMS ((Unit *unit, int angle, int force, Obj *effect, int maxval));
  37.  
  38. static void try_detonate_on_approach PARAMS ((int x, int y));
  39. static void set_created_unit_props PARAMS ((Unit *unit, int u2, Side *side));
  40. static void play_action_messages PARAMS ((Unit *unit, Action *action));
  41.  
  42. /* We can't declare all the action functions as static because some of them
  43.    are in other files, but don't let them be visible to all files. */
  44.  
  45. #undef  DEF_ACTION
  46. #define DEF_ACTION(name,code,args,prepfn,DOFN,checkfn,ARGDECL,doc)  \
  47.   extern int DOFN PARAMS (ARGDECL);
  48.  
  49. #include "action.def"
  50.  
  51. /* The table of all the types of actions. */
  52.  
  53. ActionDefn actiondefns[] = {
  54.  
  55. #undef  DEF_ACTION
  56. #define DEF_ACTION(NAME,CODE,ARGS,prepfn,DOFN,CHECKFN,argdecl,doc)  \
  57.     { CODE, NAME, ARGS, DOFN, CHECKFN },
  58.  
  59. #include "action.def"
  60.  
  61.     { -1, NULL, NULL, NULL }
  62. };
  63.  
  64. /* This is used to indicate that a move is a retreat; for normal movement it will
  65.    always be false. */
  66.  
  67. int retreating;
  68.  
  69. /* This is a specific type of unit that the retreater is running away from. */
  70.  
  71. int retreating_from = NONUTYPE;
  72.  
  73. char *actiondesigbuf = NULL;
  74.  
  75. /* Do any action-related initialization. */
  76.  
  77. void
  78. init_actions()
  79. {
  80. }
  81.  
  82. void
  83. broadcast_next_action(unit)
  84. Unit *unit;
  85. {
  86.     int i, j, atype, n;
  87.     char buf[BUFSIZE], smallbuf[32];
  88.  
  89.     if (numremotes <= 0)
  90.       return;
  91.     atype = unit->act->nextaction.type;
  92.     sprintf(buf, "A %d", unit->id);
  93.     if (unit->id != unit->act->nextaction.actee) {
  94.     sprintf(smallbuf, "/%d", unit->act->nextaction.actee);
  95.     strcat(buf, smallbuf);
  96.     }
  97.     sprintf(smallbuf, " %d", unit->act->nextaction.type);
  98.     strcat(buf, smallbuf);
  99.     n = strlen(actiondefns[atype].argtypes);
  100.     for (j = 0; j < n; ++j) {
  101.     sprintf(smallbuf, " %d", unit->act->nextaction.args[j]);
  102.     strcat(buf, smallbuf);
  103.     }
  104.     /* Send the formatted description of the action to all the remotes. */
  105.     for (i = 1; i < numremotes + 1; ++i) {
  106.     low_send(i, buf);
  107.     }
  108. }
  109.  
  110. /* Just a placeholder action, so not much to do here. */
  111.  
  112. int
  113. prep_none_action(unit, unit2)
  114. Unit *unit, *unit2;
  115. {
  116.     if (unit == NULL || unit->act == NULL)
  117.       return FALSE;
  118.     if (unit2 == NULL)
  119.       return FALSE;
  120.     unit->act->nextaction.type = ACTION_NONE;
  121.     unit->act->nextaction.actee = unit2->id;
  122.     return TRUE;
  123. }
  124.  
  125. int
  126. do_none_action(unit, unit2)
  127. Unit *unit, *unit2;
  128. {
  129.     return A_ANY_DONE;
  130. }
  131.  
  132. int
  133. check_none_action(unit, unit2)
  134. Unit *unit, *unit2;
  135. {
  136.     return A_ANY_DONE;
  137. }
  138.  
  139. /* Movement actions. */
  140.  
  141. /* Record a move action as the next to do. */
  142.  
  143. int
  144. prep_move_action(unit, unit2, x, y, z)
  145. Unit *unit, *unit2;
  146. int x, y, z;
  147. {
  148.     if (unit == NULL || unit->act == NULL)
  149.       return FALSE;
  150.     if (unit2 == NULL)
  151.       return FALSE;
  152.     unit->act->nextaction.type = ACTION_MOVE;
  153.     unit->act->nextaction.args[0] = x;
  154.     unit->act->nextaction.args[1] = y;
  155.     unit->act->nextaction.args[2] = z;
  156.     unit->act->nextaction.actee = unit2->id;
  157.     broadcast_next_action(unit);
  158.     return TRUE;
  159. }
  160.  
  161. /* The basic act of moving.  This attempts to move and maybe fails, but
  162.    takes no corrective action.  Note that this requires space in the
  163.    destination cell, will not board, attack, etc - all that is task- and
  164.    plan-level behavior. */
  165.  
  166. int
  167. do_move_action(unit, unit2, nx, ny, nz)
  168. Unit *unit, *unit2;
  169. int nx, ny, nz;
  170. {
  171.     int u, u2, nu2, t, rslt, speed, mpcost = 0, acpcost, ox, oy, oz;
  172.  
  173.     u = unit->type;  u2 = unit2->type;
  174.     t = terrain_at(nx, ny);
  175.     ox = unit2->x;  oy = unit2->y;  oz = unit2->z;
  176.     speed = 100;
  177.     mpcost = 1;
  178.     if (!inside_area(nx, ny)) {
  179.     kill_unit(unit2, H_UNIT_LEFT_WORLD);
  180.     rslt = A_ANY_DONE;
  181.     } else if (ut_vanishes_on(u2, t) && !can_move_via_conn(unit2, nx, ny)) {
  182.     kill_unit(unit2, H_UNIT_VANISHED);
  183.     rslt = A_ANY_DONE; /* should return something else :-) */
  184.     } else if (ut_wrecks_on(u2, t) && !can_move_via_conn(unit2, nx, ny)) {
  185.     if (u_wrecked_type(u2) == NONUTYPE) {
  186.         /* Occupants always die if the wrecked unit disappears. */
  187.         kill_unit(unit, H_UNIT_WRECKED);
  188.     } else {
  189.         /* Wreck the unit.  Note that we want to do the wrecking even
  190.            if the unit will vanish, so that occupants can escape if
  191.            allowed for. */
  192.         if (!ut_vanishes_on(u_wrecked_type(u2), t)) {
  193.         speed = unit_speed(unit2, nx, ny);
  194.         mpcost = move_unit(unit2, nx, ny);
  195.         }
  196.         /* Change the unit's type at its new location. */
  197.         change_unit_type(unit2, u_wrecked_type(u2), H_UNIT_WRECKED);
  198.         nu2 = unit2->type;
  199.         /* Restore to default hp for the new type. */
  200.         unit2->hp = unit2->hp2 = u_hp(nu2);
  201.         /* Get rid of occupants if now overfull. */
  202.         eject_excess_occupants(unit2);
  203.         /* Now make it go away, taking unlucky occupants with. */
  204.         if (ut_vanishes_on(nu2, t)) {
  205.         kill_unit(unit2, H_UNIT_VANISHED);
  206.         }
  207.     }
  208.     rslt = A_ANY_DONE;
  209.     } else {
  210.     speed = unit_speed(unit2, nx, ny);
  211.     mpcost = move_unit(unit2, nx, ny);
  212.     /* ZOC move cost is added after action is done. */
  213.     mpcost += zoc_move_cost(unit2, ox, oy, oz);
  214.     rslt = A_ANY_DONE;
  215.     }
  216.     if (alive(unit)) {
  217.         if (speed > 0) {
  218.         acpcost = (mpcost * 100) / speed;
  219.     } else {
  220.         acpcost = 1;
  221.     }
  222.     acpcost = max(acpcost, u_acp_to_move(u2));
  223.     if (acpcost < 1)
  224.       acpcost = 1;
  225.     use_up_acp(unit, acpcost);
  226.     }
  227.     /* Count the unit as having actually moved. */
  228.     if (alive(unit2) && unit2->act)
  229.       ++(unit2->act->actualmoves);
  230.     return rslt;
  231. }
  232.  
  233. int
  234. check_move_action(unit, unit2, nx, ny, nz)
  235. Unit *unit, *unit2;
  236. int nx, ny, nz;
  237. {
  238.     int u, u2, u3, ox, oy, oz, acp, acpavail, mpavail, totcost, m, speed;
  239.  
  240.     if (!in_play(unit))
  241.       return A_ANY_ERROR;
  242.     if (!in_play(unit2))
  243.       return A_ANY_ERROR;
  244.     /* Note that edge cell dests (used to leave the world) are allowed. */
  245.     if (!in_area(nx, ny))
  246.       return A_ANY_ERROR;
  247.     u = unit->type;  u2 = unit2->type;
  248.     ox = unit2->x;  oy = unit2->y;  oz = unit2->z;
  249.     acp = u_acp_to_move(u2);
  250.     if (acp < 1)
  251.       return A_ANY_CANNOT_DO;
  252.     acpavail = unit->act->acp;
  253.     /* If this action is a part of retreating, add more acp to represent the
  254.        motivational power of needing to run away... */
  255.     if (retreating && unit == unit2) {
  256.     if (retreating_from != NONUTYPE) {
  257.         acpavail += uu_acp_retreat(u2, retreating_from);
  258.     }
  259.     }
  260.     /* (should not have to modify the unit, but succeeding calls need this) */
  261.     unit->act->acp = acpavail;
  262.     if (!can_have_enough_acp(unit, acp))
  263.       return A_ANY_CANNOT_DO;
  264.     if (!has_enough_acp(unit, acp))
  265.       return A_ANY_NO_ACP;
  266.     if (!has_supply_to_act(unit2))
  267.       return A_ANY_NO_MATERIAL;
  268.     /* Destination is outside the world and we're not allowed to leave. */
  269.     if (!inside_area(nx, ny) && u_mp_to_leave_world(u2) < 0)
  270.     return A_MOVE_CANNOT_LEAVE_WORLD;
  271.     /* Check if the destination is within our move range. */
  272.     /* (also check for and maybe allow border slides here) */
  273.     if (distance(ox, oy, nx, ny) > u_move_range(u2))
  274.       return A_ANY_TOO_FAR;
  275.     if (nz > 0)
  276.       return A_ANY_TOO_FAR;
  277.     /* Check if the destination is in a blocking ZOC. */
  278.     if (in_blocking_zoc(unit, nx, ny, nz))
  279.       return A_ANY_ERROR;
  280.     /* Now start looking at the move costs. */
  281.     u3 = (unit2->transport ? unit2->transport->type : NONUTYPE);
  282.     totcost = total_move_cost(u2, u3, ox, oy, oz, nx, ny, nz);
  283.     speed = unit_speed(unit2, nx, ny);
  284.     mpavail = (unit->act->acp * speed) / 100;
  285.     /* take into account acp-min in computing mpavail; Massimo */
  286.     if (u_acp_min(u2) < 0)
  287.       mpavail = ((unit->act->acp - u_acp_min(u2)) * speed) / 100;
  288.     /* Zero mp always disallows movement, unless intra-cell. */
  289.     if (mpavail <= 0 && !(ox == nx && oy == ny && oz == nz))
  290.       return A_MOVE_NO_MP;
  291.     /* The free mp might get us enough moves, so add it before comparing. */
  292.     if (mpavail + u_free_mp(u2) < totcost)
  293.       return A_MOVE_NO_MP;
  294.     /* If destination is too small or already full, we can't move into it. */
  295.     if ((nz & 1) == 0) {
  296.     if (!can_occupy_cell(unit2, nx, ny))
  297.       return A_MOVE_DEST_FULL;
  298.     } else {
  299.     if (!can_occupy_conn(unit2, nx, ny, nz))
  300.       return A_MOVE_DEST_FULL;
  301.     }
  302.     /* We have to have a minimum level of supply to be able to move. */
  303.     for_all_material_types(m) {
  304.     if (unit2->supply[m] < um_to_move(u2, m))
  305.       return A_ANY_NO_MATERIAL;
  306.     }
  307.     return A_ANY_OK;
  308. }
  309.  
  310. int
  311. can_move_via_conn(unit, nx, ny)
  312. Unit *unit;
  313. int nx, ny;
  314. {
  315.     int c, dir;
  316.  
  317.     if (numconntypes == 0)
  318.       return FALSE;
  319.     for_all_terrain_types(c) {
  320.         if (t_is_connection(c)
  321.         && aux_terrain_defined(c)
  322.         && (dir = closest_dir(nx - unit->x, ny - unit->y)) >= 0
  323.         && connection_at(unit->x, unit->y, dir, c)
  324.         && !ut_vanishes_on(unit->type, c)
  325.         && !ut_wrecks_on(unit->type, c)) {
  326.         return TRUE;
  327.         }
  328.     }
  329.     return FALSE;
  330. }
  331.  
  332. int
  333. unit_speed(unit, nx, ny)
  334. Unit *unit;
  335. int nx, ny;
  336. {
  337.     int u = unit->type, speed, x = unit->x, y = unit->y, angle, windval;
  338.     int occeff, totocceff, totoccdenom;
  339.     Unit *occ;
  340.     
  341.     speed = u_speed(u);
  342.     if (unit->hp < u_hp_max(u) && u_speed_damage_effect(u) != lispnil) {
  343.     speed = damaged_value(unit, u_speed_damage_effect(u), speed);
  344.     }
  345.     if (winds_defined() && u_speed_wind_effect(u) != lispnil) {
  346.     angle = angle_with(closest_dir(nx - x, nx - y), wind_dir_at(x, y));
  347.     windval = wind_value(unit, angle, wind_force_at(x, y), u_speed_wind_effect(u), 10000);
  348.     speed = (speed * windval) / 100;
  349.     }
  350.     if (unit->occupant /* and any occupant speed effects */) {
  351.         totocceff = 100;
  352.         totoccdenom = 100;
  353.         for_all_occupants(unit, occ) {
  354.         if (completed(occ)) {
  355.         occeff = uu_speed_occ_effect(u, occ->type);
  356.         if (occeff != 100) {
  357.             totocceff *= occeff;
  358.             totoccdenom *= 100;
  359.         }
  360.         }
  361.         }
  362.         speed = (speed * totocceff) / totoccdenom;
  363.     }
  364.     /* Clip to limits. */
  365.     speed = max(speed, u_speed_min(u));
  366.     speed = min(speed, u_speed_max(u));
  367.     return speed;
  368. }
  369.  
  370. /* Compute and return value for a damaged unit, using a list of (hp val) pairs
  371.    and interpolating between them. */
  372.  
  373. int
  374. damaged_value(unit, effect, maxval)
  375. Unit *unit;
  376. Obj *effect;
  377. int maxval;
  378. {
  379.     int u, err, rslt;
  380.  
  381.     u = unit->type;
  382.     err = interpolate_in_list_ext(unit->hp, effect, 0, 0, 0, 0, u_hp(u), maxval, &rslt);
  383.     if (err != 0) {
  384.     run_warning("cannot get damaged speed for %s at hp %d, using 100",
  385.             u_type_name(u), unit->hp);
  386.     rslt = 100;
  387.     }
  388.     return rslt;
  389. }
  390.  
  391. /* Compute and return the wind's effect on a unit, using a list of lists
  392.    and interpolating between them. */
  393.  
  394. int
  395. wind_value(unit, angle, force, effect, maxval)
  396. Unit *unit;
  397. int angle, force, maxval;
  398. Obj *effect;
  399. {
  400.     int err, rslt;
  401.     Obj *rest, *head, *key, *val;
  402.  
  403.     for (rest = effect; rest != lispnil; rest = cdr(rest)) {
  404.     head = car(rest);
  405.     key = car(head);
  406.     if ((numberp(key) && angle == c_number(key))
  407.         || (symbolp(key))
  408.         || (consp(key) && number_member(angle, key))) {
  409.         val = cadr(head);
  410.         if (numberp(val))
  411.           return c_number(val);
  412.         else {
  413.         err = interpolate_in_list(force, val, &rslt);
  414.         if (err == 0) {
  415.             return rslt;
  416.         } else {
  417.             run_warning("no value for wind angle=%d force=%d", angle, force);
  418.             return maxval;
  419.         }
  420.         }
  421.     }
  422.     }
  423.     return maxval;
  424. }
  425.  
  426. int
  427. number_member(x, lis)
  428. int x;
  429. Obj *lis;
  430. {
  431.     Obj *rest;
  432.  
  433.     if (lis == lispnil) {
  434.     return FALSE;
  435.     } else if (!consp(lis)) {
  436.     /* should probably be an error of some sort */
  437.     return FALSE;
  438.     }
  439.     for (rest = lis; rest != lispnil; rest = cdr(rest)) {
  440.     if (numberp(car(rest)) && x == c_number(car(rest)))
  441.       return TRUE;
  442.     }
  443.     return FALSE;
  444. }
  445.  
  446.  
  447. /* Conduct the actual move (used in both normal moves and some combat).
  448.    Note that the new x,y may be the same as the old; this will happen
  449.    if an occupant is getting off a transport but staying in the same cell. */
  450.  
  451. int
  452. move_unit(unit, nx, ny)
  453. Unit *unit;
  454. int nx, ny;
  455. {
  456.     int u = unit->type, u3, ox = unit->x, oy = unit->y, oz = unit->z;
  457.     int nz = oz;
  458.  
  459.     u3 = (unit->transport ? unit->transport->type : NONUTYPE);
  460.     /* Disappear from the old location and appear at the new one. */
  461.     if (unit->transport == NULL /* should be unconditional, but bugs still */)
  462.       change_cell(unit, nx, ny);
  463.     else {
  464.       leave_cell(unit);
  465.       enter_cell(unit, nx, ny);
  466.     }
  467.     /* Movement may set off other people's alarms. */
  468.     maybe_react_to_move(unit, ox, oy);
  469.     /* Might have auto-detonations in response. */
  470.     if (max_detonate_on_approach_range >= 0) {
  471.     detonate_on_approach_around(unit);
  472.     /* A detonation might have been fatal, get out now if so. */
  473.     if (!alive(unit))
  474.       return 1;
  475.     }
  476.     /* The people at the new location may change sides immediately. */
  477.     if (people_sides_defined()
  478.     && any_people_side_changes
  479.     && probability(people_surrender_chance(u, nx, ny))) {
  480.     change_people_side_around(nx, ny, u, unit->side);
  481.     }
  482.     /* Use up supplies as directed. */
  483.     consume_move_supplies(unit);
  484.     /* a hack */
  485.     update_cell_display(unit->side, ox, oy, TRUE);
  486.     /* Always return the mp cost, even if the mover died. */
  487.     return total_move_cost(u, u3, ox, oy, oz, nx, ny, nz);
  488. }
  489.  
  490. int
  491. can_move_at_all(unit)
  492. Unit *unit;
  493. {
  494.     return u_speed(unit->type) > 0;
  495. }
  496.  
  497. /* This is true if the given location is in a blocking zoc for the unit. */
  498.  
  499. int
  500. in_blocking_zoc(unit, x, y, z)
  501. Unit *unit;
  502. int x, y, z;
  503. {
  504.     int u = unit->type, t = terrain_at(x, y), dir, x1, y1, u2, range;
  505.     Unit *unit2;
  506.  
  507.     if (max_zoc_range < 0)
  508.       return FALSE;
  509.     if (max_zoc_range >= 0) {
  510.     for_all_stack(x, y, unit2) {
  511.         range = zoc_range(unit2, u);
  512.         if (range >= 0
  513.         && unit_blockable_by(unit, unit2)
  514.         && ut_zoc_into(unit2->type, t)
  515.         && ut_zoc_from_terrain(unit2->type, t) > 0)
  516.           return TRUE;
  517.     }
  518.     }
  519.     if (max_zoc_range >= 1) {
  520.     for_all_directions(dir) {
  521.         if (point_in_dir(x, y, dir, &x1, &y1)) {
  522.         for_all_stack(x, y, unit2) {
  523.             u2 = unit2->type;
  524.             range = zoc_range(unit2, u);
  525.             if (range >= 1
  526.             && unit_blockable_by(unit, unit2)
  527.             && ut_zoc_into(u2, t))
  528.               return TRUE;
  529.         }
  530.         }
  531.     }
  532.     }
  533.     if (max_zoc_range >= 2) {
  534.     run_warning("Max zoc range >= 2 not implemented");
  535.     }
  536.     return FALSE;
  537. }
  538.  
  539. /* This is true if unit2 wants to block unit from moving. */
  540.  
  541. int
  542. unit_blockable_by(unit, unit2)
  543. Unit *unit, *unit2;
  544. {
  545.     return (!trusted_side(unit2->side, unit2->side) /* should make a better test */
  546.         && uu_mp_to_enter_zoc(unit->type, unit2->type) < 0);
  547. }
  548.  
  549. /* Compute the number of move points that will be needed to do the given
  550.    move. */
  551.  
  552. int
  553. total_move_cost(u, u2, x1, y1, z1, x2, y2, z2)
  554. int u, u2, x1, y1, z1, x2, y2, z2;
  555. {
  556.     int cost, ferry, b, c, conncost, dist, dir;
  557.  
  558.     if (z1 != 0 || z2 != 0) {
  559.         /* should write these calcs eventually */
  560.     }
  561.     dist = distance(x1, y1, x2, y2);
  562.     if (dist == 0) {
  563.     if (z2 != z1) {
  564.         /* (should have parms for up/down in same cell) */
  565.         return 1;
  566.     } else {
  567.             /* Unit is leaving a transport and moving into the open here;
  568.                free of charge. */
  569.             return 0;
  570.         }
  571.     } else if (dist == 1) {
  572.         /* (fall through) */
  573.     } else {
  574.         /* Border slide or multiple cell move. */
  575.         /* (should implement) */
  576.         return 9999;
  577.     }
  578.     cost = 0;
  579.     ferry = 0;
  580.     if (u2 != NONUTYPE) {
  581.     /* Charge for leaving the transport. */
  582.         cost += uu_mp_to_leave(u, u2);
  583.         /* See what type of ferrying we're going to get. */
  584.         ferry = uu_ferry_on_leave(u2, u);
  585.     }
  586.     if (ferry < 1) {
  587.         cost += ut_mp_to_leave(u, terrain_at(x1, y1));
  588.     }
  589.     if (numbordtypes > 0 && ferry < 2) {
  590.     /* Add any necessary border crossing costs. */
  591.     dir = closest_dir(x2 - x1, y2 - y1);
  592.     if (dir >= 0) {
  593.         for_all_terrain_types(b) {
  594.         if (t_is_border(b)
  595.             && aux_terrain_defined(b)
  596.             && border_at(x1, y1, dir, b)) {
  597.             cost += ut_mp_to_enter(u, b);
  598.         }
  599.         }
  600.     }
  601.     }
  602.     if (ferry < 3) {
  603.     cost += ut_mp_to_enter(u, terrain_at(x2, y2));
  604.     }
  605.     /* Use a connection traversal if it would be cheaper.  This is
  606.        only automatic if the connection on/off costs are small enough,
  607.        otherwise the unit has to do explicit actions to get on the
  608.        connection and off again. */
  609.     if (numconntypes > 0) {
  610.     /* Try each connection type to see if it's better. */
  611.     dir = closest_dir(x2 - x1, y2 - y1);
  612.     if (dir >= 0) {
  613.         for_all_terrain_types(c) {
  614.         if (t_is_connection(c)
  615.             && aux_terrain_defined(c)
  616.             && connection_at(x1, y1, dir, c)) {
  617.             conncost = ut_mp_to_enter(u, c)
  618.               + ut_mp_to_traverse(u, c)
  619.             + ut_mp_to_leave(u, c);
  620.             cost = min(cost, conncost);
  621.         }
  622.         }
  623.     }
  624.     }
  625.     /* The cost of leaving the world is always an addon. */
  626.     if (!inside_area(x2, y2)) {
  627.         cost += u_mp_to_leave_world(u);
  628.     }
  629.     /* Any (inter-cell) movement must always cost at least 1 mp. */
  630.     if (cost < 1)
  631.       cost = 1;
  632.     return cost;
  633. }
  634.  
  635. int
  636. zoc_range(unit, u2)
  637. Unit *unit;
  638. int u2;
  639. {
  640.     int u = unit->type;
  641.  
  642.     return (uu_zoc_range(u, u2)
  643.         * ut_zoc_from_terrain(u, terrain_at(unit->x, unit->y))) / 100;
  644. }
  645.  
  646. int
  647. zoc_move_cost(unit, ox, oy, oz)
  648. Unit *unit;
  649. int ox, oy, oz;
  650. {
  651.     int u = unit->type, u2, t1, t2, cost, mpcost, dir, x1, y1, range;
  652.     Unit *unit2;
  653.  
  654.     /* If this is negative, ZOCs are not part of this game. */
  655.     if (max_zoc_range < 0)
  656.       return 0;
  657.     if (!in_play(unit))
  658.       return 0;
  659.     mpcost = 0;
  660.     t1 = terrain_at(ox, oy);
  661.     t2 = terrain_at(unit->x, unit->y);
  662.     if (max_zoc_range == 0 || max_zoc_range == 1) {
  663.         /* ZOCs of units in old cell. */
  664.     for_all_stack(ox, oy, unit2) {
  665.         u2 = unit2->type;
  666.             range = zoc_range(unit2, u);
  667.         if (in_play(unit2) /* should be is_active? */
  668.         && unit2->side != unit->side
  669.         && range >= 0
  670.         && ut_zoc_into(u2, t1)
  671.         /* should account for from-terrain also */
  672.         )
  673.           mpcost = max(mpcost, uu_mp_to_leave_zoc(u, u2));
  674.     }
  675.     /* ZOCs of units in new cell. */
  676.     for_all_stack(unit->x, unit->y, unit2) {
  677.         u2 = unit2->type;
  678.             range = zoc_range(unit2, u);
  679.         if (in_play(unit2) /* should be is_active? */
  680.         && unit2->side != unit->side
  681.         && range >= 0
  682.         && ut_zoc_into(u2, t2))
  683.           mpcost = max(mpcost, uu_mp_to_enter_zoc(u, u2));
  684.     }
  685.     }
  686.     if (max_zoc_range > 0) {
  687.       if (max_zoc_range == 1) {
  688.         /* ZOCs may be into adjacent cells. */
  689.         /* Look for everybody that was exerting ZOC into the old location. */
  690.         /* (should calc with stacked units also) */
  691.     for_all_directions(dir) {
  692.         if (point_in_dir(ox, oy, dir, &x1, &y1)) {
  693.         for_all_stack(x1, y1, unit2) {
  694.             u2 = unit2->type;
  695.                     range = zoc_range(unit2, u);
  696.             if (in_play(unit2) /* should be is_active? */
  697.             && unit2->side != unit->side  /* and unfriendly */
  698.             && range >= 1
  699.             && ut_zoc_into(u2, t1)) {
  700.             if (1 /* leaving zoc */) {
  701.                 cost = uu_mp_to_leave_zoc(u, u2);
  702.             } else {
  703.                 cost = uu_mp_to_traverse_zoc(u, u2);
  704.             }
  705.             mpcost = max(mpcost, cost);
  706.             }
  707.             /* (and occupants?) */
  708.         }
  709.         }
  710.     }
  711.         /* Look for everybody that is now exerting ZOC into the new location. */
  712.         /* (should calc with stacked units also) */
  713.     for_all_directions(dir) {
  714.         if (point_in_dir(unit->x, unit->y, dir, &x1, &y1)) {
  715.         for_all_stack(x1, y1, unit2) {
  716.             u2 = unit2->type;
  717.                     range = zoc_range(unit2, u);
  718.             if (in_play(unit2) /* should be is_active? */
  719.             && unit2->side != unit->side  /* and unfriendly */
  720.             && range >= 1
  721.             && ut_zoc_into(u2, t2)) {
  722.             if (1 /* entering zoc */) {
  723.                 cost = uu_mp_to_enter_zoc(u, u2);
  724.             } else {
  725.                 cost = uu_mp_to_traverse_zoc(u, u2);
  726.             }
  727.             mpcost = max(mpcost, cost);
  728.             }
  729.             /* (and occupants?) */
  730.         }
  731.         }
  732.     }
  733.       } else {
  734.     /* General case. */
  735.         /* (should write this case - bleah, complicated) */
  736.         run_error("No zoc ranges > 1 allowed");
  737.       }
  738.     }
  739.     return mpcost;
  740. }
  741.  
  742. /* This is a hook to handle any reactions to the unit's successful move. */
  743.  
  744. int
  745. maybe_react_to_move(unit, ox, oy)
  746. Unit *unit;
  747. int ox, oy;
  748. {
  749.     return 0;
  750. }
  751.  
  752. static void
  753. try_detonate_on_approach(x, y)
  754. int x, y;
  755. {
  756.     int dist;
  757.     Unit *unit;
  758.  
  759.     dist = distance(tmpunit->x, tmpunit->y, x, y);
  760.     for_all_stack(x, y, unit) {
  761.     if (unit->side != tmpunit->side
  762.         && dist <= uu_detonate_approach_range(unit->type, tmpunit->type)
  763.         /* (should make doctrine-based decision about whether to go off) */
  764.         && !was_detonated(unit)
  765.         ) {
  766.         detonate_unit(unit, unit->x, unit->y, unit->z);
  767.     }
  768.     }
  769. }
  770.  
  771. void
  772. detonate_on_approach_around(unit)
  773. Unit *unit;
  774. {
  775.     int maxrange;
  776.  
  777.     tmpunit = unit;
  778.     apply_to_area(unit->x, unit->y, max_detonate_on_approach_range, try_detonate_on_approach);
  779.     maxrange = max(max_u_detonate_effect_range, max_t_detonate_effect_range) + max_detonate_on_approach_range;
  780.     reckon_damage_around(unit->x, unit->y, maxrange);
  781. }
  782.  
  783. /* Use up the supply consumed by a successful move.  Also, the move might
  784.    have used up essentials and left the unit without its survival needs,
  785.    so check for this case and maybe hit/kill the unit. */
  786.  
  787. void  
  788. consume_move_supplies(unit)
  789. Unit *unit;
  790. {
  791.     int u = unit->type, m, checkstarve = FALSE;
  792.     
  793.     for_all_material_types(m) {
  794.     if (um_consumption_per_move(u, m) > 0) {
  795.         unit->supply[m] -= um_consumption_per_move(u, m);
  796.         /* Don't let supply go below zero. */
  797.         if (unit->supply[m] <= 0) {
  798.         unit->supply[m] = 0;
  799.         checkstarve = TRUE;
  800.         }
  801.     }
  802.     }
  803.     if (checkstarve)
  804.       maybe_starve(unit, FALSE);
  805.     /* Trigger any supply alarms. */
  806.     if (alive(unit)
  807.         && unit->plan
  808.         && !unit->plan->supply_is_low
  809.         && past_halfway_point(unit)
  810.         ) {
  811.         unit->plan->supply_is_low = TRUE;
  812.         update_unit_display(unit->side, unit, TRUE); 
  813.     }
  814. }
  815.  
  816. /* Movement into another unit. */
  817.  
  818. /* Record an enter action as the next to do. */
  819.  
  820. int
  821. prep_enter_action(unit, unit2, unit3)
  822. Unit *unit, *unit2, *unit3;
  823. {
  824.     if (unit == NULL || unit->act == NULL)
  825.       return FALSE;
  826.     if (unit2 == NULL)
  827.       return FALSE;
  828.     if (unit3 == NULL)
  829.       return FALSE;
  830.     unit->act->nextaction.type = ACTION_ENTER;
  831.     unit->act->nextaction.args[0] = unit3->id;
  832.     unit->act->nextaction.actee = unit2->id;
  833.     broadcast_next_action(unit);
  834.     return TRUE;
  835. }
  836.  
  837. int
  838. do_enter_action(unit, unit2, unit3)
  839. Unit *unit, *unit2, *unit3;
  840. {
  841.     int u2, u3, u4, ox, oy, oz, nx, ny, nz, speed, acpcost, mpcost;
  842.  
  843.     u2 = unit2->type;
  844.     ox = unit2->x;  oy = unit2->y;  oz = unit2->z;
  845.     u3 = unit3->type;
  846.     nx = unit3->x;  ny = unit3->y;  nz = unit3->z;
  847.     /* Change the unit's position. */
  848.     leave_cell(unit2);
  849.     enter_transport(unit2, unit3);
  850.     /* Calculate how much acp has been used up. */
  851.     u4 = (unit2->transport ? unit2->transport->type : NONUTYPE);
  852.     mpcost = total_entry_cost(u2, u4, ox, oy, oz, u3, nx, ny, nz);
  853.     if (alive(unit)) {
  854.     speed = u_speed(u2);
  855.     if (speed > 0) {
  856.         acpcost = (mpcost * 100) / speed;
  857.     } else {
  858.         acpcost = 1;
  859.     }
  860.     use_up_acp(unit, acpcost + uu_acp_to_enter(u2, u3));
  861.     }
  862.     return A_ANY_DONE;
  863. }
  864.  
  865. int
  866. check_enter_action(unit, unit2, unit3)
  867. Unit *unit, *unit2, *unit3;
  868. {
  869.     int u, u2, u3, u4, u2x, u2y, u3x, u3y, totcost, speed, mpavail;
  870.     int ox, oy, oz, nx, ny, nz;
  871.  
  872.     if (!in_play(unit))
  873.       return A_ANY_ERROR;
  874.     if (!in_play(unit2))
  875.       return A_ANY_ERROR;
  876.     if (!in_play(unit3))
  877.       return A_ANY_ERROR;
  878.     u = unit->type;
  879.     u2 = unit2->type;
  880.     u3 = unit3->type;
  881.     if (uu_acp_to_enter(u2, u3) < 1)
  882.       return A_ANY_CANNOT_DO;
  883.     if (!can_have_enough_acp(unit, uu_acp_to_enter(u2, u3)))
  884.       return A_ANY_CANNOT_DO;
  885.     /* Can't enter self. */
  886.     if (unit2 == unit3)
  887.       return A_ANY_ERROR;
  888.     u2x = unit2->x;  u2y = unit2->y;
  889.     u3x = unit3->x;  u3y = unit3->y;
  890.     ox = unit2->x;  oy = unit2->y;  oz = unit2->z;
  891.     nx = unit3->x;  ny = unit3->y;  nz = unit3->z;
  892.     if (!between(0, distance(ox, oy, nx, ny), 1))
  893.       return A_ANY_ERROR;
  894.     if (!sides_allow_entry(unit2, unit3))
  895.       return A_ANY_ERROR;
  896.     if (!can_occupy(unit2, unit3))
  897.       return A_ANY_ERROR;
  898.     if (!has_enough_acp(unit, uu_acp_to_enter(u2, u3)))
  899.       return A_ANY_NO_ACP;
  900.     u4 = (unit2->transport ? unit2->transport->type : NONUTYPE);
  901.     totcost = total_entry_cost(u2, u4, ox, oy, oz, u3, nx, ny, nz);
  902.     speed = u_speed(u2);
  903.     /* (should generalize!) */
  904.     if (winds_defined() && u_speed_wind_effect(u2) != lispnil) {
  905.     speed *= wind_force_at(u3x, u3y);
  906.     }
  907.     if (speed > 0 && unit->act) {
  908.     mpavail = (unit->act->acp * speed) / 100;
  909.     } else {
  910.     mpavail = 0;
  911.     }
  912.     /* If transport picks up the unit itself, no need to check mp. */
  913.     if (uu_ferry_on_enter(u3, u2) < 3) {
  914.     /* Zero mp always disallows movement. */
  915.     if (mpavail <= 0)
  916.       return A_MOVE_NO_MP;
  917.     /* The free mp might get us enough moves, so add it before comparing. */
  918.     if (mpavail + u_free_mp(u2) < totcost)
  919.       return A_MOVE_NO_MP;
  920.     }
  921.     /* (should check materials available) */
  922.     return A_ANY_OK;
  923. }
  924.  
  925. /* This tests whether the relationship between the sides of a unit
  926.    and a prospective transport allows for entry of the unit. */
  927.  
  928. int
  929. sides_allow_entry(unit, transport)
  930. Unit *unit, *transport;
  931. {
  932.     if (unit->side == NULL) {
  933.         if (transport->side == NULL) {
  934.             return TRUE;
  935.         } else {
  936.             return uu_can_enter_indep(unit->type, transport->type);
  937.         }
  938.     } else {
  939.         if (transport->side == NULL) {
  940.             return uu_can_enter_indep(unit->type, transport->type);
  941.         } else {
  942.         /* Note that because this is for an explicit action, the unit
  943.            must trust the transport, so the only test is whether the
  944.            transports trusts the unit enough to have it as an occupant. */
  945.             return unit_trusts_unit(transport, unit);
  946.         }
  947.     }
  948. }
  949.  
  950. /* This computes the total mp cost of entering a transport. */
  951.  
  952. int
  953. total_entry_cost(u1, u3, x1, y1, z1, u2, x2, y2, z2)
  954. int u1, u3, x1, y1, z1, u2, x2, y2, z2;
  955. {
  956.     int cost = 0, ferryout, ferryin, t1, t2, b, dir, conncost, c;
  957.  
  958.     ferryout = 0;
  959.     ferryin = uu_ferry_on_enter(u2, u1);
  960.     if (u3 != NONUTYPE) {
  961.     /* Charge for leaving the transport. */
  962.         cost += uu_mp_to_leave(u1, u3);
  963.         ferryout = uu_ferry_on_leave(u3, u1);
  964.     }
  965.     /* (should include possibility of using conn to cross terrain) */
  966.     /* Maybe add cost to leave terrain of own cell. */
  967.     if (ferryout < 1 && ferryin < 3) {
  968.     t1 = terrain_at(x1, y1);
  969.         cost += ut_mp_to_leave(u1, t1);
  970.     }
  971.     /* Maybe add cost to cross one (or more) borders. */
  972.     if (numbordtypes > 0 && ferryout < 2 && ferryin < 2) {
  973.     dir = closest_dir(x2 - x1, y2 - y1);
  974.     if (dir >= 0) {
  975.         for_all_terrain_types(b) {
  976.         if (t_is_border(b)
  977.             && aux_terrain_defined(b)
  978.             && border_at(x1, y1, dir, b)) {
  979.             cost += ut_mp_to_enter(u1, b);
  980.         }
  981.         }
  982.     }
  983.     }
  984.     /* Maybe even have to pay cost of crossing destination's terrain. */
  985.     if (ferryout < 3 && ferryin < 1) {
  986.     t2 = terrain_at(x2, y2);
  987.         cost += ut_mp_to_enter(u1, t2);
  988.     }
  989.     /* Use a connection traversal if it would be cheaper.  This is
  990.        only automatic if the connection on/off costs are small enough,
  991.        otherwise the unit has to do explicit actions to get on the
  992.        connection and off again. */
  993.     if (numconntypes > 0) {
  994.     /* Try each connection type to see if it's better. */
  995.     dir = closest_dir(x2 - x1, y2 - y1);
  996.     if (dir >= 0) {
  997.         for_all_terrain_types(c) {
  998.         if (t_is_connection(c)
  999.             && aux_terrain_defined(c)
  1000.             && connection_at(x1, y1, dir, c)) {
  1001.             conncost = ut_mp_to_enter(u1, c)
  1002.               + ut_mp_to_traverse(u1, c)
  1003.             + ut_mp_to_leave(u1, c);
  1004.             cost = min(cost, conncost);
  1005.         }
  1006.         }
  1007.     }
  1008.     }
  1009.     /* Add the actual cost of entry. */
  1010.     cost += uu_mp_to_enter(u1, u2);
  1011.     /* Movement must always cost at least 1 mp. */
  1012.     if (cost < 1)
  1013.       cost = 1;
  1014.     return cost;
  1015. }
  1016.  
  1017. /* Material actions. */
  1018.  
  1019. /* Explicit material production. */
  1020.  
  1021. int
  1022. prep_produce_action(unit, unit2, m, n)
  1023. Unit *unit, *unit2;
  1024. int m, n;
  1025. {
  1026.     if (unit == NULL || unit->act == NULL)
  1027.       return FALSE;
  1028.     if (unit2 == NULL)
  1029.       return FALSE;
  1030.     unit->act->nextaction.type = ACTION_PRODUCE;
  1031.     unit->act->nextaction.args[0] = m;
  1032.     unit->act->nextaction.args[1] = n;
  1033.     unit->act->nextaction.actee = unit2->id;
  1034.     broadcast_next_action(unit);
  1035.     return TRUE;
  1036. }
  1037.  
  1038. int
  1039. do_produce_action(unit, unit2, m, n)
  1040. Unit *unit, *unit2;
  1041. int m, n;
  1042. {
  1043.     int amt;
  1044.  
  1045.     amt = min(n, um_material_per_production(unit2->type, m));
  1046.     unit2->supply[m] += n;
  1047.     use_up_acp(unit, um_acp_to_produce(unit2->type, m));
  1048.     return A_ANY_DONE;
  1049. }
  1050.  
  1051. int
  1052. check_produce_action(unit, unit2, m, n)
  1053. Unit *unit, *unit2;
  1054. int m, n;
  1055. {
  1056.     int acp, m2;
  1057.  
  1058.     if (!in_play(unit))
  1059.       return A_ANY_ERROR;
  1060.     if (!in_play(unit2))
  1061.       return A_ANY_ERROR;
  1062.     if (!is_material_type(m))
  1063.       return A_ANY_ERROR;
  1064.     acp = um_acp_to_produce(unit2->type, m);
  1065.     if (acp < 1)
  1066.       return A_ANY_CANNOT_DO;
  1067.     if (!can_have_enough_acp(unit, acp))
  1068.       return A_ANY_CANNOT_DO;
  1069.     if (um_material_per_production(unit2->type, m) < 1)
  1070.       return A_ANY_CANNOT_DO;
  1071.     if (!has_enough_acp(unit, acp))
  1072.       return A_ANY_NO_ACP;
  1073.     /* Check that the unit has any required supplies. */
  1074.     for_all_material_types(m2) {
  1075.     if (unit2->supply[m2] < um_to_produce(unit2->type, m2))
  1076.       return A_ANY_NO_MATERIAL;
  1077.     }
  1078.     return A_ANY_OK;
  1079. }
  1080.  
  1081. /* Transfer action. */
  1082.  
  1083. /* This action transfers material from one unit to another. */
  1084.  
  1085. int
  1086. prep_transfer_action(unit, unit2, m, n, unit3)
  1087. Unit *unit, *unit2, *unit3;
  1088. int m, n;
  1089. {
  1090.     if (unit == NULL || unit->act == NULL)
  1091.       return FALSE;
  1092.     if (unit2 == NULL)
  1093.       return FALSE;
  1094.     if (unit3 == NULL)
  1095.       return FALSE;
  1096.     unit->act->nextaction.type = ACTION_TRANSFER;
  1097.     unit->act->nextaction.args[0] = m;
  1098.     unit->act->nextaction.args[1] = n;
  1099.     unit->act->nextaction.args[2] = unit3->id;
  1100.     unit->act->nextaction.actee = unit2->id;
  1101.     broadcast_next_action(unit);
  1102.     return TRUE;
  1103. }
  1104.  
  1105. int
  1106. do_transfer_action(unit, unit2, m, n, unit3)
  1107. Unit *unit, *unit2, *unit3;
  1108. int m, n;
  1109. {
  1110.     int actual;
  1111.  
  1112.     if (n > 0) {
  1113.         actual = transfer_supply(unit2, unit3, m, n);
  1114.     } else {
  1115.         actual = transfer_supply(unit3, unit2, m, -n);
  1116.     }
  1117.     use_up_acp(unit, 1);
  1118.     if (actual == n) {
  1119.     return A_ANY_DONE;
  1120.     } else if (actual == 0) {
  1121.     return A_ANY_ERROR;
  1122.     } else {
  1123.         /* (should be able to say that action did not do all that was requested) */
  1124.     return A_ANY_DONE;
  1125.     }
  1126. }
  1127.  
  1128. int
  1129. check_transfer_action(unit, unit2, m, n, unit3)
  1130. Unit *unit, *unit2, *unit3;
  1131. int m, n;
  1132. {
  1133.     if (!in_play(unit))
  1134.       return A_ANY_ERROR;
  1135.     if (!in_play(unit2))
  1136.       return A_ANY_ERROR;
  1137.     if (!is_material_type(m))
  1138.       return A_ANY_ERROR;
  1139.     if (n == 0)
  1140.       return A_ANY_ERROR;
  1141.     if (!in_play(unit3))
  1142.       return A_ANY_ERROR;
  1143.     if (um_acp_to_unload(unit2->type, m) < 1)
  1144.       return A_ANY_CANNOT_DO;
  1145.     if (unit3->act && um_acp_to_load(unit3->type, m) < 1)
  1146.       return A_ANY_CANNOT_DO;
  1147.     if (!can_have_enough_acp(unit, 1))
  1148.       return A_ANY_CANNOT_DO;
  1149.     if (n > 0) {
  1150.     if (unit2->supply[m] <= 0)
  1151.       return A_ANY_ERROR;
  1152.     if (um_storage_x(unit3->type, m) == 0)
  1153.       return A_ANY_ERROR;
  1154.     } else {
  1155.     if (unit3->supply[m] <= 0)
  1156.       return A_ANY_ERROR;
  1157.     if (um_storage_x(unit2->type, m) == 0)
  1158.       return A_ANY_ERROR;
  1159.     }
  1160.     if (!has_enough_acp(unit, 1))
  1161.       return A_ANY_NO_ACP;
  1162.     return A_ANY_OK;
  1163. }
  1164.  
  1165. /* Move supply from one unit to another.  Don't move more than is possible;
  1166.    check both from and to amounts and capacities. */
  1167.  
  1168. int
  1169. transfer_supply(from, to, m, amount)
  1170. Unit *from, *to;
  1171. int m, amount;
  1172. {
  1173.     int origfrom = from->supply[m], origto = to->supply[m];
  1174.  
  1175.     amount = min(amount, origfrom);
  1176.     amount = min(amount, um_storage_x(to->type, m) - origto);
  1177.     if (um_unload_max(from->type, m) >= 0) {
  1178.     amount = min(amount, um_unload_max(from->type, m));
  1179.     }
  1180.     if (um_load_max(to->type, m) >= 0) {
  1181.     amount = min(amount, um_load_max(to->type, m));
  1182.     }
  1183.     from->supply[m] -= amount;
  1184.     to->supply[m] += amount;
  1185.     /* Make sure any displays of supply levels see the transfer. */
  1186.     update_unit_display(from->side, from, TRUE); 
  1187.     update_unit_display(to->side, to, TRUE); 
  1188.     Dprintf("%s (had %d) transfers %d %s to %s (had %d)\n",
  1189.         unit_desig(from), origfrom, amount, m_type_name(m),
  1190.         unit_desig(to), origto);
  1191.     return amount;
  1192. }
  1193.  
  1194. /* Research action. */
  1195.  
  1196. /* If a side's tech level is under its max, research can increase it. */
  1197.  
  1198. int
  1199. prep_research_action(unit, unit2, u3)
  1200. Unit *unit, *unit2;
  1201. int u3;
  1202. {
  1203.     if (unit == NULL || unit->act == NULL)
  1204.       return FALSE;
  1205.     if (unit2 == NULL)
  1206.       return FALSE;
  1207.     unit->act->nextaction.type = ACTION_RESEARCH;
  1208.     unit->act->nextaction.args[0] = u3;
  1209.     unit->act->nextaction.actee = unit2->id;
  1210.     broadcast_next_action(unit);
  1211.     return TRUE;
  1212. }
  1213.  
  1214. int
  1215. do_research_action(unit, unit2, u3)
  1216. Unit *unit, *unit2;
  1217. int u3;
  1218. {
  1219.     int u2 = unit2->type, lim;
  1220.     Side *side = unit2->side;
  1221.  
  1222.     side->tech[u3] += prob_fraction(uu_tech_per_research(u2, u3));
  1223.     /* Silently apply the per-side-per-turn limit on tech gains. */
  1224.     lim =  side->inittech[u3] + u_tech_per_turn_max(u3);
  1225.     if (side->tech[u3] > lim)
  1226.       side->tech[u3] = lim;
  1227.     /* Adjust the tech levels of any related unit types to match. */
  1228.     adjust_tech_crossover(side, u3);
  1229.     /* (should notify side about changes and/or thresholds reached?) */
  1230.     use_up_acp(unit, uu_acp_to_research(u2, u3));
  1231.     return A_ANY_DONE;
  1232. }
  1233.  
  1234. int
  1235. check_research_action(unit, unit2, u3)
  1236. Unit *unit, *unit2;
  1237. int u3;
  1238. {
  1239.     int u, u2;
  1240.     Side *side;
  1241.  
  1242.     if (!in_play(unit))
  1243.       return A_ANY_ERROR;
  1244.     if (!in_play(unit2))
  1245.       return A_ANY_ERROR;
  1246.     if (!is_unit_type(u3))
  1247.       return A_ANY_ERROR;
  1248.     u = unit->type;
  1249.     u2 = unit2->type;
  1250.     side = unit->side;
  1251.     /* Independent units don't do research. */
  1252.     if (side == NULL)
  1253.       return A_ANY_ERROR;
  1254.     /* This unit must be of a type that can research the given type. */
  1255.     if (uu_acp_to_research(u2, u3) < 1)
  1256.       return A_ANY_CANNOT_DO;
  1257.     if (!can_have_enough_acp(unit, uu_acp_to_research(u2, u3)))
  1258.       return A_ANY_CANNOT_DO;
  1259.     /* Max tech level means there's nothing more to learn. */
  1260.     if (side->tech[u3] >= u_tech_max(u3))
  1261.       return A_ANY_ERROR;
  1262.     if (!has_enough_acp(unit, uu_acp_to_research(u2, u3)))
  1263.       return A_ANY_NO_ACP;
  1264.     return A_ANY_OK;
  1265. }
  1266.  
  1267. /* For all unit types, bring their tech level up to match the crossovers
  1268.    from the given unit type. */
  1269.  
  1270. void
  1271. adjust_tech_crossover(side, u)
  1272. Side *side;
  1273. int u;
  1274. {
  1275.     int u2, cross;
  1276.  
  1277.     for_all_unit_types(u2) {
  1278.     if (u2 != u) {
  1279.         /* (should be "as ratio of max levels for each type") */
  1280.         cross = (uu_tech_crossover(u, u2) * side->tech[u2]) / 100;
  1281.         if (cross > side->tech[u2]) side->tech[u2] = cross;
  1282.     }
  1283.     }
  1284. }
  1285.  
  1286. /* Toolup action. */
  1287.  
  1288. /* Before a unit can build another, it may need to take some time to prepare by
  1289.    "tooling up". */
  1290.  
  1291. int
  1292. prep_toolup_action(unit, unit2, u3)
  1293. Unit *unit, *unit2;
  1294. int u3;
  1295. {
  1296.     if (unit == NULL || unit->act == NULL)
  1297.       return FALSE;
  1298.     if (unit2 == NULL)
  1299.       return FALSE;
  1300.     unit->act->nextaction.type = ACTION_TOOL_UP;
  1301.     unit->act->nextaction.args[0] = u3;
  1302.     unit->act->nextaction.actee = unit2->id;
  1303.     broadcast_next_action(unit);
  1304.     return TRUE;
  1305. }
  1306.  
  1307. int
  1308. do_toolup_action(unit, unit2, u3)
  1309. Unit *unit, *unit2;
  1310. int u3;
  1311. {
  1312.     int tp;
  1313.  
  1314.     if (unit2->tooling == NULL)
  1315.       init_unit_tooling(unit2);
  1316.     /* Increase the tooling, clipping to its max. */
  1317.     tp = unit2->tooling[u3];
  1318.     tp += uu_tp_per_toolup(unit2->type, u3);
  1319.     tp = min(tp, uu_tp_max(unit2->type, u3));
  1320.     unit2->tooling[u3] = tp;
  1321.     /* Adjust any related toolings. */
  1322.     adjust_tooling_crossover(unit2, u3);
  1323.     /* Consume acp. */
  1324.     use_up_acp(unit, uu_acp_to_toolup(unit2->type, u3));
  1325.     return A_ANY_DONE;
  1326. }
  1327.  
  1328. int
  1329. check_toolup_action(unit, unit2, u3)
  1330. Unit *unit, *unit2;
  1331. int u3;
  1332. {
  1333.     int acp, tp;
  1334.  
  1335.     if (!in_play(unit))
  1336.       return A_ANY_ERROR;
  1337.     if (!in_play(unit2))
  1338.       return A_ANY_ERROR;
  1339.     if (!is_unit_type(u3))
  1340.       return A_ANY_ERROR;
  1341.     acp = uu_acp_to_toolup(unit2->type, u3);
  1342.     if (acp < 1)
  1343.       return A_ANY_CANNOT_DO;
  1344.     if (!can_have_enough_acp(unit, acp))
  1345.       return A_ANY_CANNOT_DO;
  1346.     tp = (unit2->tooling ? unit2->tooling[u3] : 0);
  1347.     /* Check if tooling is already at its max. */
  1348.     if (tp >= uu_tp_max(unit2->type, u3))
  1349.       return A_ANY_ERROR;
  1350.     if (!has_enough_acp(unit, acp))
  1351.       return A_ANY_NO_ACP;
  1352.     return A_ANY_OK;
  1353. }
  1354.  
  1355. /* For all unit types, bring their tooling level up to match the crossovers
  1356.    from the given unit type. */
  1357.  
  1358. void
  1359. adjust_tooling_crossover(unit, u2)
  1360. Unit *unit;
  1361. int u2;
  1362. {
  1363.     int u3, uucross, cross, tp2, tp3;
  1364.  
  1365.     /* Perhaps nothing to cross over with. */
  1366.     if (unit->tooling == NULL)
  1367.       return;
  1368.     for_all_unit_types(u3) {
  1369.     if (u3 != u2) {
  1370.         uucross = uu_tp_crossover(u2, u3);
  1371.         if (uucross > 0) {
  1372.         tp2 = unit->tooling[u2];
  1373.         tp3 = unit->tooling[u3];
  1374.         /* (should be "as ratio of max levels for each type") */
  1375.         cross = (uucross * tp2) / 100;
  1376.         if (cross > tp3)
  1377.           unit->tooling[u3] = cross;
  1378.         }
  1379.     }
  1380.     }
  1381. }
  1382.  
  1383. /* Create-in action. */
  1384.  
  1385. /* This action creates the (incomplete) unit. */
  1386.  
  1387. int
  1388. prep_create_in_action(unit, unit2, u3, dest)
  1389. Unit *unit, *unit2, *dest;
  1390. int u3;
  1391. {
  1392.     if (unit == NULL || unit->act == NULL)
  1393.       return FALSE;
  1394.     if (unit2 == NULL)
  1395.       return FALSE;
  1396.     if (dest == NULL)
  1397.       return FALSE;
  1398.     unit->act->nextaction.type = ACTION_CREATE_IN;
  1399.     unit->act->nextaction.args[0] = u3;
  1400.     unit->act->nextaction.args[1] = dest->id;
  1401.     unit->act->nextaction.actee = unit2->id;
  1402.     broadcast_next_action(unit);
  1403.     return TRUE;
  1404. }
  1405.  
  1406. int
  1407. do_create_in_action(unit, unit2, u3, dest)
  1408. Unit *unit, *unit2, *dest;
  1409. int u3;
  1410. {
  1411.     int u2 = unit2->type, m;
  1412.     Unit *newunit;
  1413.  
  1414.     /* Make the new unit. */
  1415.     newunit = create_unit(u3, FALSE);
  1416.     if (newunit != NULL) {
  1417.     /* Fill in various properties. */
  1418.     set_created_unit_props(newunit, u2, unit->side);
  1419.     /* Put the new unit inside the designated transport. */
  1420.     enter_transport(newunit, dest);
  1421.     /* Unit might have started out complete. */
  1422.     if (completed(newunit)) {
  1423.         garrison_unit(unit2, newunit);
  1424.         make_unit_complete(newunit);
  1425.     } else {
  1426.         record_event(H_UNIT_CREATED, add_side_to_set(unit2->side, NOSIDES),
  1427.              side_number(unit2->side), newunit->id);
  1428.     }
  1429.     if (alive(unit2)) {
  1430.         count_gain(unit2->side, newunit->type, build_gain);
  1431.         /* Consume the creator's supplies as specified. */
  1432.         for_all_material_types(m) {
  1433.         unit2->supply[m] -= um_consumption_on_creation(u3, m);
  1434.         }
  1435.     }
  1436.     use_up_acp(unit, uu_acp_to_create(u2, u3));
  1437.     return A_ANY_DONE;
  1438.     } else {
  1439.     /* We've hit a max number of units, nothing to be done. */
  1440.     return A_ANY_ERROR;
  1441.     }
  1442. }
  1443.  
  1444. int
  1445. check_create_in_action(unit, unit2, u3, dest)
  1446. Unit *unit, *unit2, *dest;
  1447. int u3;
  1448. {
  1449.     int u, u2, m, tp;
  1450.  
  1451.     if (!in_play(unit))
  1452.       return A_ANY_ERROR;
  1453.     if (!in_play(unit2))
  1454.       return A_ANY_ERROR;
  1455.     if (!is_unit_type(u3))
  1456.       return A_ANY_ERROR;
  1457.     if (!in_play(dest))
  1458.       return A_ANY_ERROR;
  1459.     u = unit->type;  u2 = unit2->type;
  1460.     if (uu_acp_to_create(u2, u3) < 1)
  1461.       return A_ANY_CANNOT_DO;
  1462.     if (!can_have_enough_acp(unit, uu_acp_to_create(u2, u3)))
  1463.       return A_ANY_CANNOT_DO;
  1464.     /* Check the tech level of the side. */
  1465.     if (u_tech_to_build(u3) > 0) {
  1466.     if (unit->side == NULL)
  1467.       return A_ANY_ERROR;
  1468.     if (unit->side->tech[u3] < u_tech_to_build(u3))
  1469.       return A_ANY_ERROR;
  1470.     }
  1471.     /* Check the tooling. */
  1472.     tp = (unit2->tooling ? unit2->tooling[u3] : 0);
  1473.     if (tp < uu_tp_to_build(u2, u3))
  1474.       return A_ANY_ERROR;
  1475.     if (distance(unit2->x, unit2->y, dest->x, dest->y) > uu_create_range(u2, u3))
  1476.       return A_ANY_TOO_FAR;
  1477.     if (unit2->transport != NULL
  1478.         && !uu_occ_can_build(unit2->transport->type, u2))
  1479.       return A_ANY_ERROR;
  1480.     if (!type_can_occupy(u3, dest))
  1481.       return A_ANY_ERROR;
  1482.     for_all_material_types(m) {
  1483.         if (unit2->supply[m] < um_to_create(u3, m))
  1484.           return A_ANY_NO_MATERIAL;
  1485.         if (unit2->supply[m] < um_consumption_on_creation(u3, m))
  1486.           return A_ANY_NO_MATERIAL;
  1487.     }
  1488.     if (!has_enough_acp(unit, uu_acp_to_create(u2, u3)))
  1489.       return A_ANY_NO_ACP;
  1490.     return A_ANY_OK;
  1491. }
  1492.  
  1493. static void
  1494. set_created_unit_props(newunit, u2, side)
  1495. Unit *newunit;
  1496. int u2;
  1497. Side *side;
  1498. {
  1499.     int u3 = newunit->type, m, amt;
  1500.  
  1501.     newunit->hp = newunit->hp2 = 1;
  1502.     newunit->cp = uu_creation_cp(u2, u3);
  1503.     if (unit_allowed_on_side(newunit, side)) {
  1504.     set_unit_side(newunit, side);
  1505.     set_unit_origside(newunit, side);
  1506.     }
  1507.     /* Always number the unit when first created. */
  1508.     assign_unit_number(newunit);
  1509.     /* Set all supplies to their just-created levels. */
  1510.     for_all_material_types(m) {
  1511.     amt = newunit->supply[m];
  1512.     amt = max(amt, um_created_supply(u3, m));
  1513.     /* Clip to capacity. */
  1514.     amt = min(amt, um_storage_x(u3, m));
  1515.     newunit->supply[m] = amt;
  1516.     }
  1517. }
  1518.  
  1519. /* Create-at action. */
  1520.  
  1521. int
  1522. prep_create_at_action(unit, unit2, u3, x, y, z)
  1523. Unit *unit, *unit2;
  1524. int u3, x, y, z;
  1525. {
  1526.     if (unit == NULL || unit->act == NULL)
  1527.       return FALSE;
  1528.     if (unit2 == NULL)
  1529.       return FALSE;
  1530.     unit->act->nextaction.type = ACTION_CREATE_AT;
  1531.     unit->act->nextaction.args[0] = u3;
  1532.     unit->act->nextaction.args[1] = x;
  1533.     unit->act->nextaction.args[2] = y;
  1534.     unit->act->nextaction.args[3] = z;
  1535.     unit->act->nextaction.actee = unit2->id;
  1536.     broadcast_next_action(unit);
  1537.     return TRUE;
  1538. }
  1539.  
  1540. int
  1541. do_create_at_action(unit, unit2, u3, x, y, z)
  1542. Unit *unit, *unit2;
  1543. int u3, x, y, z;
  1544. {
  1545.     int u2 = unit2->type, m;
  1546.     Unit *newunit;
  1547.  
  1548.     /* Make the new unit. */
  1549.     newunit = create_unit(u3, FALSE);
  1550.     if (newunit != NULL) {
  1551.     /* Fill in various properties. */
  1552.     set_created_unit_props(newunit, u2, unit->side);
  1553.     /* Put it at a correct location. */
  1554.     if (can_occupy_cell(newunit, x, y)) {
  1555.         enter_cell(newunit, x, y);
  1556.     } else if (can_occupy_cell_without(newunit, x, y, unit2)
  1557.            && can_occupy(unit2, newunit)) {
  1558.         /* Let the builder occupy its incomplete work. */
  1559.         leave_cell(unit2);
  1560.         enter_cell(newunit, x, y);
  1561.         enter_transport(unit2, newunit);
  1562.     } else {
  1563.         /* This should never happen. */
  1564.         run_error("construction/occupation complications");
  1565.     }
  1566.     /* and set its altitude? */
  1567.     /* Unit might be complete right away. */
  1568.     if (completed(newunit)) {
  1569.             garrison_unit(unit2, newunit);
  1570.         make_unit_complete(newunit);
  1571.     } else {
  1572.         record_event(H_UNIT_CREATED, add_side_to_set(unit2->side, NOSIDES),
  1573.              side_number(unit2->side), newunit->id);
  1574.     }
  1575.     if (alive(unit2)) {
  1576.         count_gain(unit2->side, newunit->type, build_gain);
  1577.         /* Consume the creator's supplies as specified. */
  1578.         for_all_material_types(m) {
  1579.         unit2->supply[m] -= um_consumption_on_creation(u3, m);
  1580.         }
  1581.     }
  1582.     use_up_acp(unit, uu_acp_to_create(u2, u3));
  1583.     return A_ANY_DONE;
  1584.     } else {
  1585.     /* We've hit a max number of units, nothing to be done. */
  1586.     return A_ANY_ERROR;
  1587.     }
  1588. }
  1589.  
  1590. int
  1591. check_create_at_action(unit, unit2, u3, x, y, z)
  1592. Unit *unit, *unit2;
  1593. int u3, x, y, z;
  1594. {
  1595.     int u, u2, m, tp;
  1596.  
  1597.     /* (should share code in create_in) */
  1598.     if (!in_play(unit))
  1599.       return A_ANY_ERROR;
  1600.     if (!in_play(unit2))
  1601.       return A_ANY_ERROR;
  1602.     if (!is_unit_type(u3))
  1603.       return A_ANY_ERROR;
  1604.     if (!inside_area(x, y))
  1605.       return A_ANY_ERROR;
  1606.     u = unit->type;  u2 = unit2->type;
  1607.     if (uu_acp_to_create(u2, u3) < 1)
  1608.       return A_ANY_CANNOT_DO;
  1609.     if (!can_have_enough_acp(unit, uu_acp_to_create(u2, u3)))
  1610.       return A_ANY_CANNOT_DO;
  1611.     if (u_tech_to_build(u3) > 0) {
  1612.     if (unit->side == NULL)
  1613.       return A_ANY_ERROR;
  1614.     if (unit->side->tech[u3] < u_tech_to_build(u3))
  1615.       /* (should have an "insufficient tech" error for this case) */
  1616.       return A_ANY_ERROR;
  1617.     }
  1618.     if (distance(unit2->x, unit2->y, x, y) > uu_create_range(u2, u3))
  1619.       return A_ANY_TOO_FAR;
  1620.     /* Check the tooling. */
  1621.     tp = (unit2->tooling ? unit2->tooling[u3] : 0);
  1622.     if (tp < uu_tp_to_build(u2, u3))
  1623.       /* (should have an "insufficient tooling" error for this case) */
  1624.       return A_ANY_ERROR;
  1625.     if (unit2->transport != NULL
  1626.         && !uu_occ_can_build(unit2->transport->type, u2))
  1627.       return A_ANY_ERROR;
  1628.     /* (should check for room and safety of terrain) */
  1629.     if (!(type_can_occupy_cell(u3, x, y)
  1630.           || (can_occupy_type(unit2, u3)
  1631.               && type_can_occupy_cell_without(u3, x, y, unit2))))
  1632.                 return A_ANY_ERROR;
  1633.     /* (should check that unit limit not hit yet) */
  1634.     for_all_material_types(m) {
  1635.         if (unit2->supply[m] < um_to_create(u3, m))
  1636.           return A_ANY_NO_MATERIAL;
  1637.         if (unit2->supply[m] < um_consumption_per_build(u3, m))
  1638.           return A_ANY_NO_MATERIAL;
  1639.     }
  1640.     if (!has_enough_acp(unit, uu_acp_to_create(u2, u3)))
  1641.       return A_ANY_NO_ACP;
  1642.     return A_ANY_OK;
  1643. }
  1644.  
  1645. /* Build action. */
  1646.  
  1647. /* This action makes progress on a construction effort, possibly completing
  1648.    the new unit and making it available. */
  1649.  
  1650. int build_step_consumption PARAMS ((int u2, int u3, int m, int cp));
  1651.  
  1652. int
  1653. prep_build_action(unit, unit2, newunit)
  1654. Unit *unit, *unit2, *newunit;
  1655. {
  1656.     if (unit == NULL || unit->act == NULL)
  1657.       return FALSE;
  1658.     if (unit2 == NULL)
  1659.       return FALSE;
  1660.     unit->act->nextaction.type = ACTION_BUILD;
  1661.     unit->act->nextaction.args[0] = newunit->id;
  1662.     unit->act->nextaction.actee = unit2->id;
  1663.     broadcast_next_action(unit);
  1664.     return TRUE;
  1665. }
  1666.  
  1667. int
  1668. do_build_action(unit, unit2, newunit)
  1669. Unit *unit, *unit2, *newunit;
  1670. {
  1671.     int u, u2, u3, m;
  1672.  
  1673.     u = unit->type;
  1674.     u2 = unit2->type;
  1675.     u3 = newunit->type;
  1676.     for_all_material_types(m) {
  1677.         unit2->supply[m] -= build_step_consumption(u2, u3, m, newunit->cp);
  1678.     }
  1679.     newunit->cp += uu_cp_per_build(u2, u3);
  1680.     if (completed(newunit)) {
  1681.         garrison_unit(unit2, newunit);
  1682.     make_unit_complete(newunit);
  1683.     }
  1684.     update_unit_display(newunit->side, newunit, TRUE);
  1685.     use_up_acp(unit, uu_acp_to_build(u2, u3));
  1686.     return A_ANY_DONE;
  1687. }
  1688.  
  1689. /* Consumption per build is in terms of total material to complete,
  1690.    this routine computes the consumption for a particular build action.
  1691.    This is basically division of the total by the number of completion
  1692.    points, but is careful about not missing any needed consumption
  1693.    if the division rounds down. */
  1694.  
  1695. int
  1696. build_step_consumption(u2, u3, m, cp)
  1697. int u2, u3, m, cp;
  1698. {
  1699.     int consumtot = um_consumption_per_build(u3, m);
  1700.     int cpinc = uu_cp_per_build(u2, u3);
  1701.     int consum, rslt;
  1702.  
  1703.     consum = (cpinc * consumtot * 100) / (u_cp(u3));
  1704.     rslt = consum / 100;
  1705.     if (((cp + cpinc) * 100) / (u_cp(u3)) <= consum % 100)
  1706.       ++rslt;
  1707.     return rslt;
  1708. }
  1709.  
  1710. void
  1711. garrison_unit(unit, unit2)
  1712. Unit *unit, *unit2;
  1713. {
  1714.     int u = unit->type, u2 = unit2->type, x = unit->x, y = unit->y;
  1715.     Unit *transport = NULL, *occ, *nextocc;
  1716.  
  1717.     /* Maybe get rid of the building unit if it is to be the garrison. */
  1718.     if (uu_hp_to_garrison(u, u2) >= unit->hp) {
  1719.     /* But first get the about-to-be-killed garrisoning unit
  1720.        disconnected from everything. */
  1721.     leave_cell(unit);
  1722.     /* Put new unit in place of the garrisoning one, if it was an occupant. */
  1723.     if (unit2->transport == unit) {
  1724.         leave_transport(unit2);
  1725.         if (transport != NULL) { /* some other unit that could be transport? */
  1726.         enter_transport(unit2, transport);
  1727.         } else {
  1728.         enter_cell(unit2, x, y);
  1729.         }
  1730.     }
  1731.  
  1732.     if (unit2->transport != NULL && unit2->transport != unit)
  1733.       transport = unit2->transport;
  1734.     /* for_all_occupants will not work here, 
  1735.        since leave_transport changes occ->nexthere */
  1736.     for (occ = unit->occupant; occ != NULL; occ = nextocc) {
  1737.         nextocc = occ->nexthere;
  1738.         /* Move the other occupants anywhere we can find. */
  1739.         if (can_occupy(occ, unit2)) {
  1740.         /* leave_cell won't work here, since "unit" already left cell */
  1741.         leave_transport(occ);
  1742.         update_unit_display(unit->side, unit, TRUE);
  1743.         enter_transport(occ, unit2);
  1744.         } else if (transport != NULL && can_occupy(occ, transport)) {
  1745.         leave_transport(occ);
  1746.         update_unit_display(unit->side, unit, TRUE);
  1747.         enter_transport(occ, transport);
  1748.         } else if (can_occupy_cell(occ, x, y)) {
  1749.         leave_transport(occ);
  1750.         update_unit_display(unit->side, unit, TRUE);
  1751.         enter_cell(occ, x, y);
  1752.         }
  1753.         /* Otherwise the occupant has to die along with the garrison. */
  1754.         /* (should also do something with sub-occs of doomed occs?) */
  1755.     }
  1756.     /* Now we can get rid of the garrisoning unit without scrambling
  1757.        anything else. */
  1758.     tmphevtdata1 = unit2->id;
  1759.     kill_unit(unit, H_UNIT_GARRISONED);
  1760.     } else {
  1761.     /* Note that if this all happens before damage is reckoned,
  1762.        hp and hp2 might be different. */
  1763.     unit->hp -= uu_hp_to_garrison(u, u2);
  1764.     unit->hp2 -= uu_hp_to_garrison(u, u2);
  1765.     /* (should record loss of hp as garrison event?) */
  1766.     }
  1767. }
  1768.  
  1769. int
  1770. check_build_action(unit, unit2, newunit)
  1771. Unit *unit, *unit2, *newunit;
  1772. {
  1773.     int u, u2, u3, acpcost, m, tp;
  1774.  
  1775.     if (!in_play(unit))
  1776.       return A_ANY_ERROR;
  1777.     if (!in_play(unit2))
  1778.       return A_ANY_ERROR;
  1779.     if (!in_play(newunit))
  1780.       return A_ANY_ERROR;
  1781.     u = unit->type;
  1782.     u2 = unit2->type;
  1783.     u3 = newunit->type;
  1784.     acpcost = uu_acp_to_build(u2, u3);
  1785.     if (acpcost < 1)
  1786.       return A_ANY_CANNOT_DO;
  1787.     if (!can_have_enough_acp(unit, acpcost))
  1788.       return A_ANY_CANNOT_DO;
  1789.     if (uu_cp_per_build(u2, u3) <= 0)
  1790.       return A_ANY_ERROR;
  1791.     /* Can't finish building a unit until we have the technology. */
  1792.     if (u_tech_to_build(u3) > 0) {
  1793.     if (unit->side == NULL)
  1794.       return A_ANY_ERROR;
  1795.     if (unit->side->tech[u3] < u_tech_to_build(u3))
  1796.       return A_ANY_ERROR;
  1797.     }
  1798.     /* Check the tooling. */
  1799.     tp = (unit2->tooling ? unit2->tooling[u3] : 0);
  1800.     if (tp < uu_tp_to_build(u2, u3))
  1801.       return A_ANY_ERROR;
  1802.     /* Check the distance to the unit being worked on. */
  1803.     if (distance(unit->x, unit->y, newunit->x, newunit->y)
  1804.     > uu_build_range(u, u3))
  1805.       return A_ANY_ERROR;
  1806.     /* Note that we should be able to build when inside the incomplete
  1807.        unit we're building. */
  1808.     if (unit2->transport != NULL
  1809.     && completed(unit2->transport)
  1810.         && !uu_occ_can_build(unit2->transport->type, u2))
  1811.       return A_ANY_ERROR;
  1812.     if (!has_enough_acp(unit, acpcost))
  1813.       return A_ANY_NO_ACP;
  1814.     for_all_material_types(m) {
  1815.         if (unit2->supply[m] < um_to_build(u2, m))
  1816.           return A_ANY_NO_MATERIAL;
  1817.         if (unit2->supply[m] < build_step_consumption(u2, u3, m, newunit->cp))
  1818.           return A_ANY_NO_MATERIAL;
  1819.     }
  1820.     return A_ANY_OK;
  1821. }
  1822.  
  1823. /* Do all the little things to make a fully operational unit. */
  1824.  
  1825. void
  1826. make_unit_complete(unit)
  1827. Unit *unit;
  1828. {
  1829.     int u = unit->type, m;
  1830.     SideMask observers;
  1831.     Side *side;
  1832.  
  1833.     /* Make this a "complete" but not a "fullsized" unit. */
  1834.     unit->cp = max(unit->cp, u_cp(u) / u_parts(u));
  1835.     unit->hp = unit->hp2 = u_hp(u) / u_parts(u);
  1836.     /* Christen our new unit. Its serial number (if it is a type that has
  1837.        one) was assigned just after its creation. */
  1838.     make_up_unit_name(unit);
  1839.     /* It also starts viewing its surroundings. */
  1840.     if (unit->transport == NULL
  1841.     || uu_occ_can_see(unit->type, unit->transport->type)) {
  1842.     cover_area(unit->side, unit, -1, -1, unit->x, unit->y);
  1843.     }
  1844.     /* Set all the supplies up to their unit-just-completed levels. */
  1845.     for_all_material_types(m) {
  1846.     unit->supply[m] = max(unit->supply[m], um_completed_supply(u, m));
  1847.     unit->supply[m] = min(unit->supply[m], um_storage_x(u, m));
  1848.     }
  1849.     /* Also see if anybody here is willing to share to make up any
  1850.        deficiencies before the end of the turn. */
  1851.     for_all_material_types(m) {
  1852.     if (unit->transport)
  1853.       try_sharing(unit->transport, unit, m);
  1854.     }
  1855.     init_unit_actorstate(unit, FALSE);
  1856.     init_unit_plan(unit);
  1857.     /* Put this unit into action immediately, at full acp. */
  1858.     if (unit->act) {
  1859.     compute_acp(unit);
  1860.     if (unit->act->initacp > 0) {
  1861.         side = (unit->side ? unit->side : indepside);
  1862.         side->actionvector = add_unit_to_vector(side->actionvector, unit, 0);
  1863.     }
  1864.     }
  1865.     observers = add_side_to_set(unit->side, NOSIDES);
  1866.     /* (should add any other sides that might see this) */
  1867.     record_event(H_UNIT_COMPLETED, observers, side_number(unit->side), unit->id);
  1868.     /* (should add to any per-side tallies) */
  1869.     Dprintf("%s is completed\n", unit_desig(unit));
  1870. }
  1871.  
  1872. /* Repair action. */
  1873.  
  1874. int
  1875. prep_repair_action(unit, unit2, unit3)
  1876. Unit *unit, *unit2, *unit3;
  1877. {
  1878.     if (unit == NULL || unit->act == NULL)
  1879.       return FALSE;
  1880.     if (unit2 == NULL)
  1881.       return FALSE;
  1882.     if (unit3 == NULL)
  1883.       return FALSE;
  1884.     unit->act->nextaction.type = ACTION_REPAIR;
  1885.     unit->act->nextaction.args[0] = unit3->id;
  1886.     unit->act->nextaction.actee = unit2->id;
  1887.     broadcast_next_action(unit);
  1888.     return TRUE;
  1889. }
  1890.  
  1891. int
  1892. do_repair_action(unit, unit2, unit3)
  1893. Unit *unit, *unit2, *unit3;
  1894. {
  1895.     int u, u2, u3, rep, m;
  1896.  
  1897.     u = unit->type;  u2 = unit2->type;  u3 = unit3->type;
  1898.     rep = uu_repair(u2, u3);
  1899.     /* Add to the repairee's hit points. */
  1900.     add_to_unit_hp(unit3, prob_fraction(rep));
  1901.     /* Eat supplies used up by repair. */
  1902.     for_all_material_types(m) {
  1903.     unit2->supply[m] -= um_consumption_per_repair(u3, m);
  1904.     }
  1905.     use_up_acp(unit, uu_acp_to_repair(u2, u3));
  1906.     return A_ANY_DONE;
  1907. }
  1908.  
  1909. int
  1910. check_repair_action(unit, unit2, unit3)
  1911. Unit *unit, *unit2, *unit3;
  1912. {
  1913.     int u, u2, u3, acp, m;
  1914.  
  1915.     if (!in_play(unit))
  1916.       return A_ANY_ERROR;
  1917.     if (!in_play(unit2))
  1918.       return A_ANY_ERROR;
  1919.     if (!in_play(unit3))
  1920.       return A_ANY_ERROR;
  1921.     u = unit->type;  u2 = unit2->type;  u3 = unit3->type;
  1922.     acp = uu_acp_to_repair(u2, u3);
  1923.     if (acp < 1)
  1924.       return A_ANY_CANNOT_DO;
  1925.     if (!can_have_enough_acp(unit, acp))
  1926.       return A_ANY_CANNOT_DO;
  1927.     if (uu_repair(u2, u3) <= 0)
  1928.       return A_ANY_ERROR;
  1929.     if (unit3->hp >= u_hp(u3))
  1930.       return A_ANY_ERROR;
  1931.     if (unit2->hp < uu_hp_to_repair(u2, u3))
  1932.       return A_ANY_ERROR;
  1933.     for_all_material_types(m) {
  1934.     if (unit2->supply[m] < um_to_repair(u2, m))
  1935.       return A_ANY_NO_MATERIAL;
  1936.     if (unit2->supply[m] < um_consumption_per_repair(u3, m))
  1937.       return A_ANY_NO_MATERIAL;
  1938.     }
  1939.     if (!has_enough_acp(unit, acp))
  1940.       return A_ANY_NO_ACP;
  1941.     return A_ANY_OK;
  1942. }
  1943.  
  1944. /* Disband action. */
  1945.  
  1946. /* The disband action destroys a unit in an "orderly" fashion, and can be
  1947.    undertaken voluntarily. */
  1948.  
  1949. int
  1950. prep_disband_action(unit, unit2)
  1951. Unit *unit, *unit2;
  1952. {
  1953.     if (unit == NULL || unit->act == NULL)
  1954.       return FALSE;
  1955.     if (unit2 == NULL)
  1956.       return FALSE;
  1957.     unit->act->nextaction.type = ACTION_DISBAND;
  1958.     unit->act->nextaction.actee = unit2->id;
  1959.     broadcast_next_action(unit);
  1960.     return TRUE;
  1961. }
  1962.  
  1963. int
  1964. do_disband_action(unit, unit2)
  1965. Unit *unit, *unit2;
  1966. {
  1967.     int u2, m, amt, disb;
  1968.  
  1969.     u2 = unit2->type;
  1970.     /* Recover some percentage of the unit's supply. */
  1971.     for_all_material_types(m) {
  1972.         if (um_supply_per_disband(u2, m) > 0 && unit2->supply[m] > 0) {
  1973.             amt = (unit2->supply[m] * um_supply_per_disband(u2, m)) / 100;
  1974.             /* Unit always loses the amount, whether or not distributed. */
  1975.             unit2->supply[m] -= amt;
  1976.             distribute_material(unit2, m, amt);
  1977.         }
  1978.     }
  1979.     /* Remove hit points or kill the unit directly. */
  1980.     disb = u_hp_per_disband(u2);
  1981.     if (disb < unit2->hp) {
  1982.     unit2->hp -= disb;
  1983.     unit2->hp2 = unit2->hp;
  1984.     } else {
  1985.         /* Pass around whatever we can get out of the unit itself. */
  1986.         for_all_material_types(m) {
  1987.             if (um_recycleable(u2, m) > 0) {
  1988.                 distribute_material(unit2, m, um_recycleable(u2, m));
  1989.             }
  1990.         }
  1991.         /* should ensure vanish */
  1992.     kill_unit(unit2, H_UNIT_DISBANDED);
  1993.     }
  1994.     use_up_acp(unit, u_acp_to_disband(u2));
  1995.     return A_ANY_DONE;
  1996. }
  1997.  
  1998. /* Given a unit and a quantity of material, pass it out to nearby units. */
  1999.  
  2000. void
  2001. distribute_material(unit, m, amt)
  2002. Unit *unit;
  2003. int m, amt;
  2004. {
  2005.     /* Distribute to transport first. */
  2006.     if (amt > 0 && unit->transport != NULL) {
  2007.         /* (should clip to capacity etc) */
  2008.         unit->transport->supply[m] += amt;
  2009.         amt = 0;
  2010.     }
  2011.     /* Then to any unit in the cell. */
  2012.     if (amt > 0) {
  2013.     }
  2014.     /* Then to any unit in an adjacent cell. */
  2015.     if (amt > 0) {
  2016.     }
  2017.     /* (should note anything that went to waste?) */
  2018. }
  2019.  
  2020. int
  2021. check_disband_action(unit, unit2)
  2022. Unit *unit, *unit2;
  2023. {
  2024.     int u, u2, acp;
  2025.  
  2026.     if (!in_play(unit))
  2027.       return A_ANY_ERROR;
  2028.     if (!in_play(unit2))
  2029.       return A_ANY_ERROR;
  2030.     u = unit->type;  u2 = unit->type;
  2031.     acp = u_acp_to_disband(u2);
  2032.     if (acp < 1)
  2033.       return A_ANY_CANNOT_DO;
  2034.     if (!can_have_enough_acp(unit, acp))
  2035.       return A_ANY_CANNOT_DO;
  2036.     if (u_hp_per_disband(unit2->type) <= 0)
  2037.       return A_ANY_CANNOT_DO;
  2038.     if (!has_enough_acp(unit, acp))
  2039.       return A_ANY_NO_ACP;
  2040.     return A_ANY_OK;
  2041. }
  2042.  
  2043. /* Transfer-part action. */
  2044.  
  2045. /* Create a new unit that is similar to the original one, and give it
  2046.    some of the parts of the original unit. */
  2047. /* (New unit in same cell if possible or else in random adjacent cell.) */
  2048.  
  2049. int
  2050. prep_transfer_part_action(unit, unit2, parts, unit3)
  2051. Unit *unit, *unit2, *unit3;
  2052. int parts;
  2053. {
  2054.     if (unit == NULL || unit->act == NULL)
  2055.       return FALSE;
  2056.     if (unit2 == NULL)
  2057.       return FALSE;
  2058.     unit->act->nextaction.type = ACTION_TRANSFER_PART;
  2059.     unit->act->nextaction.args[0] = parts;
  2060.     unit->act->nextaction.args[1] = (unit3 ? unit3->id : 0);
  2061.     unit->act->nextaction.actee = unit2->id;
  2062.     broadcast_next_action(unit);
  2063.     return TRUE;
  2064. }
  2065.  
  2066. int
  2067. do_transfer_part_action(unit, unit2, parts, unit3)
  2068. Unit *unit, *unit2, *unit3;
  2069. int parts;
  2070. {
  2071.     int u2 = unit2->type, acp, part_hp;
  2072.  
  2073.     part_hp = u_hp(u2) / u_parts(u2);
  2074.     if (unit3 == NULL) {
  2075.     /* Create a new unit with parts from unit2. */
  2076.     unit3 = create_unit(u2, TRUE);
  2077.     if (unit3 != NULL) {
  2078.         unit3->hp = parts * part_hp;
  2079.         /* (Cap the hp now - occupancy calcs below might use unit parts
  2080.             to determine available capacity) */
  2081.         unit3->hp = min(unit3->hp, u_hp(unit3->type));
  2082.         unit3->hp2 = unit3->hp;
  2083.         if (unit_allowed_on_side(unit3, unit->side)) {
  2084.         set_unit_side(unit3, unit->side);
  2085.         set_unit_origside(unit3, unit->origside);
  2086.         }
  2087.         /* Always number the unit when first created. */
  2088.         assign_unit_number(unit3);
  2089.         /* (should fill in more slots of new unit, such as supply?) */
  2090.         if (can_occupy_cell(unit3, unit2->x, unit2->y)) {
  2091.         enter_cell(unit3, unit2->x, unit2->y);
  2092.         } else {
  2093.             /* (should add code to enter something else here) */
  2094.         /* This should never happen. */
  2095.         run_warning("transfer_part complications, leaving unit offworld");
  2096.         }
  2097.     } else {
  2098.         /* We have a problem. */
  2099.         return A_ANY_ERROR;
  2100.     }
  2101.     } else {
  2102.     /* Increase the unit3's hp by what's in this unit, and cap it. */
  2103.     add_to_unit_hp(unit3, parts * part_hp);
  2104.     }
  2105.     /* Need to tweak parts in unit2 also */
  2106.     if (parts * part_hp >= unit2->hp) {
  2107.     /* (should transfer occs to unit3) */
  2108.     kill_unit(unit2, -1);  /* should add a merge kill-reason */
  2109.     } else {
  2110.     unit2->hp -= parts * part_hp;
  2111.     unit2->hp2 = unit2->hp;
  2112.     }
  2113.     if (alive(unit2))
  2114.       update_unit_display(unit2->side, unit2, TRUE);
  2115.     update_unit_display(unit3->side, unit3, TRUE);
  2116.     acp = u_acp_to_transfer_part(u2);
  2117.     use_up_acp(unit, acp);
  2118.     return A_ANY_DONE;
  2119. }
  2120.  
  2121. int
  2122. check_transfer_part_action(unit, unit2, parts, unit3)
  2123. Unit *unit, *unit2, *unit3;
  2124. int parts;
  2125. {
  2126.     int u2, acp;
  2127.  
  2128.     if (!in_play(unit))
  2129.       return A_ANY_ERROR;
  2130.     if (!in_play(unit2))
  2131.       return A_ANY_ERROR;
  2132.     if (parts <= 0)
  2133.       return A_ANY_ERROR;
  2134.     /* unit3 can be null. */
  2135.     u2 = unit2->type;
  2136.     acp = u_acp_to_transfer_part(u2);
  2137.     if (acp < 1)
  2138.       return A_ANY_CANNOT_DO;
  2139.     if (!can_have_enough_acp(unit, acp))
  2140.       return A_ANY_CANNOT_DO;
  2141.     if (u_parts(u2) <= 1)
  2142.       return A_ANY_ERROR;
  2143.     if (!has_enough_acp(unit, acp))
  2144.       return A_ANY_NO_ACP;
  2145.     return A_ANY_OK;
  2146. }
  2147.  
  2148. /* Change-type action. */
  2149.  
  2150. int
  2151. prep_change_type_action(unit, unit2, u3)
  2152. Unit *unit, *unit2;
  2153. int u3;
  2154. {
  2155.     if (unit == NULL || unit->act == NULL)
  2156.       return FALSE;
  2157.     if (unit2 == NULL)
  2158.       return FALSE;
  2159.     unit->act->nextaction.type = ACTION_CHANGE_TYPE;
  2160.     unit->act->nextaction.args[0] = u3;
  2161.     unit->act->nextaction.actee = unit2->id;
  2162.     broadcast_next_action(unit);
  2163.     return TRUE;
  2164. }
  2165.  
  2166. /* Actually change the type of a unit. */
  2167.  
  2168. int
  2169. do_change_type_action(unit, unit2, u3)
  2170. Unit *unit, *unit2;
  2171. int u3;
  2172. {
  2173.     int u, u2;
  2174.  
  2175.     u = unit->type;
  2176.     u2 = unit2->type;
  2177.     change_unit_type(unit2, u3, H_UNIT_TYPE_CHANGED);
  2178.     update_unit_display(unit2->side, unit2, TRUE);
  2179.     /* (should consume materials) */
  2180.     use_up_acp(unit, uu_acp_to_change_type(u2, u3));
  2181.     return A_ANY_DONE;
  2182. }
  2183.  
  2184. int
  2185. check_change_type_action(unit, unit2, u3)
  2186. Unit *unit, *unit2;
  2187. int u3;
  2188. {
  2189.     int u, u2, acp, m;
  2190.  
  2191.     if (!in_play(unit))
  2192.       return A_ANY_ERROR;
  2193.     if (!in_play(unit2))
  2194.       return A_ANY_ERROR;
  2195.     if (!is_unit_type(u3))
  2196.       return A_ANY_ERROR;
  2197.     u = unit->type;
  2198.     u2 = unit2->type;
  2199.     acp = uu_acp_to_change_type(u2, u3);
  2200.     if (acp < 1)
  2201.       return A_ANY_CANNOT_DO;
  2202.     if (!can_have_enough_acp(unit, acp))
  2203.       return A_ANY_CANNOT_DO;
  2204.     /* should check if still on allowable side */
  2205.     if (!has_enough_acp(unit, acp))
  2206.       return A_ANY_NO_ACP;
  2207.     /* Check that the unit has any required supplies. */
  2208.     for_all_material_types(m) {
  2209.     if (unit2->supply[m] < um_to_change_type(u2, m))
  2210.       return A_ANY_NO_MATERIAL;
  2211.     }
  2212.     return A_ANY_OK;
  2213. }
  2214.  
  2215. /* Change-side action. */
  2216.  
  2217. /* Tell a unit to change to a given side. */
  2218.  
  2219. /* (what about occs, garrisons, plans?) */
  2220.  
  2221. int
  2222. prep_change_side_action(unit, unit2, side)
  2223. Unit *unit, *unit2;
  2224. Side *side;
  2225. {
  2226.     if (unit == NULL || unit->act == NULL)
  2227.       return FALSE;
  2228.     if (unit2 == NULL)
  2229.       return FALSE;
  2230.     unit->act->nextaction.type = ACTION_CHANGE_SIDE;
  2231.     unit->act->nextaction.args[0] = side_number(side);
  2232.     unit->act->nextaction.actee = unit2->id;
  2233.     broadcast_next_action(unit);
  2234.     return TRUE;
  2235. }
  2236.  
  2237. int
  2238. do_change_side_action(unit, unit2, side)
  2239. Unit *unit, *unit2;
  2240. Side *side;
  2241. {
  2242.     int rslt;
  2243.  
  2244.     if (side_controls_unit(unit->side, unit2)) {
  2245.     /* If we own it, we can just change it. */
  2246.     change_unit_side(unit2, side, H_UNIT_ACQUIRED, NULL);
  2247.     rslt = A_ANY_DONE;
  2248.     } else {
  2249.     rslt = A_ANY_ERROR;
  2250.     }
  2251.     use_up_acp(unit, u_acp_to_change_side(unit2->type));
  2252.     return rslt;
  2253. }
  2254.  
  2255. int
  2256. check_change_side_action(unit, unit2, side)
  2257. Unit *unit, *unit2;
  2258. Side *side;
  2259. {
  2260.     int u, u2, acp;
  2261.  
  2262.     if (!in_play(unit))
  2263.       return A_ANY_ERROR;
  2264.     if (!in_play(unit2))
  2265.       return A_ANY_ERROR;
  2266.     if (!side_in_play(side))
  2267.       return A_ANY_ERROR;
  2268.     if (unit2->side == side)
  2269.       return A_ANY_ERROR;
  2270.     if (!unit_allowed_on_side(unit2, side))
  2271.       return A_ANY_ERROR;
  2272.     u = unit->type;
  2273.     u2 = unit2->type;
  2274.     acp = u_acp_to_change_side(u2);
  2275.     if (acp < 1)
  2276.       return A_ANY_CANNOT_DO;
  2277.     if (!can_have_enough_acp(unit, acp))
  2278.       return A_ANY_CANNOT_DO;
  2279.     if (!has_enough_acp(unit, acp))
  2280.       return A_ANY_NO_ACP;
  2281.     return A_ANY_OK;
  2282. }
  2283.  
  2284. /* Alter-terrain action. */
  2285.  
  2286. /* Change the terrain in the cell to something else. */
  2287.  
  2288. /* We don't need to ensure that the unit can exist on the new terrain
  2289.    type, because the designer is presumed to have set things up sensibly,
  2290.    because the unit might be in an appropriate transport, or because
  2291.    there is some actual use in such a bizarre shtick. */
  2292.  
  2293. /* What if engineers dig hole underneath enemy unit?  Should this be
  2294.    possible, or should there be a "can-dig-under-enemy" parm?  */
  2295.  
  2296. int
  2297. prep_alter_cell_action(unit, unit2, x, y, t)
  2298. Unit *unit, *unit2;
  2299. int x, y, t;
  2300. {
  2301.     if (unit == NULL || unit->act == NULL)
  2302.       return FALSE;
  2303.     if (unit2 == NULL)
  2304.       return FALSE;
  2305.     unit->act->nextaction.type = ACTION_ALTER_TERRAIN;
  2306.     unit->act->nextaction.args[0] = x;
  2307.     unit->act->nextaction.args[1] = y;
  2308.     unit->act->nextaction.args[2] = t;
  2309.     unit->act->nextaction.actee = unit2->id;
  2310.     broadcast_next_action(unit);
  2311.     return TRUE;
  2312. }
  2313.  
  2314. int
  2315. do_alter_cell_action(unit, unit2, x, y, t)
  2316. Unit *unit, *unit2;
  2317. int x, y, t;
  2318. {
  2319.     int u, u2, oldt, acpr, acpa;
  2320.     Side *side;
  2321.  
  2322.     u = unit->type;  u2 = unit2->type;
  2323.     oldt = terrain_at(x, y);
  2324.     /* Change the terrain to the new type. */
  2325.     change_terrain_type(x, y, t);
  2326.     /* Note that we still charge acp even if terrain type doesn't change. */
  2327.     acpr = ut_acp_to_remove_terrain(u2, oldt);
  2328.     acpa = ut_acp_to_add_terrain(u2, t);
  2329.     use_up_acp(unit, acpr + acpa);
  2330.     return A_ANY_DONE;
  2331. }
  2332.  
  2333. int
  2334. check_alter_cell_action(unit, unit2, x, y, t)
  2335. Unit *unit, *unit2;
  2336. int x, y, t;
  2337. {
  2338.     int u, u2, oldt, acpr, acpa;
  2339.  
  2340.     if (!in_play(unit))
  2341.       return A_ANY_ERROR;
  2342.     if (!in_play(unit2))
  2343.       return A_ANY_ERROR;
  2344.     if (!in_area(x, y))
  2345.       return A_ANY_ERROR;
  2346.     if (!is_terrain_type(t))
  2347.       return A_ANY_ERROR;
  2348.     if (!t_is_cell(t))
  2349.       return A_ANY_ERROR;
  2350.     u = unit->type;
  2351.     u2 = unit2->type;
  2352.     oldt = terrain_at(x, y);
  2353.     acpr = ut_acp_to_remove_terrain(u2, oldt);
  2354.     acpa = ut_acp_to_add_terrain(u2, t);
  2355.     if (acpr < 1 || acpa < 1)
  2356.       return A_ANY_CANNOT_DO;
  2357.     if (!can_have_enough_acp(unit, acpr + acpa))
  2358.       return A_ANY_CANNOT_DO;
  2359.     if (distance(unit2->x, unit2->y, x, y) > ut_alter_range(u2, t))
  2360.       return A_ANY_ERROR;
  2361.     if (!has_enough_acp(unit, acpr + acpa))
  2362.       return A_ANY_NO_ACP;
  2363.     return A_ANY_OK;
  2364. }
  2365.  
  2366. /* Add-terrain action. */
  2367.  
  2368. /* Add terrain; border, connection, or coating. */
  2369.  
  2370. int
  2371. prep_add_terrain_action(unit, unit2, x, y, dir, t)
  2372. Unit *unit, *unit2;
  2373. int x, y, dir, t;
  2374. {
  2375.     if (unit == NULL || unit->act == NULL)
  2376.       return FALSE;
  2377.     if (unit2 == NULL)
  2378.       return FALSE;
  2379.     unit->act->nextaction.type = ACTION_ADD_TERRAIN;
  2380.     unit->act->nextaction.args[0] = x;
  2381.     unit->act->nextaction.args[1] = y;
  2382.     unit->act->nextaction.args[2] = dir;
  2383.     unit->act->nextaction.args[3] = t;
  2384.     unit->act->nextaction.actee = unit2->id;
  2385.     broadcast_next_action(unit);
  2386.     return TRUE;
  2387. }
  2388.  
  2389. int
  2390. do_add_terrain_action(unit, unit2, x, y, dir, t)
  2391. Unit *unit, *unit2;
  2392. int x, y, dir, t;
  2393. {
  2394.     int u = unit->type, oldval, newval, x1, y1;
  2395.     Side *side;
  2396.  
  2397.     switch (t_subtype(t)) {
  2398.       case cellsubtype:
  2399.           /* Will never happen. */
  2400.           break;
  2401.       case bordersubtype:
  2402.           oldval = border_at(x, y, dir, t);
  2403.           newval = TRUE;
  2404.     set_border_at(x, y, dir, t, newval);
  2405.           break;
  2406.       case connectionsubtype:
  2407.           oldval = connection_at(x, y, dir, t);
  2408.           newval = TRUE;
  2409.     set_connection_at(x, y, dir, t, newval);
  2410.           break;
  2411.       case coatingsubtype:
  2412.         oldval = aux_terrain_at(x, y, t);
  2413.           /* Interpret "dir" as depth of coating to add. */
  2414.         newval = min(oldval + dir, tt_coat_max(terrain_at(x, y), t));
  2415.         set_aux_terrain_at(x, y, t, newval);
  2416.           break;
  2417.     }
  2418.     /* Let everybody see what has happened. */
  2419.     for_all_sides(side) {
  2420.     if (active_display(side)) {
  2421.         if (terrain_visible(side, x, y)) {
  2422.         update_cell_display(side, x, y, TRUE);
  2423.         }
  2424.         if (t_subtype(t) != coatingsubtype) {
  2425.         if (point_in_dir(x, y, dir, &x1, &y1) && terrain_visible(side, x1, y1))
  2426.           update_cell_display(side, x1, y1, TRUE);
  2427.             }
  2428.         }
  2429.     }
  2430.     use_up_acp(unit, (newval != oldval ? ut_acp_to_add_terrain(u, t) : 1));
  2431.     return A_ANY_DONE;
  2432. }
  2433.  
  2434. int
  2435. check_add_terrain_action(unit, unit2, x, y, dir, t)
  2436. Unit *unit, *unit2;
  2437. int x, y, dir, t;
  2438. {
  2439.     int u, u2, acp;
  2440.  
  2441.     if (!in_play(unit))
  2442.       return A_ANY_ERROR;
  2443.     if (!in_play(unit2))
  2444.       return A_ANY_ERROR;
  2445.     if (!inside_area(x, y))
  2446.       return A_ANY_ERROR;
  2447.     if (!between(0, dir, NUMDIRS - 1))
  2448.       return A_ANY_ERROR;
  2449.     if (!is_terrain_type(t))
  2450.       return A_ANY_ERROR;
  2451.     if (t_is_cell(t))
  2452.       return A_ANY_ERROR;
  2453.     u = unit->type;
  2454.     u2 = unit2->type;
  2455.     acp = ut_acp_to_add_terrain(u2, t);
  2456.     if (acp < 1)
  2457.       return A_ANY_CANNOT_DO;
  2458.      if (!can_have_enough_acp(unit, acp))
  2459.        return A_ANY_CANNOT_DO;
  2460.    if (distance(unit->x, unit->y, x, y) > ut_alter_range(u2, t))
  2461.       return A_ANY_ERROR;
  2462.     if (!has_enough_acp(unit, acp))
  2463.       return A_ANY_NO_ACP;
  2464.     return A_ANY_OK;
  2465. }
  2466.  
  2467. /* Remove-terrain action. */
  2468.  
  2469. /* Remove a border, connection, or coating. */
  2470.  
  2471. int
  2472. prep_remove_terrain_action(unit, unit2, x, y, dir, t)
  2473. Unit *unit, *unit2;
  2474. int x, y, dir, t;
  2475. {
  2476.     if (unit == NULL || unit->act == NULL)
  2477.       return FALSE;
  2478.     if (unit2 == NULL)
  2479.       return FALSE;
  2480.     unit->act->nextaction.type = ACTION_REMOVE_TERRAIN;
  2481.     unit->act->nextaction.args[0] = x;
  2482.     unit->act->nextaction.args[1] = y;
  2483.     unit->act->nextaction.args[2] = dir;
  2484.     unit->act->nextaction.args[3] = t;
  2485.     unit->act->nextaction.actee = unit2->id;
  2486.     broadcast_next_action(unit);
  2487.     return TRUE;
  2488. }
  2489.  
  2490. int
  2491. do_remove_terrain_action(unit, unit2, x, y, dir, t)
  2492. Unit *unit, *unit2;
  2493. int x, y, dir, t;
  2494. {
  2495.     int u = unit->type, oldval, newval, x1, y1;
  2496.     Side *side;
  2497.  
  2498.     switch (t_subtype(t)) {
  2499.       case cellsubtype:
  2500.           /* Will never happen. */
  2501.           break;
  2502.       case bordersubtype:
  2503.     oldval = border_at(x, y, dir, t);
  2504.     newval = FALSE;
  2505.     set_border_at(x, y, dir, t, newval);
  2506.           break;
  2507.       case connectionsubtype:
  2508.     oldval = connection_at(x, y, dir, t);
  2509.     newval = FALSE;
  2510.     set_connection_at(x, y, dir, t, newval);
  2511.           break;
  2512.       case coatingsubtype:
  2513.         oldval = aux_terrain_at(x, y, t);
  2514.            /* Interpret "dir" as depth of coating to remove. */
  2515.        newval = max(oldval - dir, 0);
  2516.        /* If newval drops below the min coating depth, coating will vanish. */
  2517.         if (newval < tt_coat_min(terrain_at(x, y), t))
  2518.           newval = 0;
  2519.         set_aux_terrain_at(x, y, t, newval);
  2520.           break;
  2521.     }
  2522.     /* Let everybody see what has happened. */
  2523.     for_all_sides(side) {
  2524.     if (active_display(side)) {
  2525.         if (terrain_visible(side, x, y)) {
  2526.         update_cell_display(side, x, y, TRUE);
  2527.         }
  2528.         if (t_subtype(t) != coatingsubtype) {
  2529.         if (point_in_dir(x, y, dir, &x1, &y1) && terrain_visible(side, x1, y1))
  2530.           update_cell_display(side, x1, y1, TRUE);
  2531.             }
  2532.         }
  2533.     }
  2534.     use_up_acp(unit, (newval != oldval ? ut_acp_to_remove_terrain(u, t) : 1));
  2535.     return A_ANY_DONE;
  2536. }
  2537.  
  2538. int
  2539. check_remove_terrain_action(unit, unit2, x, y, dir, t)
  2540. Unit *unit, *unit2;
  2541. int x, y, dir, t;
  2542. {
  2543.     int u, u2, acp;
  2544.  
  2545.     if (!in_play(unit))
  2546.       return A_ANY_ERROR;
  2547.     if (!in_play(unit2))
  2548.       return A_ANY_ERROR;
  2549.     if (!inside_area(x, y))
  2550.       return A_ANY_ERROR;
  2551.     if (!between(0, dir, NUMDIRS - 1))
  2552.       return A_ANY_ERROR;
  2553.     if (!is_terrain_type(t))
  2554.       return A_ANY_ERROR;
  2555.     if (t_is_cell(t))
  2556.       return A_ANY_ERROR;
  2557.     u = unit->type;
  2558.     u2 = unit2->type;
  2559.     acp = ut_acp_to_remove_terrain(u2, t);
  2560.     if (acp < 1)
  2561.       return A_ANY_CANNOT_DO;
  2562.     if (!can_have_enough_acp(unit, acp))
  2563.       return A_ANY_CANNOT_DO;
  2564.     if (distance(unit->x, unit->y, x, y) > ut_alter_range(u2, t))
  2565.       return A_ANY_ERROR;
  2566.     if (!has_enough_acp(unit, acp))
  2567.       return A_ANY_NO_ACP;
  2568.     return A_ANY_OK;
  2569. }
  2570.  
  2571. /* Execute a given action on a given unit. */
  2572.  
  2573. /* (assumes unit can act in the first place - valid?) */
  2574.  
  2575. int
  2576. execute_action(unit, action)
  2577. Unit *unit;
  2578. Action *action;
  2579. {
  2580.     char *argtypestr;
  2581.     int u = unit->type, rslt = A_ANY_ERROR, n, i;
  2582.     long args[4];
  2583.     Unit *unit2, *argunit;
  2584.     Side *argside, *side2;
  2585. #ifdef THINK_C
  2586.     /* Think C can be excessively picky sometimes. */
  2587.     int (*checkfn) PARAMS ((Unit *unit, Unit *unit2, ...));
  2588.     int (*dofn) PARAMS ((Unit *unit, Unit *unit2, ...));
  2589. #else
  2590.     int (*checkfn) ();
  2591.     int (*dofn) ();
  2592. #endif
  2593.     extern int numsoundplays;
  2594.  
  2595.     Dprintf("%s doing %s with %d acp left\n",
  2596.         unit_desig(unit), action_desig(action), unit->act->acp);
  2597.  
  2598.     if (!alive(unit) || !unit->act || unit->act->acp < u_acp_min(u))
  2599.       return A_ANY_ERROR;
  2600.  
  2601.     argtypestr = actiondefns[(int) action->type].argtypes;
  2602.     n = strlen(argtypestr);
  2603.     for (i = 0; i < n; ++i) {
  2604.     switch (argtypestr[i]) {
  2605.       case 'n':
  2606.       case 'u':
  2607.       case 'm':
  2608.       case 't':
  2609.       case 'x':
  2610.       case 'y':
  2611.       case 'z':
  2612.       case 'd':
  2613.         args[i] = action->args[i];
  2614.         break;
  2615.       case 'U':
  2616.         argunit = find_unit(action->args[i]);
  2617.         if (argunit == NULL) {
  2618.         /* an error, should do run_warning */
  2619.         }
  2620.         args[i] = (long) argunit;
  2621.         break;
  2622.       case 'S':
  2623.         argside = side_n(action->args[i]);
  2624.         args[i] = (long) argside;
  2625.         break;
  2626.       default:
  2627.         /* should warn */
  2628.         break;
  2629.     }
  2630.     }
  2631.     checkfn = actiondefns[(int) action->type].checkfn;
  2632.     dofn = actiondefns[(int) action->type].dofn;
  2633.     if (action->actee == 0) {
  2634.     unit2 = unit;
  2635.     } else {
  2636.     unit2 = find_unit(action->actee);
  2637.     }
  2638.     if (unit2 == NULL) {
  2639.     return A_ANY_ERROR;
  2640.     }
  2641.     switch (n) {
  2642.       case 0:
  2643.     rslt = (*checkfn)(unit, unit2);
  2644.     break;
  2645.       case 1:
  2646.     rslt = (*checkfn)(unit, unit2, args[0]);
  2647.     break;
  2648.       case 2:
  2649.     rslt = (*checkfn)(unit, unit2, args[0], args[1]);
  2650.     break;
  2651.       case 3:
  2652.     rslt = (*checkfn)(unit, unit2, args[0], args[1], args[2]);
  2653.     break;
  2654.       case 4:
  2655.     rslt = (*checkfn)(unit, unit2, args[0], args[1], args[2], args[3]);
  2656.     break;
  2657.       default:
  2658.     case_panic("action arg count", n);
  2659.     }
  2660.     numsoundplays = 0; /* kind of a hack */
  2661.     if (valid(rslt)) {
  2662.     if (g_action_messages() != lispnil)
  2663.       play_action_messages(unit, action);
  2664.     switch (n) {
  2665.       case 0:
  2666.         rslt = (*dofn)(unit, unit2);
  2667.         break;
  2668.       case 1:
  2669.         rslt = (*dofn)(unit, unit2, args[0]);
  2670.         break;
  2671.       case 2:
  2672.         rslt = (*dofn)(unit, unit2, args[0], args[1]);
  2673.         break;
  2674.       case 3:
  2675.         rslt = (*dofn)(unit, unit2, args[0], args[1], args[2]);
  2676.         break;
  2677.       case 4:
  2678.         rslt = (*dofn)(unit, unit2, args[0], args[1], args[2], args[3]);
  2679.         break;
  2680.       default:
  2681.         case_panic("action arg count", n);
  2682.     }
  2683.     Dprintf("%s action %s result is %s, %d acp left\n",
  2684.         unit_desig(unit), action_desig(action), hevtdefns[rslt].name,
  2685.         (unit->act ? unit->act->acp : -9999));
  2686.     if (unit->plan) {
  2687.         unit->plan->lastaction = *action;
  2688.         unit->plan->lastresult = rslt;
  2689.     }
  2690.     if (unit->side && side_has_ai(unit->side)) {
  2691.         ai_react_to_action_result(unit->side, unit, rslt);
  2692.     }
  2693.     if (unit->side && side_has_display(unit->side)) {
  2694.         update_action_result_display(unit->side, unit, rslt, TRUE);
  2695.     }
  2696.     /* Show other sides that some action has occurred. */
  2697.     for_all_sides(side2) {
  2698.         if (side_has_display(side2)) {
  2699.         update_side_display(side2, unit->side, TRUE);
  2700.         }
  2701.     }
  2702.     /* If of a type that might be spotted if it does anything, check
  2703.        each side to see if they notice.  Note that the type is from
  2704.        *before* the action, not after (some actions may cause type changes). */
  2705.     if (u_spot_action(u)
  2706.         && !all_see_all
  2707.         && !u_see_always(u)
  2708.         && in_area(unit->x, unit->y)) {
  2709.         for_all_sides(side2) {
  2710.         if (cover(side2, unit->x, unit->y) > 0) {
  2711.             /* (should call some sort of "glimpsing" routine) */
  2712.         }
  2713.         }
  2714.     }
  2715.     /* Check any scorekeepers that run after each action. */
  2716.     if (any_post_action_scores) {
  2717.         check_post_action_scores(unit, action, rslt);
  2718.     }
  2719.     } else {
  2720.     if (unit->plan) {
  2721.         unit->plan->lastaction = *action;
  2722.         unit->plan->lastresult = rslt;
  2723.     }
  2724.     if (unit->side && side_has_ai(unit->side)) {
  2725.         ai_react_to_action_result(unit->side, unit, rslt);
  2726.     }
  2727.     Dprintf("%s action %s can't be done, result is %s\n",
  2728.         unit_desig(unit), action_desig(action), hevtdefns[rslt].name);
  2729.     }
  2730.     /* Return success/failure so caller can use. */
  2731.     return rslt;
  2732. }
  2733.  
  2734. static void
  2735. play_action_messages(unit, action)
  2736. Unit *unit;
  2737. Action *action;
  2738. {
  2739.     int found = FALSE;
  2740.     char *soundname;
  2741.     Obj *rest, *head, *parms, *msgdesc;
  2742.  
  2743.     for_all_list(g_action_messages(), rest) {
  2744.     head = car(rest);
  2745.     if (consp(head)
  2746.         && symbolp(car(head))
  2747.         && strcmp(c_string(car(head)),
  2748.               actiondefns[(int) action->type].name) == 0) {
  2749.         found = TRUE;
  2750.         break;
  2751.     }
  2752.     if (consp(head)
  2753.         && consp(car(head))
  2754.         && symbolp(car(car(head)))
  2755.         && strcmp(c_string(car(car(head))),
  2756.               actiondefns[(int) action->type].name) == 0) {
  2757.         parms = cdr(car(head));
  2758.         if (parms == lispnil) {
  2759.         found = TRUE;
  2760.         break;
  2761.         }
  2762.         if (((symbolp(car(parms))
  2763.            && strcmp(c_string(car(parms)),
  2764.                  u_type_name(unit->type)) == 0)
  2765.           || match_keyword(car(parms), K_USTAR)
  2766.           || (symbolp(car(parms))
  2767.               && boundp(car(parms))
  2768.               && ((symbolp(symbol_value(car(parms)))
  2769.                   && strcmp(c_string(symbol_value(car(parms))),
  2770.                     u_type_name(unit->type)) == 0)
  2771.                   || (numberp(symbol_value(car(parms)))
  2772.                       && c_number(symbol_value(car(parms)))
  2773.                   == unit->type)))
  2774.           )) {
  2775.         found = TRUE;
  2776.         break;
  2777.         }
  2778.         /* (should be able to match on particular action parms also) */
  2779.     }
  2780.     }
  2781.     /* If we have a match, do something with it. */
  2782.     if (found) {
  2783.     msgdesc = cadr(head);
  2784.     if (stringp(msgdesc)) {
  2785.         notify(unit->side, "%s", c_string(msgdesc));
  2786.     } else if (consp(msgdesc)
  2787.            && symbolp(car(msgdesc))
  2788.            && strcmp(c_string(car(msgdesc)), "sound") == 0
  2789.            && stringp(cadr(msgdesc))) {
  2790.         soundname = c_string(cadr(msgdesc));
  2791.         /* (should not be passing ptrs to schedule_movie) */
  2792.         schedule_movie(unit->side, movie_extra_0, soundname);
  2793.         play_movies(add_side_to_set(unit->side, NOSIDES));
  2794.     } else {
  2795.     }
  2796.     }
  2797. }
  2798.  
  2799. /* Basic check that unit has sufficient acp to do an action. */
  2800.  
  2801. int
  2802. can_have_enough_acp(unit, acp)
  2803. Unit *unit;
  2804. int acp;
  2805. {
  2806.     int u = unit->type, maxacp, minacp;
  2807.  
  2808.     maxacp = u_acp(u);
  2809.     if (u_acp_turn_max(u) >= 0)
  2810.       maxacp = min(maxacp, u_acp_turn_max(u));
  2811.     maxacp = (u_acp_max(u) < 0 ? maxacp : u_acp_max(u));
  2812.     minacp = u_acp_min(u);
  2813.     return (maxacp - acp >= minacp);
  2814. }
  2815.  
  2816. int
  2817. has_enough_acp(unit, acp)
  2818. Unit *unit;
  2819. int acp;
  2820. {
  2821.     if (unit->act == NULL)
  2822.       return FALSE;
  2823.     return ((unit->act->acp - acp) >= u_acp_min(unit->type));
  2824. }
  2825.  
  2826. /* This is true iff the unit has enough of each sort of supply to act. */
  2827.  
  2828. int
  2829. has_supply_to_act(unit)
  2830. Unit *unit;
  2831. {
  2832.     int m;
  2833.  
  2834.     for_all_material_types(m) {
  2835.     if (unit->supply[m] < um_to_act(unit->type, m))
  2836.       return FALSE;
  2837.     }
  2838.     return TRUE;
  2839. }
  2840.  
  2841. /* Make the consumed acp disappear, but not go below the minimum possible. */
  2842.  
  2843. void
  2844. use_up_acp(unit, acp)
  2845. Unit *unit;
  2846. int acp;
  2847. {
  2848.     int oldacp, newacp, acpmin;
  2849.  
  2850.     /* This can sometimes be called on dead or non-acting units,
  2851.        so check first. */
  2852.     if (alive(unit) && unit->act && acp > 0) {
  2853.         oldacp = unit->act->acp;
  2854.     newacp = oldacp - acp;
  2855.     acpmin = u_acp_min(unit->type);
  2856.     unit->act->acp = max(newacp, acpmin);
  2857.     /* Maybe modify the unit's display. */
  2858.     if (oldacp != unit->act->acp) {
  2859.         update_unit_display(unit->side, unit, TRUE);
  2860.     }
  2861.     }
  2862. }
  2863.  
  2864. /* Functions returning general abilities of a unit. */
  2865.  
  2866. int
  2867. can_research(unit)
  2868. Unit *unit;
  2869. {
  2870.     return type_can_research(unit->type);
  2871. }
  2872.  
  2873. int
  2874. type_can_research(u)
  2875. int u;
  2876. {
  2877.     int u2;
  2878.     
  2879.     for_all_unit_types(u2) {
  2880.     if (uu_acp_to_research(u, u2) > 0)
  2881.       return TRUE;
  2882.     }
  2883.     return FALSE;
  2884. }
  2885.  
  2886. int
  2887. can_toolup(unit)
  2888. Unit *unit;
  2889. {
  2890.     return type_can_toolup(unit->type);
  2891. }
  2892.  
  2893. int
  2894. type_can_toolup(u)
  2895. int u;
  2896. {
  2897.     int u2;
  2898.     
  2899.     for_all_unit_types(u2) {
  2900.     if (uu_acp_to_toolup(u, u2) > 0)
  2901.       return TRUE;
  2902.     }
  2903.     return FALSE;
  2904. }
  2905.  
  2906. int
  2907. can_create(unit)
  2908. Unit *unit;
  2909. {
  2910.     return type_can_create(unit->type);
  2911. }
  2912.  
  2913. int
  2914. type_can_create(u)
  2915. int u;
  2916. {
  2917.     int u2;
  2918.     
  2919.     for_all_unit_types(u2) {
  2920.     if (uu_acp_to_create(u, u2) > 0
  2921.         && uu_tp_max(u, u2) >= uu_tp_to_build(u, u2))
  2922.       return TRUE;
  2923.     }
  2924.     return FALSE;
  2925. }
  2926.  
  2927. int
  2928. can_complete(unit)
  2929. Unit *unit;
  2930. {
  2931.     return type_can_complete(unit->type);
  2932. }
  2933.  
  2934. int
  2935. type_can_complete(u)
  2936. int u;
  2937. {
  2938.     int u2;
  2939.     
  2940.     for_all_unit_types(u2) {
  2941.     if (uu_acp_to_build(u, u2) > 0
  2942.         && uu_tp_max(u, u2) >= uu_tp_to_build(u, u2))
  2943.       return TRUE;
  2944.     }
  2945.     return FALSE;
  2946. }
  2947.  
  2948. /* This tests whether the given unit is capable of doing repair. */
  2949.  
  2950. int
  2951. can_repair(unit)
  2952. Unit *unit;
  2953. {
  2954.     return type_can_repair(unit->type);
  2955. }
  2956.  
  2957. int
  2958. type_can_repair(u)
  2959. int u;
  2960. {
  2961.     int u2;
  2962.     
  2963.     for_all_unit_types(u2) {
  2964.     if (uu_acp_to_repair(u, u2) > 0)
  2965.       return TRUE;
  2966.     }
  2967.     return FALSE;
  2968. }
  2969.  
  2970. /* This tests whether the given unit is capable of doing repair. */
  2971.  
  2972. int
  2973. can_change_type(unit)
  2974. Unit *unit;
  2975. {
  2976.     return type_can_change_type(unit->type);
  2977. }
  2978.  
  2979. int
  2980. type_can_change_type(u)
  2981. int u;
  2982. {
  2983.     int u2;
  2984.     
  2985.     for_all_unit_types(u2) {
  2986.     if (uu_acp_to_change_type(u, u2) > 0)
  2987.       return TRUE;
  2988.     }
  2989.     return FALSE;
  2990. }
  2991.  
  2992. int
  2993. can_disband(unit)
  2994. Unit *unit;
  2995. {
  2996.     return (type_can_disband(unit->type) || !completed(unit));
  2997. }
  2998.  
  2999. int
  3000. type_can_disband(u)
  3001. int u;
  3002. {
  3003.     return (u_acp_to_disband(u) > 0);
  3004. }
  3005.  
  3006. int
  3007. side_can_disband(side, unit)
  3008. Side *side;
  3009. Unit *unit;
  3010. {
  3011. #ifdef DESIGNERS
  3012.     if (side->designer)
  3013.       return TRUE;
  3014. #endif /* DESIGNERS */
  3015.     return (side_controls_unit(side, unit)
  3016.         && can_disband(unit));
  3017. }
  3018.  
  3019. /* This tests whether the given unit is capable of adding terrain. */
  3020.  
  3021. int
  3022. can_add_terrain(unit)
  3023. Unit *unit;
  3024. {
  3025.     return type_can_add_terrain(unit->type);
  3026. }
  3027.  
  3028. int
  3029. type_can_add_terrain(u)
  3030. int u;
  3031. {
  3032.     int t;
  3033.     
  3034.     for_all_terrain_types(t) {
  3035.     if (ut_acp_to_add_terrain(u, t) > 0)
  3036.       return TRUE;
  3037.     }
  3038.     return FALSE;
  3039. }
  3040.  
  3041. /* This tests whether the given unit is capable of removing terrain. */
  3042.  
  3043. int
  3044. can_remove_terrain(unit)
  3045. Unit *unit;
  3046. {
  3047.     return type_can_remove_terrain(unit->type);
  3048. }
  3049.  
  3050. int
  3051. type_can_remove_terrain(u)
  3052. int u;
  3053. {
  3054.     int t;
  3055.     
  3056.     for_all_terrain_types(t) {
  3057.     if (ut_acp_to_remove_terrain(u, t) > 0)
  3058.       return TRUE;
  3059.     }
  3060.     return FALSE;
  3061. }
  3062.  
  3063. /* The following is generic code. */
  3064.  
  3065. int
  3066. any_construction_possible()
  3067. {
  3068.     int u, u2;
  3069.     static int any_construction = -1;
  3070.  
  3071.     if (any_construction < 0) {
  3072.     any_construction = FALSE;
  3073.     for_all_unit_types(u) {
  3074.         for_all_unit_types(u2) {
  3075.         if (uu_acp_to_create(u, u2) > 0) {
  3076.             any_construction = TRUE;
  3077.             return any_construction;
  3078.         }
  3079.         }
  3080.     }
  3081.     }
  3082.     return any_construction;
  3083. }
  3084.  
  3085. int
  3086. construction_possible(u2)
  3087. int u2;
  3088. {
  3089.     int u;
  3090.  
  3091.     for_all_unit_types(u) {
  3092.     if (uu_acp_to_create(u, u2) > 0
  3093.         && uu_tp_max(u, u2) >= uu_tp_to_build(u, u2))
  3094.       return TRUE;
  3095.     }
  3096. }
  3097.  
  3098. /* Compose a legible description of a given action. */
  3099.  
  3100. char *
  3101. action_desig(act)
  3102. Action *act;
  3103. {
  3104.     int i, slen;
  3105.     char ch, *str;
  3106.  
  3107.     if (act == NULL)
  3108.       return "?null action?";
  3109.     if (act->type == ACTION_NONE)
  3110.       return "[]";
  3111.     if (actiondesigbuf == NULL)
  3112.       actiondesigbuf = xmalloc(BUFSIZE);
  3113.     str = actiondesigbuf;
  3114.     sprintf(str, "[%s", actiondefns[act->type].name);
  3115.     slen = strlen(actiondefns[act->type].argtypes);
  3116.     for (i = 0; i < slen; ++i) {
  3117.     ch = (actiondefns[act->type].argtypes)[i];
  3118.     switch (ch) {
  3119.       case 'U':
  3120.         tprintf(str, " \"%s\"",
  3121.             unit_desig(find_unit(act->args[i])));
  3122.         break;
  3123.       default:
  3124.         tprintf(str, " %d", act->args[i]);
  3125.     }
  3126.     }
  3127.     if (act->actee != 0) {
  3128.     tprintf(str, " (#%d)", act->actee);
  3129.     }
  3130.     strcat(str, "]");
  3131.     return actiondesigbuf;
  3132. }
  3133.