]> granicus.if.org Git - xconq/blobdiff - kernel/actions.c
commits for 7.5.0 pre-release tarball
[xconq] / kernel / actions.c
index 536de8ab2c8e41498ca52fc146022c24d1597ba4..7646bfb0beb8570bf8ea00904f7fb5f1c85a6201 100644 (file)
 /* Implementations of Xconq actions.
    Copyright (C) 1987-1989, 1991-2000 Stanley T. Shebs.
+   Copyright (C) 2005 Eric A. McDonald.
 
 Xconq is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.  See the file COPYING.  */
 
-/* The general theory of actions is that interface or AI code calls, for
-   an action foo, the routine prep_foo_action, which just records the action
-   for later execution.  The action loop in run_game eventually calls
-   do_foo_action, which first calls check_foo_action to confirm that the
-   action will succeed.  If check_foo_action does not find any errors, then
-   the action cannot fail.  The main body of do_foo_action then implements
-   the effects of the action.  Interfaces may call check_foo_action freely,
-   but should never call do_foo_action directly. */
+/*! \file kernel/actions.c
+ * \brief Implementations of Xconq actions.
+ *
+ * The general theory of actions is that interface or AI code calls, for
+ * an action foo, the routine prep_foo_action, which just records the action
+ * for later execution.  The action loop in run_game eventually calls
+ * do_foo_action, which first calls check_foo_action to confirm that the
+ * action will succeed.  If check_foo_action does not find any errors, then
+ * the action cannot fail.  The main body of do_foo_action then implements
+ * the effects of the action.  Interfaces may call check_foo_action freely,
+ * but should never call do_foo_action directly.
+ * 
+ * action.def is used to declare the actions as extern int, as well
+ * as defining the action default function array, actiondefns.  A macro,
+ * ACTION_DEF is redefined to use different portions of it's arguments
+ * to define the different types of information to this module.
+ *
+ * Each action has an acting unit, which is the unit that schedules the action 
+ * and supplies the ACP to perform the action. Each action also has an "actee",
+ * a unit that actually performs the action (extractor, builder, creator, etc).
+ * The two units are currently always identical, but the theoretical possibility 
+ * of splitting the work in this way is supported by two separate unit arguments
+ * in all action functions. It is the status, position, capabilities and available
+ * supplies of the "actee" that determines if, how and to what extent the action 
+ * can be performed, but the action is also limited by the ACPs that are available 
+ * to the acting unit. Note that the "actee" is called so for historical reasons - a
+ * better name would be "actor" since it in most cases is the active unit. One
+ * exception is the materials transfer code, where the "actee" is the donor (not
+ * necessarily active) of the transferred materials. Another example is the
+ * disband action where the "actee" is the unit being disbanded. Other parameters 
+ * may be defined.
+ *
+ * \note We can't declare all the action functions as static 
+ * because some of them are in other files, but don't 
+ * let them be visible to all files. 
+ * 
+ * \note <P>The DEF_ACTION macro and it's like can't be documented directly
+ * with Doxygen, as it doesn't support overlaid macros, or macro substitiution
+ * in comments.  So where a single definition file is used for several purposes,
+ * the documentation has to be manually included each time, which kind of 
+ * defeats the purpose of having the definions in a single file.  One
+ * possibility would be to use a pre-processor like m4 to create a set
+ * of documentation includes, like action_function.doc to be included.
+ * It's probably not worthwile for external function declarations, since
+ * they'll be documented where they are defined, but it might be nice for
+ * things like enumerations or fixed data structures.
+ */
 
 #include "conq.h"
 #include "kernel.h"
 
-static int check_create_common(Unit *unit, Unit *unit2, int u3,
-                              int x, int y);
-static void set_created_unit_props(Unit *unit, int u2, Side *side,
-                                  int u2mor);
+extern int at_turn_start;
+
+static int creator_always_dies_on_creation(int u, int new_u);
+static void set_created_unit_props(Unit *newunit, Unit *creator, Side *side);
+//! Checks that are common to both explicit and auto-repair.
+static int can_any_repair_common(Unit *actor, Unit *repairer, Unit *repairee);
 static int give_away(Unit *unit, int m, int amt);
 static void notify_action(Unit *unit, Action *action);
 static void play_action_movies(Unit *unit, Action *action);
 static void adjust_tech_crossover(Side *side, int u);
 static void adjust_tooling_crossover(Unit *unit, int u2);
 static void distribute_material(Unit *unit, int m, int amt);
-
 static void notify_tech(Side *side, int u, int oldtech, int newtech);
 static void notify_tp(Side *side, Unit *unit, int u2, int oldtp, int newtp);
-
-
-/* We can't declare all the action functions as static because some of them
-   are in other files, but don't let them be visible to all files. */
+static int extract_one_round(Unit *extractor, int x, int y, int m, int amount);
 
 #undef  DEF_ACTION
+
 #define DEF_ACTION(name,code,args,prepfn,netprepfn,DOFN,checkfn,ARGDECL,doc)  \
-  extern int DOFN ARGDECL;
+    extern int DOFN ARGDECL;
 
 #include "action.def"
 
-/* The table of all the types of actions. */
-
-ActionDefn actiondefns[] = {
-
 #undef  DEF_ACTION
 #define DEF_ACTION(NAME,CODE,ARGS,prepfn,netprepfn,dofn,checkfn,argdecl,doc)  \
     { CODE, NAME, ARGS },
 
+/*! \brief Action function table.
+ *
+ * The table of all the action functions declared above.  It uses 
+ * CODE_DEF_ACTION and action.def above to generate an "extern int"
+ * declaration for every action (prep, do, and * check).  Below it
+ * generates a table with 3 entries for each function, a code number
+ * (CODe), the name of the function (NAME), and the extended
+ * declaration list for the function (ARGS).
+ */
+ActionDefn actiondefns[] = {
+
 #include "action.def"
 
-    { -1, NULL, NULL }
+    { (ActionType)-1, NULL, NULL }
 };
 
-/* This is used to indicate that a move is a retreat; for normal movement it will
-   always be false. */
-
+/*! \brief Retreat flag.
+ *
+ * This is used to indicate that a move is a retreat; for normal 
+ * movement it will always be false.
+ */
 int retreating;
 
-/* This is a specific type of unit that the retreater is running away from. */
-
+/*! \brief Type of Unit from which a Unit is retreating.
+ *
+ * This is a specific type of Unit that the retreater is running away from.
+ */
 int retreating_from = NONUTYPE;
 
+/*! \brief Action description buffer.
+ *
+ * This is used to compose a description of what a Unit is doing.
+ */
 char *actiondesigbuf = NULL;
 
-/* Do any action-related initialization. */
+extern Action *latest_action;
+
+/* Cache variables. */
+int *cache__type_max_night_acp_from_any_terrains = NULL;
+int *cache__type_max_acp_from_any_occs = NULL;
+int *cache__type_max_acp = NULL;
+
+int
+could_take_from_treasury(int u, int m)
+{
+    assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
+    assert_error(is_material_type(m),
+                 "Attempted to manipulate an invalid mtype");
+    return (um_takes_from_treasury(u, m) && m_treasury(m) 
+           && (0 < g_treasury_size()));
+}
+
+int
+could_take_from_treasury(int u, Side *side, int m)
+{
+    assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
+    assert_error(side, "Attempted to access a NULL side");
+    assert_error(is_material_type(m),
+                 "Attempted to manipulate an invalid mtype");
+    return ((side == indepside) && !g_indepside_has_treasury() ? FALSE
+           : could_take_from_treasury(u, m));
+}
+
+int
+could_take_directly_from_treasury(int u, int m)
+{
+    assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
+    assert_error(is_material_type(m),
+                 "Attempted to manipulate an invalid mtype");
+    return (!um_storage_x(u, m) && could_take_from_treasury(u, m));
+}
+
+int
+could_take_directly_from_treasury(int u, Side *side, int m)
+{
+    assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
+    assert_error(side, "Attempted to access a NULL side");
+    assert_error(is_material_type(m),
+                 "Attempted to manipulate an invalid mtype");
+    return ((side == indepside) && !g_indepside_has_treasury() ? FALSE
+           : could_take_directly_from_treasury(u, m));
+}
+
+int
+could_give_to_treasury(int u, int m)
+{
+    assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
+    assert_error(is_material_type(m),
+                 "Attempted to manipulate an invalid mtype");
+    return (um_gives_to_treasury(u, m) && m_treasury(m) 
+           && (0 < g_treasury_size()));
+}
+
+int
+could_give_to_treasury(int u, Side *side, int m)
+{
+    assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
+    assert_error(side, "Attempted to access a NULL side");
+    assert_error(is_material_type(m),
+                 "Attempted to manipulate an invalid mtype");
+    return ((side == indepside) && !g_indepside_has_treasury() ? FALSE
+           : could_give_to_treasury(u, m));
+}
+
+int
+could_give_directly_to_treasury(int u, int m)
+{
+    assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
+    assert_error(is_material_type(m),
+                 "Attempted to manipulate an invalid mtype");
+    return (!um_storage_x(u, m) && could_give_to_treasury(u, m));
+}
+
+int
+could_give_directly_to_treasury(int u, Side *side, int m)
+{
+    assert_error(is_unit_type(u), "Attempted to manipulate an invalid utype");
+    assert_error(side, "Attempted to access a NULL side");
+    assert_error(is_material_type(m),
+                 "Attempted to manipulate an invalid mtype");
+    return ((side == indepside) && !g_indepside_has_treasury() ? FALSE
+           : could_give_directly_to_treasury(u, m));
+}
 
 void
-init_actions(void)
+get_materials_availability(
+    Unit *actor, Unit *agent, long *p_mavail, long *p_mavailmax, int flags)
 {
+    int u2 = NONUTYPE;
+    Side *side = NULL, *side2 = NULL, *tside = NULL;
+    int m = NONMTYPE;
+
+    assert_error(in_play(actor),
+                "Materials Check: Attempted to access an out-of-play actor");
+    assert_error(in_play(agent),
+                "Materials Check: Attempted to access an out-of-play agent");
+    assert_error(p_mavail,
+                "Materials Check: Attempted to access a NULL materials array");
+    assert_error(p_mavailmax,
+                "Materials Check: Attempted to access a NULL materials array");
+    // Useful info.
+    u2 = agent->type;
+    side = actor->side;
+    side2 = agent->side;
+    // Process flags.
+    tside = (flags & MReq_AGENT_TREASURY ? side2 : side);
+    // Fill out the materials arrays.
+    for_all_material_types(m) {
+       if (could_take_directly_from_treasury(u2, tside, m)) {
+           p_mavail[m] = tside->treasury[m];
+           p_mavailmax[m] = g_treasury_size();
+       }
+       else if (could_take_from_treasury(u2, tside, m)) {
+           p_mavail[m] = 
+               min(agent->supply[m] + tside->treasury[m], um_storage_x(u2, m));
+           p_mavailmax[m] = um_storage_x(u2, m);
+       }
+       else {
+           p_mavail[m] = agent->supply[m];
+           p_mavailmax[m] = um_storage_x(u2, m);
+       }
+    }
 }
 
-/* Just a placeholder action, so not much to do here. */
+int
+can_meet_materials_requirement(
+    long *p_mreq, long *p_mavail, long *p_mavailmax)
+{
+    int m = NONMTYPE;
+
+    assert_error(p_mreq,
+                "Materials Check: Attempted to access a NULL materials array");
+    assert_error(p_mavail,
+                "Materials Check: Attempted to access a NULL materials array");
+    assert_error(p_mavailmax,
+                "Materials Check: Attempted to access a NULL materials array");
+    // For each material, see if requirement can be met by availabilities.
+    for_all_material_types(m) {
+       // If requirement > what can ever be available...
+       if (p_mreq[m] > p_mavailmax[m])
+           return A_ANY_CANNOT_DO;
+       // If requirement > what is currently available...
+       if (p_mreq[m] > p_mavail[m])
+           return A_ANY_NO_MATERIAL;
+    }
+    return A_ANY_OK;
+}
 
 int
-prep_none_action(Unit *unit, Unit *unit2)
+can_meet_materials_requirement(
+    Unit *actor, Unit *agent, int (*getter)(int u, int m), int u3, int mult)
 {
-    if (unit == NULL || unit->act == NULL || unit2 == NULL)
-      return FALSE;
+    int rslt = A_ANY_OK;
+    int u2 = NONUTYPE;
+    int m = NONMTYPE;
+    Side *side = NULL;
+    long amtreq = 0, aamtavail = 0, tamtavail = 0, astorcap = 0;
+
+    assert_error(in_play(actor), "Attempted to access an out-of-play unit");
+    assert_error(in_play(agent), "Attempted to access an out-of-play unit");
+    assert_error(getter, "Attempted to use a NULL getter function");
+    u2 = agent->type;
+    side = actor->side;
+    for_all_material_types(m) {
+       /* Get amount requested. */
+       amtreq = getter(is_unit_type(u3) ? u3 : u2, m) * mult;
+       /* If none requested, then no further processing for material. */
+       if (!amtreq)
+         continue;
+       /* Get amount available in agent. */
+       aamtavail = agent->supply[m];
+       /* Check if agent supply can satisfy request. */
+       if (aamtavail >= amtreq)
+         continue;
+       /* Get agent's storage capacity for material. */
+       astorcap = um_storage_x(u2, m);
+       /* Can agent take from treasury? */
+       if (side_has_treasury(side, m) && um_takes_from_treasury(u2, m)) {
+           tamtavail = side->treasury[m];
+           /* Does agent use treasury directly? */
+           if (!um_storage_x(u2, m)) {
+               /* Check if request exceeds treasury size. */
+               if (amtreq > g_treasury_size())
+                 return A_ANY_CANNOT_DO;
+               /* Check if side treasury can satisfy request. */
+               if (amtreq > tamtavail)
+                 return A_ANY_NO_MATERIAL;
+           }
+           /* Else, agent only uses what is needed from treasury. */
+           else {
+               /* Check if request exceeds agent capacity. */
+               if (amtreq > astorcap)
+                 return A_ANY_CANNOT_DO;
+               /* Check if request exceeds agent + treasury amounts. */
+               if (amtreq > (aamtavail + tamtavail))
+                 return A_ANY_NO_MATERIAL;
+           }
+       }
+       /* Else, agent cannot use from treasury, but needs more material. */
+       else {
+           /* Check if request exceeds agent capacity. */
+           if (amtreq > astorcap)
+             return A_ANY_CANNOT_DO;
+           else
+             return A_ANY_NO_MATERIAL;
+       }
+    }
+    return rslt;
+}
+
+int
+consume_materials(
+    Unit *actor, Unit *consumer, int (*getter)(int u, int m), int u3, int mult)
+{
+    int rslt = A_ANY_OK;
+    int u2 = NONUTYPE;
+    int m = NONMTYPE;
+    Side *side = NULL;
+    long amtreq = 0, camtavail = 0, tamtavail = 0, cstorcap = 0, tsize = 0;
+
+    assert_error(in_play(actor), "Attempted to access an out-of-play unit");
+    assert_error(in_play(consumer), 
+                "Attempted to access an out-of-play unit");
+    assert_error(getter, "Attempted to use a NULL getter function");
+    u2 = consumer->type;
+    side = actor->side;
+    /* Check before diving in. */
+    if (!valid(rslt = can_meet_materials_requirement(actor, consumer, getter)))
+      return rslt;
+    for_all_material_types(m) {
+       /* Get amount requested. */
+       amtreq = getter(is_unit_type(u3) ? u3 : u2, m) * mult;
+       /* If none requested, then no further processing for material. */
+       if (!amtreq)
+         continue;
+       /* Get amount available in consumer. */
+       camtavail = consumer->supply[m];
+       /* Get consumer's storage capacity for material. */
+       cstorcap = um_storage_x(u2, m);
+       /* Get treasury amount, if any. */
+       if (side_has_treasury(side, m) && um_takes_from_treasury(u2, m))
+         tamtavail = side->treasury[m];
+       else
+         tamtavail = 0;
+       /* Get treasury's size. */
+       if (side_has_treasury(side, m) && um_gives_to_treasury(u2, m))
+         tsize = g_treasury_size();
+       else
+         tsize = 0;
+       /* If request is positive. */
+       if (0 < amtreq) {
+           /* Consume consumer supply. */
+           if (amtreq <= camtavail) {
+               consumer->supply[m] -= amtreq;
+               continue;
+           }
+           else {
+               amtreq -= camtavail;
+               consumer->supply[m] = 0;
+           }
+           /* Consume treasury supply. */
+           side->treasury[m] -= amtreq;
+       }
+       /* Else request is negative. */
+       else {
+           /* Produce consumer supply, if possible. */
+           if (-amtreq <= (cstorcap - camtavail)) {
+               consumer->supply[m] -= amtreq;
+               continue;
+           }
+           else {
+               amtreq += (cstorcap - camtavail);
+               consumer->supply[m] = cstorcap;
+           }
+           /* Produce treasury supply, if possible. */
+           if (0 < tsize) {
+               side->treasury[m] = min(-amtreq + tamtavail, tsize);
+               amtreq = tsize - (-amtreq + tamtavail);
+               /* (TODO: Try something with any remaining excess?) */
+           }
+       }
+    }
+    return rslt;
+}
+
+//! Does unit has enough of each material needed to act?
+
+int
+has_supply_to_act(Unit *unit)
+{
+    int m = NONMTYPE;
+
+    for_all_material_types(m) {
+       if (unit->supply[m] < um_to_act(unit->type, m))
+         return FALSE;
+    }
+    return TRUE;
+}
+
+/* Unit/utype status/analysis functions. */
+
+/*! \todo Eventually assert activeness instead of just returning an error. */
+
+int
+can_act(Unit *actor, Unit *agent)
+{
+    int rslt = A_ANY_OK;
+
+    // Only active units can act.
+    if (!is_active(actor))
+      return A_ANY_ERROR;
+    if (!is_active(agent))
+      return A_ANY_ERROR;
+    /* Does agent have enough material to act? */
+    if (!has_supply_to_act(agent))
+      return A_ANY_NO_MATERIAL;
+    return rslt;
+}
+
+int
+has_enough_tooling(Unit *constructor, int u2)
+{
+    assert_error(is_active(constructor),
+                "Toolup Check: Attempted to access an inactive constructor");
+    assert_error(is_unit_type(u2),
+                "Toolup Check: Encountered invalid unit type");
+    return ((constructor->tooling ? constructor->tooling[u2] : 0)
+           >= uu_tp_to_build(constructor->type, u2));
+}
+
+int
+could_toolup_for(int u, int u2)
+{
+    assert_error(is_unit_type(u),
+                "Toolup Check: Encountered invalid unit type");
+    assert_error(is_unit_type(u2),
+                "Toolup Check: Encountered invalid unit type");
+    return (uu_toolup_for(u, u2) && (0 < uu_tp_per_toolup(u, u2))
+           && (uu_tp_max(u, u2) >= uu_tp_to_build(u, u2)));
+}
+
+int
+could_toolup_for_any(int u)
+{
+    int u2 = NONUTYPE;
+
+    assert_error(is_unit_type(u),
+                "Toolup Check: Encountered invalid unit type");
+    for_all_unit_types(u2) {
+       if (could_toolup_for(u, u2))
+           return TRUE;
+    }
+    return FALSE;
+}
+
+int
+can_toolup_for(Unit *actor, Unit *constructor, int u3)
+{
+    static long *p_mavail, *p_mavailmax, *p_mreq;
+
+    int rslt = A_ANY_OK;
+    int u = NONUTYPE, u2 = NONUTYPE;
+    Side *side = NULL;
+    int acpcost = 0, tpt = 0;
+    int m = NONMTYPE;
+
+    assert_error(is_active(actor),
+                 "Toolup Check: Attempted to manipulate an inactive actor");
+    assert_error(is_active(constructor),
+"Toolup Check: Attempted to manipulate an inactive constructor");
+    assert_error(is_unit_type(u3),
+                 "Toolup Check: Encountered invalid unit type to toolup for");
+    // Can the creator act?
+    if (!valid(rslt = can_act(actor, constructor)))
+      return rslt;
+    // Some useful info.
+    u = actor->type;
+    u2 = constructor->type;
+    side = actor->side;
+    tpt = uu_tp_per_toolup(u2, u3);
+    // Maybe we are already tooled up or don't have any tooling up to do?
+    if (has_enough_tooling(constructor, u3))
+       return A_ANY_OK;
+    // Could the constructor's utype toolup for the requested utype?
+    if (!could_toolup_for(u2, u3))
+       return A_ANY_CANNOT_DO;
+    // Initialize materials arrays, if necessary.
+    if (!p_mavail)
+        p_mavail = (long *)xmalloc(nummtypes * sizeof(long));
+    if (!p_mavailmax)
+        p_mavailmax = (long *)xmalloc(nummtypes * sizeof(long));
+    if (!p_mreq)
+        p_mreq = (long *)xmalloc(nummtypes * sizeof(long));
+    // Possibly check against ACP.
+    if (!u_acp_independent(u2) 
+       && (0 < (acpcost = uu_acp_to_toolup(u2, u3)))) {
+        // Can the ACP source ever provide enough ACP?
+        if (!can_have_enough_acp(actor, acpcost))
+            return A_ANY_CANNOT_DO;
+        // Does the ACP source have enough ACP to support toolup?
+        if (!has_enough_acp(actor, acpcost))
+            return A_ANY_NO_ACP;
+    }
+    // Check if utype is allowed, and if needed tech & advances exist.
+    if (!side_can_build(side, u3))
+        return A_ANY_CANNOT_DO;
+    // Compare materials availability and requirements.
+    get_materials_availability(actor, constructor, p_mavail, p_mavailmax);
+    for_all_material_types(m) {
+        p_mreq[m] =
+            max(um_to_toolup(u2, m),
+                um_consumption_per_tooledup(u3, m)
+                + um_consumption_per_toolup(u2, m)
+               + tpt * um_consumption_per_tp(u2, m));
+    }
+    if (!valid(
+            rslt =
+                can_meet_materials_requirement(p_mreq, p_mavail, p_mavailmax)))
+        return rslt;
+    return A_ANY_OK;
+}
+
+//! Materials requirement for build or create-as-build action.
+
+static int
+materials_req_for_build(int u2, int u3, int m, int cp)
+{
+    assert_error(is_unit_type(u2),
+                "Construct Check: Encountered invalid constructor unit type");
+    assert_error(is_unit_type(u3),
+                "Construct Check: Encountered invalid constructee unit type");
+    assert_error(is_material_type(m),
+"Construct Check: Encountered invalid construction material type");
+    return max(um_to_build(u2, m),
+              (um_consumption_per_cp(u3, m) * cp)
+               + um_consumption_per_built(u3, m) 
+               + um_consumption_per_build(u2, m));
+}
+
+int
+could_create(int u, int u2)
+{
+    assert_error(is_unit_type(u),
+                "Create Check: Encountered invalid creator unit type");
+    assert_error(is_unit_type(u2),
+                "Create Check: Encountered invalid creation unit type");
+    if (uu_create_as_build(u, u2)) {
+       if (!uu_build(u, u2) || (0 > uu_cp_per_build(u, u2)))
+           return FALSE;
+    }
+    else {
+       if (!uu_create(u, u2) || (0 > uu_creation_cp(u, u2)))
+           return FALSE;
+    }
+    if ((0 < uu_tp_to_build(u, u2)) && !could_toolup_for(u, u2))
+       return FALSE;
+    return TRUE;
+}
+
+int
+could_create_any(int u)
+{
+    int u2 = NONUTYPE;
+
+    assert_error(is_unit_type(u),
+                "Create Check: Encountered invalid creator unit type");
+    for_all_unit_types(u2) {
+       if (could_create(u, u2))
+           return TRUE;
+    }
+    return FALSE;
+}
+
+int
+can_create_common(Unit *actor, Unit *creator, int u3, int x, int y)
+{
+    static long *p_mavail, *p_mavailmax, *p_mreq;
+
+    int rslt = A_ANY_OK;
+    int u = NONUTYPE, u2 = NONUTYPE;
+    Side *side = NULL;
+    int acpcost = 0, cp = -1;
+    int m = NONMTYPE;
+    int cab = FALSE;
+
+    assert_error(is_active(actor),
+                "Create Check: Attempted to manipulate an inactive actor");
+    assert_error(is_active(creator),
+                "Create Check: Attempted to manipulate an inactive creator");
+    assert_error(is_unit_type(u3), 
+                "Create Check: Encountered invalid unit type to create");
+    if (!inside_area(x, y))
+       return A_MOVE_CANNOT_LEAVE_WORLD;
+    // Can the creator act?
+    if (!valid(rslt = can_act(actor, creator)))
+      return rslt;
+    u = actor->type;
+    u2 = creator->type;
+    side = actor->side;
+    cab = uu_create_as_build(u2, u3);
+    // Can the creator's utype create the requested utype? 
+    if (!could_create(u2, u3))
+       return A_ANY_CANNOT_DO;
+    // Initialize materials arrays, if necessary.
+    if (!p_mavail)
+       p_mavail = (long *)xmalloc(nummtypes * sizeof(long));
+    if (!p_mavailmax)
+       p_mavailmax = (long *)xmalloc(nummtypes * sizeof(long));
+    if (!p_mreq)
+       p_mreq = (long *)xmalloc(nummtypes * sizeof(long));
+    // Is the distance within creation range?
+    if (distance(creator->x, creator->y, x, y) 
+       > (cab ? uu_build_range(u2, u3) : uu_create_range(u2, u3))) 
+       return A_ANY_TOO_FAR;
+    // Possibly check against ACP.
+    if (!u_acp_independent(u2) 
+       && (0 < (cab ? uu_acp_to_build(u2, u3) : uu_acp_to_create(u2, u3)))) {
+       // Can the ACP source ever provide enough ACP? 
+       acpcost = (cab ? uu_acp_to_build(u2, u3) : uu_acp_to_create(u2, u3));
+       if (!can_have_enough_acp(actor, acpcost)) 
+           return A_ANY_CANNOT_DO;
+       // Does the ACP source have enough ACP to support creation? 
+       if (!has_enough_acp(actor, acpcost)) 
+           return A_ANY_NO_ACP;
+    }
+    // Check if utype is allowed, and if needed tech & advances exist. 
+    if (!side_can_build(side, u3)) 
+       return A_ANY_CANNOT_DO;
+    // Check if we hit a limit on the number of units. 
+    if (!new_unit_allowed_on_side(u3, side)) 
+       return A_ANY_CANNOT_DO;
+    // Check the tooling.
+    if (!valid(can_toolup_for(actor, creator, u3)))
+       return A_ANY_CANNOT_DO;
+    if (!has_enough_tooling(creator, u3))
+       return A_CONSTRUCT_NO_TOOLING;
+    // If creator is in transport, can creator build from within the transport? 
+    if (creator->transport
+        && !uu_occ_can_build(creator->transport->type, u2))
+       return A_ANY_CANNOT_DO;
+    // Compare materials availability and requirements.
+    cp = min((cab ? uu_cp_per_build(u2, u3) : uu_creation_cp(u2, u3)),
+            u_cp(u3));
+    get_materials_availability(actor, creator, p_mavail, p_mavailmax);
+    for_all_material_types(m) {
+       if (cab)
+           p_mreq[m] = materials_req_for_build(u2, u3, m, cp);
+       else
+           p_mreq[m] =
+               max(um_to_create(u2, m),
+                   um_consumption_per_cp(u3, m) * cp
+                   + um_consumption_on_creation(u3, m)
+                   + um_consumption_per_create(u2, m));
+    }
+    if (!valid(
+           rslt = 
+               can_meet_materials_requirement(p_mreq, p_mavail, p_mavailmax)))
+       return rslt;
+    return A_ANY_OK;
+}
+
+int
+could_build(int u, int u2)
+{
+    assert_error(is_unit_type(u),
+                "Build Check: Encountered invalid builder unit type");
+    assert_error(is_unit_type(u2),
+                "Build Check: Encountered invalid buildee unit type");
+    return (uu_build(u, u2) && (0 < uu_cp_per_build(u, u2))
+           && (!uu_tp_to_build(u, u2) || could_toolup_for(u, u2)));
+}
+
+int
+could_build_any(int u)
+{
+    int u2 = NONUTYPE;
+
+    assert_error(is_unit_type(u),
+                "Build Check: Encountered invalid builder unit type");
+    for_all_unit_types(u2) {
+       if (could_build(u, u2))
+           return TRUE;
+    }
+    return FALSE;
+}
+
+int
+can_build(Unit *actor, Unit *builder, int u3)
+{
+    int rslt = A_ANY_OK;
+    int u = NONUTYPE, u2 = NONUTYPE;
+
+    assert_error(is_active(actor),
+                "Build Check: Attempted to access an inactive actor");
+    assert_error(is_active(builder),
+                "Build Check: Attempted to access an inactive builder");
+    assert_error(is_unit_type(u3),
+                "Build Check: Encountered an invalid buildee unit type");
+    u = actor->type;
+    u2 = builder->type;
+    if (!valid(rslt = can_act(actor, builder)))
+       return rslt;
+    if (!could_build(u2, u3))
+       return A_ANY_CANNOT_DO;
+    if (!valid(can_toolup_for(actor, builder, u3)))
+       return A_ANY_CANNOT_DO;
+    if (!has_enough_tooling(builder, u3))
+       return A_CONSTRUCT_NO_TOOLING;
+    return rslt;
+}
+
+int
+can_build(Unit *actor, Unit *builder, Unit *buildee)
+{
+    static long *p_mavail, *p_mavailmax, *p_mreq;
+
+    int rslt = A_ANY_OK;
+    int acp = 0, cp = -1;
+    int u = NONUTYPE, u2 = NONUTYPE, u3 = NONUTYPE;
+    int m = NONMTYPE;
+    Unit *transport = NULL;
+    
+    assert_error(is_active(actor),
+                "Build Check: Attempted to access an inactive actor");
+    assert_error(is_active(builder),
+                "Build Check: Attempted to access an inactive builder");
+    assert_error(in_play(buildee),
+                "Build Check: Attempted to access an out-of-play buildee");
+    u = actor->type;
+    u2 = builder->type;
+    u3 = buildee->type;
+    transport = builder->transport;
+    if (!valid(rslt = can_build(actor, builder, u3)))
+      return rslt;
+    // Can builder build while inside transport?
+    // Note that an exception is made, if building on the transport itself.
+    if (transport && (transport != buildee)
+        && !uu_occ_can_build(transport->type, u2)) 
+       return A_ANY_CANNOT_DO;
+    // Initialize materials arrays, if necessary.
+    if (!p_mavail)
+        p_mavail = (long *)xmalloc(nummtypes * sizeof(long));
+    if (!p_mavailmax)
+        p_mavailmax = (long *)xmalloc(nummtypes * sizeof(long));
+    if (!p_mreq)
+        p_mreq = (long *)xmalloc(nummtypes * sizeof(long));
+    // Check if necessary ACP is available to build.
+    if (!u_acp_independent(u2) && (0 < uu_acp_to_build(u2, u3))) {
+       acp = uu_acp_to_build(u2, u3);
+       if (!can_have_enough_acp(actor, acp)) 
+           return A_ANY_CANNOT_DO;
+       if (!has_enough_acp(actor, acp))
+           return A_ANY_NO_ACP;
+    }
+    // Compare materials availability and requirements.
+    cp = min(uu_cp_per_build(u2, u3), completenesses[u3] - buildee->cp);
+    get_materials_availability(actor, builder, p_mavail, p_mavailmax);
+    for_all_material_types(m) 
+       p_mreq[m] = materials_req_for_build(u2, u3, m, cp);
+    if (!valid(
+            rslt =
+                can_meet_materials_requirement(p_mreq, p_mavail, p_mavailmax)))
+        return rslt;
+    return rslt;
+}
+
+static int
+can_any_repair_common(Unit *actor, Unit *repairer, Unit *repairee)
+{
+    static long *p_mavail, *p_mavailmax, *p_mreq;
+
+    int rslt = A_ANY_OK;
+    int u = NONUTYPE, u2 = NONUTYPE, u3 = NONUTYPE;
+    int m = NONMTYPE;
+
+    assert_error(is_active(actor),
+                "Repair Check: Attempted to manipulate inactive actor");
+    assert_error(is_active(repairer),
+                "Repair Check: Attempted to manipulate inactive repairer");
+    assert_error(in_play(repairer),
+                "Repair Check: Attempted to manipulate out-of-play repairee");
+    // Check if we are attempting to repair an enemy?
+    if (enemy_side(repairer->side, repairee->side))
+       return A_ANY_CANNOT_DO;
+    // Check if we meet basic action requirements.
+    if (!valid(rslt = can_act(actor, repairer)))
+       return rslt;
+    // Useful info.
+    u = actor->type;
+    u2 = repairer->type;
+    u3 = repairee->type;
+    // Initialize materials arrays, if necessary.
+    if (!p_mavail)
+       p_mavail = (long *)xmalloc(nummtypes * sizeof(long));
+    if (!p_mavailmax)
+       p_mavailmax = (long *)xmalloc(nummtypes * sizeof(long));
+    if (!p_mreq)
+       p_mreq = (long *)xmalloc(nummtypes * sizeof(long));
+    // Compare materials availability and requirements.
+    get_materials_availability(actor, repairer, p_mavail, p_mavailmax);
+    for_all_material_types(m) {
+       p_mreq[m] =
+           max(um_to_repair(u2, m),
+               um_consumption_per_repaired(u3, m)
+               + um_consumption_per_repair(u2, m));
+    }
+    if (!valid(
+            rslt =
+                can_meet_materials_requirement(p_mreq, p_mavail, p_mavailmax)))
+        return rslt;
+    return A_ANY_OK;
+}
+
+int
+could_auto_repair(int u, int u2)
+{
+    assert_error(is_unit_type(u),
+                "Repair Check: Encountered an invalid repairer unit type");
+    assert_error(is_unit_type(u2),
+                "Repair Check: Encountered an invalid repairee unit type");
+    if (0 < uu_auto_repair(u, u2))
+       return TRUE;
+    return FALSE;
+}
+
+int
+can_auto_repair(Unit *repairer, Unit *repairee)
+{
+    int rslt = A_ANY_OK;
+    int u2 = NONUTYPE, u3 = NONUTYPE;
+    int recovery = FALSE;
+    int dist = -1;
+
+    if (!is_active(repairer))
+       return A_ANY_ERROR;
+    assert_error(in_play(repairee),
+                "Repair Check: Attempted to manipulate out-of-play repairee");
+    // Useful info.
+    u2 = repairer->type;
+    u3 = repairee->type;
+    dist = distance(repairer->x, repairer->y, repairee->x, repairee->y);
+    // Check if there is any repair to perform.
+    // Note: We check against full HP rather than doctrine level here, 
+    // because, technically, anything less than full HP means that 
+    // repair could be performed.
+    if (repairee->hp >= u_hp(u3))
+       return A_ANY_OK;
+    // Could we use hp-recovery mechanism?
+    if ((repairer == repairee) && (0 < u_hp_recovery(u2))) 
+       recovery = TRUE;
+    // Could we auto-repair?
+    if (!could_auto_repair(u2, u3) && !recovery)
+       return A_ANY_CANNOT_DO;
+    // Can we use hp-recovery mechanism?
+    if (recovery) {
+       if (repairee->hp < u_hp_to_recover(u2))
+           // TODO: Should return A_REPAIR_TOO_DAMAGED.
+           return A_ANY_NO_MATERIAL;
+       return A_ANY_OK;
+    }
+    // Are we in range for auto-repair?
+    if (dist > uu_auto_repair_range(u2, u3))
+       return A_ANY_TOO_FAR;
+    // Additional checks.
+    if (!valid(rslt = can_any_repair_common(repairer, repairer, repairee)))
+       return rslt;
+    return rslt;
+}
+
+int
+could_repair(int u, int u2)
+{
+    assert_error(is_unit_type(u),
+                "Repair Check: Encountered an invalid repairer unit type");
+    assert_error(is_unit_type(u2),
+                "Repair Check: Encountered an invalid repairee unit type");
+    if (uu_repair(u, u2) && (0 < uu_hp_per_repair(u, u2)))
+       return TRUE;
+    return FALSE;
+}
+
+int
+can_repair(Unit *actor, Unit *repairer, int u3)
+{
+    int rslt = A_ANY_OK;
+    int u = NONUTYPE, u2 = NONUTYPE;
+
+    assert_error(is_active(actor),
+                "Repair Check: Attempted to manipulate inactive actor");
+    assert_error(is_active(repairer),
+                "Repair Check: Attempted to manipulate inactive repairer");
+    assert_error(is_unit_type(u3),
+                "Repair Check: Encountered an invalid repairee unit type");
+    u = actor->type;
+    u2 = repairer->type;
+    // Check if we meet basic action requirements.
+    if (!valid(rslt = can_act(actor, repairer)))
+       return rslt;
+    // Could we explicitly repair?
+    if (!could_repair(u2, u3))
+       return A_ANY_CANNOT_DO;
+    return rslt;
+}
+
+int
+can_repair(Unit *actor, Unit *repairer, Unit *repairee)
+{
+    int rslt = A_ANY_OK;
+    int u = NONUTYPE, u2 = NONUTYPE, u3 = NONUTYPE;
+    int acp = -1, dist = -1;
+
+    assert_error(is_active(actor),
+                "Repair Check: Attempted to manipulate inactive actor");
+    assert_error(is_active(repairer),
+                "Repair Check: Attempted to manipulate inactive repairer");
+    assert_error(in_play(repairer),
+                "Repair Check: Attempted to manipulate out-of-play repairee");
+    // Additional checks.
+    if (!valid(rslt = can_any_repair_common(repairer, repairer, repairee)))
+       return rslt;
+    // Useful info.
+    u = actor->type;
+    u2 = repairer->type;
+    u3 = repairee->type;
+    dist = distance(repairer->x, repairer->y, repairee->x, repairee->y);
+    // Check if there is any repair to perform.
+    // Note: We check against full HP rather than doctrine level here, 
+    // because, technically, anything less than full HP means that 
+    // repair could be performed.
+    if (repairee->hp >= u_hp(u3))
+       return A_ANY_OK;
+    if (!valid(rslt = can_repair(actor, repairer, u3)))
+       return rslt;
+    if (dist > uu_repair_range(u2, u3))
+       return A_ANY_TOO_FAR;
+    // Check if necessary ACP is available for explicit repair.
+    if (!u_acp_independent(u2) && (0 < uu_acp_to_repair(u2, u3))) {
+       acp = uu_acp_to_repair(u2, u3);
+       if (!can_have_enough_acp(actor, acp))
+           return A_ANY_CANNOT_DO;
+       if (!has_enough_acp(actor, acp))
+           return A_ANY_NO_ACP;
+    }
+    return rslt;
+}
+
+int
+can_change_type_to(int u, int u2, Side *side)
+{
+    int rslt = A_ANY_OK;
+    int a = NONATYPE;
+
+    assert_error(is_unit_type(u), "Attempted to reference an invalid utype");
+    assert_error(is_unit_type(u2), 
+                "Attempted to change type to an invalid utype");
+    assert_error(side, "Attempted to access a NULL side");
+    /* Check if a manual change-type or auto-upgrade is ever possible. */
+    if (!could_change_type_to(u, u2) && !could_auto_upgrade_to(u, u2))
+      return A_ANY_CANNOT_DO;
+    /* Check if the turn number is high enough. */
+    if (g_turn() < uu_turn_to_change_type(u, u2))
+      /* (Should return A_ANY_PREMATURE.) */
+      return A_ANY_NO_MATERIAL; 
+    /* Check if the unit's new type can be on the side. */
+    if (!type_allowed_on_side(u2, side))
+      return A_ANY_CANNOT_DO;
+    /* Check if the unit could ever have anough CXP. */
+    if (u_cxp_max(u) < uu_cxp_to_change_type(u, u2))
+      return A_ANY_CANNOT_DO;
+    /* Check if there could ever be ebough tech. */
+    if (u_tech_max(u2) < u_tech_to_change_type_to(u2))
+      return A_ANY_CANNOT_DO;
+    /* Check if the side has enough tech. */
+    if (side->tech[u2] < u_tech_to_change_type_to(u2))
+      /* (Should return A_ANY_NO_TECH.) */
+      return A_ANY_NO_MATERIAL;
+    /* Check that the side has any advances necessary for the change. */
+    for_all_advance_types(a) {
+        if (!ua_to_change_type(u, a))
+          continue;
+        if (!has_advance(side, a))
+          /* (Should return A_ANY_NO_ADVANCE.) */
+          return A_ANY_NO_MATERIAL;
+    }
+    return rslt;
+}
+
+//! Can given unit change into given utype?
+
+int
+can_change_type_to(Unit *actor, Unit *morpher, int u3)
+{
+    int rslt = A_ANY_OK;
+    int u = NONUTYPE, u2 = NONUTYPE, u4 = NONUTYPE;
+    int acp = 0;
+    Unit *occ = NULL;
+
+    assert_error(in_play(actor), "Attempted to manipulate an out-of-play unit");
+    assert_error(in_play(morpher), 
+                "Attempted to manipulate an out-of-play unit");
+    assert_error(is_unit_type(u3), 
+                "Attempted to change type into an invalid utype");
+    if (!valid(rslt = can_act(actor, morpher)))
+      return rslt;
+    u = actor->type;
+    u2 = morpher->type;
+    /* Is manual change-type valid? */
+    if (!at_turn_start && !uu_change_type_to(u2, u3))
+      return A_ANY_CANNOT_DO;
+    /* Is auto-upgrade valid? */
+    if (at_turn_start && (u3 != u_auto_upgrade_to(u2)))
+      return A_ANY_CANNOT_DO;
+    /* Go through utype-based and side-based tests. */
+    if (!valid(rslt = can_change_type_to(u2, u3, actor->side)))
+      return rslt;
+    acp = uu_acp_to_change_type(u2, u3);
+#if (0)
+    /* Check if the unit can even perform the action. */
+    if (!at_turn_start && !u_acp_independent(u) && (acp < 1))
+      return A_ANY_CANNOT_DO;
+#endif
+    /* Check if the actor actually has enough ACP to make the 
+       change-type happen. Give a free pass for automated happenings at the 
+       the turn start. */
+    if (!at_turn_start && !u_acp_independent(u) && !has_enough_acp(actor, acp))
+      return A_ANY_NO_ACP;
+    /* Check that the unit has grown enough. */
+    if (morpher->size < uu_size_to_change_type(u2, u3))
+      /* (Should return A_ANY_TOO_SMALL.) */
+      return A_ANY_NO_MATERIAL;
+    /* Check that the unit has the necessary CXP for the change. */
+    if (morpher->cxp < uu_cxp_to_change_type(u2, u3))
+      /* (Should return A_ANY_NO_CXP.) */
+      return A_ANY_NO_MATERIAL; 
+    /* Check that the unit has any materials necessary for the change. */
+    if (!valid(rslt = 
+               can_meet_materials_requirement(actor, morpher, 
+                                              um_to_change_type)))
+      return rslt;
+    if (!valid(rslt = 
+               can_meet_materials_requirement(actor, morpher, 
+                                              um_consumption_per_change_type)))
+      return rslt;
+    /* Check that the unit has any occupants necessary for the change. */
+    for_all_unit_types(u4) 
+      tmp_u_array[u4] = uu_occs_to_change_type(u2, u4);
+    for_all_occupants(morpher, occ) {
+        u4 = occ->type;
+        if (!uu_occs_to_change_type(u2, u4))
+          continue;
+        --(tmp_u_array[u4]);
+    }
+    for_all_unit_types(u4) {
+        if (tmp_u_array[u4])
+          /* (Should return A_ANY_NO_OCCS.) */
+          return A_ANY_NO_MATERIAL;
+    }
+    return rslt;
+}
+
+/*! \brief Action Initialization.
+ *
+ * Do any action-related initialization.
+ * Currently it doesn't do anything.
+ */
+void
+init_actions(void)
+{
+}
+
+/*! \brief Prepare for No Action.
+ *
+ * Just a placeholder action, so not much to do here.
+ *
+ * \see do_none_action, check_none_action
+ *
+ * \param unit is the pointer to the \Unit initiating action.
+ * \param actee is the pointer to the \Unit which performs the action.
+ * \return
+ *   - TRUE if action is queed.
+ *   - FALSE if 
+ *     - \Unit pointer to unit is NULL, 
+ *     - \Unit action pointer is NULL, or
+ *     - \Unit pointer to actee is NULL
+ */
+int
+prep_none_action(Unit *unit, Unit *actee)
+{
+    if (unit == NULL || unit->act == NULL || actee == NULL) {
+       return FALSE;
+    }
     unit->act->nextaction.type = ACTION_NONE;
-    unit->act->nextaction.actee = unit2->id;
+    unit->act->nextaction.actee = actee->id;
     return TRUE;
 }
 
+/*! \brief Do No Action.
+ *
+ * Perform no action action. :-)
+ *
+ * \see prep_none_action, check_none_action.
+ *
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param actee is the pointer to the \Unit which performs the action.
+ * \return A_ANY_DONE always.
+ */
 int
-do_none_action(Unit *unit, Unit *unit2)
+do_none_action(Unit *unit, Unit *actee)
 {
     return A_ANY_DONE;
 }
 
+/*! \brief Check for No Action.
+ *
+ * Check to see if no action is possible.
+ *
+ * \see prep_none_action, do_none_action.
+ *
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param actee is the pointer to the \Unit which performs the action
+ * \return A_ANY_DONE always.
+ */
 int
-check_none_action(Unit *unit, Unit *unit2)
+check_none_action(Unit *unit, Unit *actee)
 {
     return A_ANY_DONE;
 }
@@ -101,207 +1157,542 @@ check_none_action(Unit *unit, Unit *unit2)
 
 /* Explicit material production. */
 
+/*! \brief Prepare for Material Production Action.
+ *
+ * Produce materials from unit.  The unit supplies the ACP
+ * for the action, and stores the action arguments.  The
+ * producer stores the available material.
+ * - Sets the next action type to ACTION_PRODUCE.
+ * - Sets the type and amount of production.
+ * - Set producer to the actee.
+ * Fails if either of the pointers to \Unit is NULL, or tha ction is NULL.
+ *
+ * \see do_produce_action, check_produce_action.
+ *
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param producer is the pointer to the \Unit extracting the material.
+ * \param m is material type.
+ * \param amount is amount of material to produce.
+ * \return 
+ *    - TRUE if action is queed.
+ *    - FALSE if
+ *      - unit pointer is NULL,
+ *      - unit action pointer is NULL, or
+ *      - producer pointer is NULL.
+ */
 int
-prep_produce_action(unit, unit2, m, n)
-Unit *unit, *unit2;
-int m, n;
+prep_produce_action(Unit *unit, Unit *producer, int m, int amount)
 {
-    if (unit == NULL || unit->act == NULL || unit2 == NULL)
-      return FALSE;
+    if (unit == NULL || unit->act == NULL || producer == NULL) {
+       return FALSE;
+    }
     unit->act->nextaction.type = ACTION_PRODUCE;
     unit->act->nextaction.args[0] = m;
-    unit->act->nextaction.args[1] = n;
-    unit->act->nextaction.actee = unit2->id;
+    unit->act->nextaction.args[1] = amount;
+    unit->act->nextaction.actee = producer->id;
     return TRUE;
 }
 
+/*! \brief Do Material Production Action.
+ *
+ * Produce materials from a unit.  The producer unit stores as much material 
+ * internally as possible, then distributes it ot units around it.
+ * - Sets the production amount to the quantity asked for, or the
+ *    maximum that can be produced, whichever is less.
+ * - Clips the amount stored to the storeage maximum.
+ * - If there is an excess amount, passes it around, if possible.
+ * - Uses up ACP for production.
+ *
+ * \see prep_produce_action, check_produce_action, um_material_per_production,
+ *      um_storate_x, distribute_material, use_up_acp, 
+ *      um_acp_to_produce.
+ *
+ * \GDL
+ *    - <a href="xcdesign_246.html#GDL_ref_acp-to-produce">acp-to-produce</a>
+ *    - <a href="xcdesign_246.html#GDL_ref_material-per-production">material-per-production</a>
+ *    - <a href="xcdesign_246.html#GDL_ref_material-to-produce">material-to-produce</a>
+ *    - <a href="xcdesign_204.html#GDL_ref_unit-storage-x">unit-storage-x</a>
+ *    - <a href="xcdesign_182.html#GDL_ref_unit-type">unit-type</a>
+ *
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param producer is the pointer to the \Unit which extracts the material.
+ * \param m is the material type.
+ * \param amount is the amount of material to produce.
+ * \return A_ANY_DONE always.
+ */
 int
-do_produce_action(unit, unit2, m, n)
-Unit *unit, *unit2;
-int m, n;
+do_produce_action(Unit *unit, Unit *producer, int m, int amount)
 {
-    int amt, excess;
-
-    amt = min(n, um_material_per_production(unit2->type, m));
-    unit2->supply[m] += n;
-    /* Clip to storage space and pass around any extra. */
-    excess = unit2->supply[m] - um_storage_x(unit2->type, m);
+    int amt;   /* amount of material produced */
+    int excess; /* amount of material that can't be stored by producer */
+    int space; /* max amount of material that can be added to the supply */
+
+    /* Note: it is very important that the transactions below are made in the
+    correct order to avoid both numeric overflow in the producer's supply and 
+    the latter being depleted before all excess has been passed around. */
+    amt = min(amount, um_material_per_production(producer->type, m));
+    space = um_storage_x(producer->type, m) - producer->supply[m];
+
+    /* First fill up the producer as far as there is room. */
+    producer->supply[m] += min(amt, space);
+    /* Compute the excess we couldn't store. */
+    excess = amt - space;
+    /* Try to give away the same amount to make room for the excess. */
     if (excess > 0) {
-       unit2->supply[m] -= excess;
-       distribute_material(unit2, m, excess);
+       /* But first clip it to available supplies. */
+       excess = min(excess, producer->supply[m]);
+       producer->supply[m] -= excess;
+       distribute_material(producer, m, excess);
     }
-    use_up_acp(unit, um_acp_to_produce(unit2->type, m));
+    /* Then try to fill up the producer again with the remaining excess. */
+    space = um_storage_x(producer->type, m) - producer->supply[m];
+    /* The check for available space is redundant now, but will be needed
+    in the future when distribute_material has been improved. */
+    producer->supply[m] += min(excess, space);
+    use_up_acp(unit, um_acp_to_produce(producer->type, m));
     return A_ANY_DONE;
 }
 
+/*! \brief Check for Material Production Action.
+ *
+ * Produce materials from Unit.
+ * Validate:
+ *    - unit is in play
+ *    - producer is in play.
+ *    - material type is valid.
+ *    - producer needs at least 1 acp to produce material
+ *    - unit must be able to have enough acp to produce at some point
+ *      in the future.
+ *    - unit has enough acp to produce the material
+ *    - all needed supplies to produce the material
+ *      are available.
+ *    .
+ * \see prep_produce_action, do_produce_action, in_play,
+ *      is_material_type, um_acp_to_produce, can_have_enough_acp,
+ *      um_material_per_production, has_enough_acp, for_all_material_types,
+ *      um_to_produce.
+ *
+ * \GDL
+ *    - <a href="xcdesign_246.html#GDL_ref_acp-to-produce">acp-to-produce</a>
+ *    - <a href="xcdesign_246.html#GDL_ref_material-per-production">material-per-production</a>
+ *    - <a href="xcdesign_246.html#GDL_ref_material-to-produce">material-to-produce</a>
+ *    - <a href="xcdesign_182.html#GDL_ref_unit-type">unit-type</a>
+ *
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param producer is the pointer to the \Unit that extracts the material.
+ * \param m is material type?
+ * \param amount is amount of material produced?
+ * \return 
+ *   - A_ANY_ERROR if
+ *     - unit is not in play
+ *     - producer is not in play
+ *     - the material type is unknown
+ *     .
+ *   - A_ANY_CANNOT_DO if
+ *     - ACP of unit is less than 1
+ *     - if the unit cannot ever have enough ACP for the extraction
+ *     - if the material production per turn is less than 1
+ *     .
+ *   - A_ANY_NO_ACP if the unit doesn't have enough ACP
+ *   - A_ANY_NO_MATERIAL if any required materials are not available.
+ *   - A_ANY_OK if the unit can produce the material.
+ */
 int
-check_produce_action(unit, unit2, m, n)
-Unit *unit, *unit2;
-int m, n;
+check_produce_action(Unit *unit, Unit *producer, int m, int amount)
 {
-    int acp, m2, u2;
+    int acp;                   /* ACP used in production of material */
+    int supply;                /* iteration - material needed as supplies to produce material */
 
-    if (!in_play(unit))
-      return A_ANY_ERROR;
-    if (!in_play(unit2))
-      return A_ANY_ERROR;
-    if (!is_material_type(m))
-      return A_ANY_ERROR;
-    u2 = unit2->type;
-    acp = um_acp_to_produce(u2, m);
-    if (acp < 1)
-      return A_ANY_CANNOT_DO;
-    if (!can_have_enough_acp(unit, acp))
-      return A_ANY_CANNOT_DO;
-    if (um_material_per_production(u2, m) < 1)
-      return A_ANY_CANNOT_DO;
-    if (!has_enough_acp(unit, acp))
-      return A_ANY_NO_ACP;
+    if (!in_play(unit)) {
+       return A_ANY_ERROR;
+    }
+    if (!in_play(producer)) {
+       return A_ANY_ERROR;
+    }
+    if (!is_material_type(m)) {
+       return A_ANY_ERROR;
+    }
+    acp = um_acp_to_produce(producer->type, m);
+    if (acp < 1) {
+       return A_ANY_CANNOT_DO;
+    }
+    if (!can_have_enough_acp(unit, acp)) {
+       return A_ANY_CANNOT_DO;
+    }
+    if (um_material_per_production(producer->type, m) < 1) {
+       return A_ANY_CANNOT_DO;
+    }
+    if (!has_enough_acp(unit, acp)) {
+       return A_ANY_NO_ACP;
+    }
     /* Check that the unit has any required supplies. */
-    for_all_material_types(m2) {
-       if (unit2->supply[m2] < um_to_produce(u2, m2))
-         return A_ANY_NO_MATERIAL;
+    for_all_material_types(supply) {
+       if (producer->supply[supply] < um_to_produce(producer->type, supply)) {
+           return A_ANY_NO_MATERIAL;
+       }
     }
     return A_ANY_OK;
 }
 
 /* Extraction of material from terrain. */
 
+/*! \brief Prepare for Terrain Extraction Action.
+ *
+ * Prepare to extract material from a cell.  The unit supplies the ACP
+ * for the extraction process and stores the parameters for the extaction
+ * action.  The extractor is the unit which recieves the material.
+ *
+ * \see do_extract_action, check_extract_action.
+ *
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param extractor is the pointer to the \Unit doing the extraction.
+ * \param x is the x co-ordinate of the cell.
+ * \param y is the y co-ordinate of the cell.
+ * \param m is the material to extract from the cell.
+ * \param amount is the quantify of material to extract from the cell.
+ * \return
+ *    - true action is queed.
+ *    -false if 
+ *      - unit pointer is NULL,
+ *      - unit action pointer is NULL, or
+ *      - extractor pointer is NULL
+ */
 int
-prep_extract_action(unit, unit2, x, y, m, n)
-Unit *unit, *unit2;
-int x, y, m, n;
+prep_extract_action(Unit *unit, Unit *extractor, int x, int y, int m, int amount)
 {
-    if (unit == NULL || unit->act == NULL || unit2 == NULL)
-      return FALSE;
+    if (unit == NULL || unit->act == NULL || extractor == NULL) {
+       return FALSE;
+    }
     unit->act->nextaction.type = ACTION_EXTRACT;
     unit->act->nextaction.args[0] = x;
     unit->act->nextaction.args[1] = y;
     unit->act->nextaction.args[2] = m;
-    unit->act->nextaction.args[3] = n;
-    unit->act->nextaction.actee = unit2->id;
+    unit->act->nextaction.args[3] = amount;
+    unit->act->nextaction.actee = extractor->id;
     return TRUE;
 }
 
+/*! \brief Do Terrain Material Extraction Action.
+ *
+ * Extract material from the cell or other \Units in the cell.
+ * - Calculate material production.
+ *   - if cell produces material and has at least amount units of material
+ *      - reduce materials at cell by amount.
+ *      - if remaining amount is zero and the probability of changing
+ *           on exhaustion is met, and the terrain on exhaustion has
+ *           a value, change the terrain.
+ *   - else try to supply from \Units in cell.
+ * - clip to amount requested.
+ * - distribute excess to other \Units.
+ * - reduce ACP of the unit \Unit.
+ *
+ * \see prep_extract_action, check_extract_action, any_cell_materials_defined,
+ *      cell_material_defined, material_at, set_material_at, terrain_at,
+ *      probabability, tm_change_on_exhaust, tm_exhaust_type,
+ *      change_terrain_type, for_all_stack, um_storage_x, distribute_material,
+ *      use_up_acp, um_acp_to_extract.
+ *
+ * \GDL
+ *    - <a href="xcdesign_247.html#GDL_ref_acp-to-extract">acp-to-extract</a>
+ *    - <a href="xcdesign_263.html#GDL_ref_change-on-exhaustion-chance">change-on-exhaustion-chance</a>
+ *    - <a href="xcdesign_263.html#GDL_ref_terrain-exhaustion-type">terrain-exhaustion-type</a>
+ *    - <a href="xcdesign_204.html#GDL_ref_unit-storage-x">unit-storage-x</a>
+ *    - <a href="xcdesign_182.html#GDL_ref_unit-type">unit-type</a>
+ *
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param extractor is the pointer to the \Unit extracting the material.
+ * \param x is the cell x location.
+ * \param y is the cell y location.
+ * \param m is the material needed.
+ * \param amount is the quanity to produce.
+ * \return A_ANY_DONE.
+ */
 int
-do_extract_action(unit, unit2, x, y, m, n)
-Unit *unit, *unit2;
-int x, y, m, n;
+do_extract_action(Unit *unit, Unit *extractor, int x, int y, int m, int amount)
 {
-    int oldamt, amt, newamt, excess, t, newt;
-    Unit *unit3;
+    int found = 0;             /* Amount of material actually extracted. */
+    int excess;                /* Amount of material that can't be stored in extractor. */
+    int space;                 /* Free space in the supply. */
+
+    /* Do one attempt at extracting the amount. */
+    found = extract_one_round(extractor, x, y, m, amount);
+    /* Compute the excess we couldn't extract. */
+    excess = amount - found;
+    /* Compute the remaining storage space. */
+    space = um_storage_x(extractor->type, m) - extractor->supply[m];
+    /* If we ran out of space, we try to make room for more. */
+    if (space == 0
+        && excess > 0) {
+       /* But first clip to availble storage space. */
+       excess = min(excess, extractor->supply[m]);
+       extractor->supply[m] -= excess;
+       distribute_material(extractor, m, excess);
+    }
+    /* Do one more attempt at extracting the remaining amount. */
+    found += extract_one_round(extractor, x, y, m, excess);
+
+    use_up_acp(unit, um_acp_to_extract(extractor->type, m));
+    if (found < amount) {
+       /* Should never happen since materials were checked by check_extract_action. */
+       run_warning("%s unable to extract %d %s at (%d, %d).", 
+               short_unit_handle(extractor), amount, m_type_name(m), x, y);
+       return A_ANY_ERROR;
+    } else {
+       return A_ANY_DONE;
+    }
+}
 
+int
+extract_one_round(Unit *extractor, int x, int y, int m, int amount)
+{
+    int oldamt;                /* Amount of material in terrain before adjustment */
+    int amt;                   /* Amount of material removed. */
+    int newamt;                /* New amount of material in terrain after extraction. */
+    int space;                 /* Max amount of material that can be added to the supply */
+    int found = 0;             /* Amount of material actually extracted. */
+    int t;                             /* Rerrain of cell */
+    int newt;          /* New terrain type of cell if all materials extracted */
+    Unit *unit2;               /* Iteration - pointer to next unit in stack of units. */
+
+    /* First compute the available storage space. */
+    space = um_storage_x(extractor->type, m) - extractor->supply[m];
+
+    /* Get what we can get from the terrain. */
     if (any_cell_materials_defined()
-       && cell_material_defined(m)
-       && material_at(x, y, m) >= n) {
+         && cell_material_defined(m)
+         && material_at(x, y, m) > 0) {
        oldamt = material_at(x, y, m);
-       amt = min(n, oldamt);
-       unit2->supply[m] += amt;
-       newamt = oldamt - amt;
+       amt = min(amount, oldamt);
+       /* First fill up the extractor as far as there is room. */
+       extractor->supply[m] += min(amt, space);
+       newamt = oldamt - min(amt, space);
+       found += min(amt, space);
+       space -= min(amt, space);
        set_material_at(x, y, m, newamt);
        /* (should do with a common routine) */
        t = terrain_at(x, y);
        if (newamt == 0
-           && probability(tm_change_on_exhaust(t, m))
-           && tm_exhaust_type(t, m) != NONTTYPE) {
+             && probability(tm_change_on_exhaust(t, m))
+             && tm_exhaust_type(t, m) != NONTTYPE) {
            newt = tm_exhaust_type(t, m);
            /* Change the terrain's type. */
            change_terrain_type(x, y, newt);
        }
-    } else {
-       for_all_stack(x, y, unit3) {
-           if (in_play(unit3) && indep(unit3) && unit3->supply[m] >= n) {
-               oldamt = unit3->supply[m];
-               amt = min(n, oldamt);
-               unit2->supply[m] += amt;
-               newamt = oldamt - amt;
-               unit3->supply[m] = newamt;
-               break;
+    }
+    /* If there was not enough material in the terrain we proceed
+    to plunder any owner-less independent units in the stack. */
+    if (amount - found > 0
+       && space > 0
+       && g_no_indepside_ingame()) {
+       for_all_stack(x, y, unit2) {
+           /* If we don't need more or ran out of space we are done. */
+           if (amount - found == 0 || space == 0) {
+               break;
+           }
+           if (in_play(unit2) 
+               && indep(unit2) 
+               && unit2->supply[m] >= 0) {
+               oldamt = unit2->supply[m];
+               amt = min(amount - found, oldamt);
+               /* First fill up the extractor as far as there is room. */
+               extractor->supply[m] += min(amt, space);
+               found += min(amt, space);
+               newamt = oldamt - min(amt, space);
+               unit2->supply[m] = newamt;
+               space -= min(amt, space);
            }
        }
     }
-    /* Clip to storage space and pass around any extra. */
-    excess = unit2->supply[m] - um_storage_x(unit2->type, m);
-    if (excess > 0) {
-       unit2->supply[m] -= excess;
-       distribute_material(unit2, m, excess);
-    }
-    use_up_acp(unit, um_acp_to_extract(unit2->type, m));
-    return A_ANY_DONE;
+    return found;
 }
 
+/*! \brief Check for Terrain Material Estraction Action.
+ *
+ * This checks to see if an extract operation is possible.
+ * It verifies:
+ * - the unit is in play,
+ * - the extractor is in play,
+ * - the material type is valid,
+ * - the unit is capable of extracting material (no negative ACP balance)
+ * - the unit has enough available ACP,
+ * - the extractor has any supplies needed for extraction.
+ * It then checks to see if material can be produced from the cell,
+ * else from any other independent \Units also in the cell.
+ *
+ * \see prep_extract_action, do_extract_action, in_play, is_material_type,
+ *      um_acp_to_extract, can_have_enough_acp, has_enough_acp,
+ *      for_all_material_types, um_to_extract, any_cell_materials_defined,
+ *      cell_material_defined, material_at, for_all_stack, indep.
+ *
+ * \GDL
+ *    - <a href="xcdesign_247.html#GDL_ref_acp-to-extract">u-acp-to-extract</a>
+ *    - <a href="xcdesign_263.html#GDL_ref_change-on-exhaustion-chance">change-on-exhaustion-chance</a>
+ *    - <a href="xcdesign_182.html#GDL_ref_unit-type">unit-type</a>
+ *
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param extractor is the pointer to the \Unit on which the action is preformed,
+ * \param x is the x co-ordinate of the  cell,
+ * \param y is the y co-ordinate of the cell,
+ * \param m is the material to be produced,
+ * \param amount is the quanity to be produced.
+ * \return
+ *    - A_ANY_ERROR if
+ *      - the unit is not in play,
+ *      - the extractor is not in play,
+ *      - the material type is not valid.
+ *    - A_ANY_CANNOT_DO if
+ *      - the ACP is negative,
+ *      - the unit can never have enough ACP.
+ *    - A_ANY_NO_ACP if the unit doesn't have enough ACP.
+ *    - A_ANY_NO_MATERIAL if the cell doesn't have the material.
+ *    - A_ANY_OK if the material is available.
+ *    - A_EXTRACT_NO_SOURCE if no material could be extracted.
+ */
 int
-check_extract_action(unit, unit2, x, y, m, n)
-Unit *unit, *unit2;
-int x, y, m, n;
+check_extract_action(Unit *unit, Unit *extractor, int x, int y, int m, int amount)
 {
-    int acp, m2, u2;
-    Unit *unit3;
+    int acp;                   /* ACP for extraction. */
+    int supply;                /* supply needed for extraction. */
+    int found;         /* materials found when looking around. */
+    Unit *stack_unit;  /* interation - pointer to next stack unit. */
 
-    if (!in_play(unit))
-      return A_ANY_ERROR;
-    if (!in_play(unit2))
-      return A_ANY_ERROR;
-    if (!is_material_type(m))
-      return A_ANY_ERROR;
-    u2 = unit2->type;
-    acp = um_acp_to_extract(u2, m);
-    if (acp < 1)
-      return A_ANY_CANNOT_DO;
-    if (!can_have_enough_acp(unit, acp))
-      return A_ANY_CANNOT_DO;
-    if (!has_enough_acp(unit, acp))
-      return A_ANY_NO_ACP;
+    if (!in_play(unit)) {
+       return A_ANY_ERROR;
+    }
+    if (!in_play(extractor)) {
+       return A_ANY_ERROR;
+    }
+    if (!is_material_type(m)) {
+       return A_ANY_ERROR;
+    }
+    acp = um_acp_to_extract(extractor->type, m);
+    if (acp < 1) {
+       return A_ANY_CANNOT_DO;
+    }
+    if (!can_have_enough_acp(unit, acp)) {
+       return A_ANY_CANNOT_DO;
+    }
+    if (!has_enough_acp(unit, acp)) {
+       return A_ANY_NO_ACP;
+    }
     /* Check that the unit has any required supplies. */
-    for_all_material_types(m2) {
-       if (unit2->supply[m2] < um_to_extract(u2, m2))
-         return A_ANY_NO_MATERIAL;
+    for_all_material_types(supply) {
+       if (extractor->supply[supply] < um_to_extract(extractor->type, supply)) {
+           return A_ANY_NO_MATERIAL;
+       }
     }
     /* Look for case of extraction from terrain. */
+    found = 0;
     if (any_cell_materials_defined()
        && cell_material_defined(m)
-       && material_at(x, y, m) >= n)
-      return A_ANY_OK;
-    /* Then look for extraction from independent unit. */
-    for_all_stack(x, y, unit3) {
-       if (in_play(unit3)
-           && indep(unit3)
-           && unit3->supply[m] >= n) {
-           return A_ANY_OK;
-       }
+       /* amount is currently always 1 (see do_collect_task) so this is in fact
+       a check for material_at(x, y, m) > 0. However, we keep support
+       for n in case the task code is modified in the future. */
+       && material_at(x, y, m) > 0) {
+       found += material_at(x, y, m);
+    }
+    /* Then look for extraction from independent unit provided that there
+    is no independent side that owns these units. This breaks the one game
+    that uses explicit extraction, ancient-days, but prevents the absurd 
+    case where a unit is using units belonging to another side (indepside) 
+    to resupply itself. Possible fix for ancient-days: let berry bushes etc.
+    be independent, set no-indepside-ingame to true, and let live animals
+    belong to a third side. */
+    if (g_no_indepside_ingame()) {
+           for_all_stack(x, y, stack_unit) {
+               if (in_play(stack_unit)
+                   && indep(stack_unit)
+                   && stack_unit->supply[m] > 0) {
+                       found += stack_unit->supply[m];
+               }
+           }
+    }
+    if (found >= amount) {
+       return A_ANY_OK;    
     }
-    return A_ANY_ERROR; /* (should be "nothing to extract from") */
+    return A_EXTRACT_NO_SOURCE;
 }
 
 /* Transfer action. */
 
 /* This action transfers material from one unit to another. */
 
+/*! \brief Prepare for Material Transfer Action.
+ *
+ * This routine sets up a material transfer from one \Unit to another.
+ * The unit \Unit supplies the ACP for the action, and stores the parameters
+ * for the action.  The from Unit supplies the material to the to Unit.
+ *
+ * \see do_transfer_action, check_transfer_action.
+ *
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param from is the \Unit the materisl comes from.
+ * \param m is the material being transferred.
+ * \param amount is the quanity of material being transferred.
+ * \param to is the \Unit receiving the transfer.
+ * \return 
+ *   - TRUE if action is queed.
+ *   - FALSE if 
+ *     - unit pointer is NULL,
+ *     - unit action pointer is NULL,
+ *     - from pointer is NULL, or
+ *     - to pointer is NULL.
+ */
 int
-prep_transfer_action(Unit *unit, Unit *unit2, int m, int n, Unit *unit3)
+prep_transfer_action(Unit *unit, Unit *from, int m, int amount, Unit *to)
 {
-    if (unit == NULL || unit->act == NULL || unit2 == NULL || unit3 == NULL)
-      return FALSE;
+    if (unit == NULL || unit->act == NULL || from == NULL || to == NULL) {
+       return FALSE;
+    }
     unit->act->nextaction.type = ACTION_TRANSFER;
     unit->act->nextaction.args[0] = m;
-    unit->act->nextaction.args[1] = n;
-    unit->act->nextaction.args[2] = unit3->id;
-    unit->act->nextaction.actee = unit2->id;
+    unit->act->nextaction.args[1] = amount;
+    unit->act->nextaction.args[2] = to->id;
+    unit->act->nextaction.actee = from->id;
     return TRUE;
 }
 
+/*! \brief Do Material Transfer Action.
+ *
+ * This routine transfers material from one \Unit to another.
+ * Transfer goes from the to Unit to the from Unit if the 
+ * quanity transferred is negative.  The actual quantity transfered is
+ * calculated by transfer_supply.  The ACP for the transer
+ * is used buy the unit Unit, even if no materis is transfered.
+ * Transfers always use 1 ACP.
+ *
+ * \todo Add return code specifying that only a partial amount of
+ *       material was transferred.
+ *
+ * \see prep_transfer_action, check_transfer_action, transfer_supply.
+ *
+ * \GDL
+ *    - <a href="xcdesign_248.html#GDL_ref_acp-to-unload">acp-to-unload</a>
+ *
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param from is the pointer to the \Unit supplying the material
+ *        (for positive transfers).
+ * \param m is the material being transferred.
+ * \param amount is the quanity of material being transferred.
+ * \param to is the pointer to the \Unit receiving the transfer
+ *        (for positive transfers).
+ * \return 
+ *   - A_ANY_ERROR if no material was transferred.
+ *   - A_ANY_DONE if at least one unit of material was transferred.
+ */
 int
-do_transfer_action(Unit *unit, Unit *unit2, int m, int n, Unit *unit3)
+do_transfer_action(Unit *unit, Unit *from, int m, int amount, Unit *to)
 {
-    int actual;
+    int actual; /* Actual amount of material transferred */
 
-    if (n > 0) {
-       actual = transfer_supply(unit2, unit3, m, n);
+    if (amount > 0) {
+       actual = transfer_supply(from, to, m, amount);
+       use_up_acp(unit, um_acp_to_unload(from->type, m));
     } else {
-       actual = transfer_supply(unit3, unit2, m, -n);
+       actual = transfer_supply(to, from, m, -amount);
+       use_up_acp(unit, um_acp_to_unload(to->type, m));
     }
-    use_up_acp(unit, 1);
-    if (actual == n) {
+    if (actual == amount) {
        return A_ANY_DONE;
     } else if (actual == 0) {
        return A_ANY_ERROR;
@@ -311,178 +1702,451 @@ do_transfer_action(Unit *unit, Unit *unit2, int m, int n, Unit *unit3)
     }
 }
 
+/*! \brief Check for Material Transfer Action.
+ *
+ * This routine makes sure that a transfer is possible.
+ * It verifies
+ *  - that unit, <I>to</I>, and <I>from</I> \Units are in play.
+ *  - that the material tor transfer is a valid material,
+ *  - that the quantify of material to transfer is non-zero.
+ *  - that the <I>from</I> \Unit can unload material (ACP 1 or more),
+ *  - that the <I>to</I> \Unit may load material(ACP 1 or more),
+ *  - that the unit can ever have enough ACP to transfer the material,
+ *  - that the \Unit suppling the material has the supplies needed to 
+ *    transfer the material,
+ *  - that the \Unit receivng the material has the storage for the 
+ *    transferred material. and
+ *  - that the unit has enough ACP to transfer the material.
+ *
+ * \see prep_transfer_action, do_transfer_action, in_play, is_material_type, 
+ *      um_acp_to_unload, um_acp_to_load, can_have_enough_acp,
+ *      um_storage_x, has_enough_acp.
+ *
+ * \GDL
+ *    - <a href="xcdesign_248.html#GDL_ref_acp-to-load">acp-to-load</a>
+ *    - <a href="xcdesign_248.html#GDL_ref_acp-to-unload">acp-to-unload</a>
+ *    - <a href="xcdesign_182.html#GDL_ref_unit-type">unit-type</a>
+ *    
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param from is the pointer to the \Unit supplying the material (if
+ *        amount is positive).
+ * \param m is the material being transferred.
+ * \param amount is the quanity of material being transferred.
+ * \param to is the pointer to the \Unit receiving the transfer (if
+ *        amount is positive).
+ * \return 
+ *   - A_ANY_ERROR if
+ *     - the unit is not in play,
+ *     - the <I>to</I> \Unit is not in play,
+ *     - the material type is invalid,
+ *     - the quanity of material to produce is zero (negative is ok),
+ *     - the <I>from</I> \Unit is not in play,
+ *     - the appropriate \Unit (depending on quantity positive or negative) does
+ *       not have enough supplies of other materials on hand, or
+ *     - the appropriate \Unit does not have enough storage capacity.
+ *   - A_ANY_CANNOT_DO if
+ *     - the <I>from</I> \Unit cannot unload material (ACP to unload less than 1),
+ *     - the <I>to</I> \Unit has a NULL action pointer or cannot load material
+ *       (ACP to load less than 1), or
+ *     - the unit can never have enought ACP to do the transfer.
+ *   - A_ANY_NO_ACP if the unit doesn't have enought ACP.
+ *   - A_ANY_DONE if at least one unit of material can be transferred.
+ */
 int
-check_transfer_action(Unit *unit, Unit *unit2, int m, int n, Unit *unit3)
+check_transfer_action(Unit *unit, Unit *from, int m, int amount, Unit *to)
 {
-    if (!in_play(unit))
-      return A_ANY_ERROR;
-    if (!in_play(unit2))
-      return A_ANY_ERROR;
-    if (!is_material_type(m))
-      return A_ANY_ERROR;
-    if (n == 0)
-      return A_ANY_ERROR;
-    if (!in_play(unit3))
-      return A_ANY_ERROR;
-    if (um_acp_to_unload(unit2->type, m) < 1)
-      return A_ANY_CANNOT_DO;
-    if (unit3->act && um_acp_to_load(unit3->type, m) < 1)
-      return A_ANY_CANNOT_DO;
-    if (!can_have_enough_acp(unit, 1))
-      return A_ANY_CANNOT_DO;
-    if (n > 0) {
-       if (unit2->supply[m] <= 0)
-         return A_ANY_ERROR;
-       if (um_storage_x(unit3->type, m) == 0)
-         return A_ANY_ERROR;
+    if (!in_play(unit)) {
+       return A_ANY_ERROR;
+    }
+    if (!in_play(from)) {
+       return A_ANY_ERROR;
+    }
+    if (!is_material_type(m)) {
+       return A_ANY_ERROR;
+    }
+    if (amount == 0) {
+       return A_ANY_ERROR;
+    }
+    if (!in_play(to)) {
+       return A_ANY_ERROR;
+    }
+    if (amount > 0) {
+       if (um_acp_to_unload(from->type, m) < 1) {
+           return A_ANY_CANNOT_DO;
+       }
+       if (to->act && um_acp_to_load(to->type, m) < 1) {
+           return A_ANY_CANNOT_DO;
+       }
+       /* We check only the acp needed for the unload action since um_acp_to_load 
+       is used strictly as a permission flag (never causes acps to be consumed). */
+       if (!can_have_enough_acp(unit, um_acp_to_unload(from->type, m))) {
+           return A_ANY_CANNOT_DO;           
+       }
+       if (from->supply[m] <= 0) {
+           return A_ANY_ERROR;
+       }
+       if (um_storage_x(to->type, m) == 0) {
+           return A_ANY_ERROR;
+       }
     } else {
-       if (unit3->supply[m] <= 0)
-         return A_ANY_ERROR;
-       if (um_storage_x(unit2->type, m) == 0)
-         return A_ANY_ERROR;
+       if (um_acp_to_load(from->type, m) < 1) {
+           return A_ANY_CANNOT_DO;
+       }
+       if (to->act && um_acp_to_unload(to->type, m) < 1) {
+           return A_ANY_CANNOT_DO;
+       }
+       /* We check only the acp needed for the unload action since um_acp_to_load 
+       is used strictly as a permission flag (never causes acps to be consumed). */
+       if (!can_have_enough_acp(unit, um_acp_to_unload(to->type, m))) {
+           return A_ANY_CANNOT_DO;           
+       }
+       if (to->supply[m] <= 0) {
+           return A_ANY_ERROR;
+       }
+       if (um_storage_x(from->type, m) == 0) {
+           return A_ANY_ERROR;
+       }
+    }
+    if (!has_enough_acp(unit, 1)) {
+       return A_ANY_NO_ACP;
     }
-    if (!has_enough_acp(unit, 1))
-      return A_ANY_NO_ACP;
     return A_ANY_OK;
 }
 
-/* Move supply from one unit to another.  Don't move more than is
-   possible; check both from and to amounts and capacities.  This
-   routine will also transfer to the side's treasury if necessary to
-   handle overflow. */
-
+/*! \brief Transfer Supply.
+ *
+ * Move supply from one \Unit to another.  Don't move more than is
+ * possible; check both from and to amounts and capacities.  This
+ * routine will also transfer to the side's treasury if necessary can
+ * handle overflow. This is a utility routine.
+ * - Calculate the min amount to transfer based on the available
+ *   supply and the maximum that can be loaded in the to \Unit.
+ * - if there is a treasury for the material, and the receiving
+ *   \Unit can transfer material to the treasury, then transfer any
+ *   excess production from the from \Unit to the treasure
+ * - reduce the material supply of the from \Unit,
+ * - increase the  material supply of the to \Unit.
+ * - update to and from \Unit supply display for the sides involved.
+ * - if the treasury was modified, update the treasury supply display.
+ * - print debug message, if it's enabled.
+ *
+ * \see do_transfer_material, um_unload_max, um_load_max, UM_storage_x,
+ *      side_has_treasury, um_gives_to_treasury, update_unit_display,
+ *      update_side_display.
+ *
+ * \GDL
+ *    - <a href="xcdesign_248.html#GDL_ref_load-max">load-max</a>
+ *    - <a href="xcdesign_262.html#GDL_ref_gives-to-treasury">gives-to-treasury</a>
+ *    - <a href="xcdesign_161.html#GDL_ref_treasury">treasury</a>
+ *    - <a href="xcdesign_182.html#GDL_ref_unit-type">unit-type</a>
+ *    - <a href="xcdesign_248.html#GDL_ref_unload-max">unload-max</a>
+ *
+ * \param from is the pointer to the \Unit supplying the material.
+ * \param to is the pointer to the \Unit receiving the material.
+ * \param m is the material type to transfer.
+ * \param amount is the amount of material to transfer.
+ * \return the amount to transfer.
+ */
 int
 transfer_supply(Unit *from, Unit *to, int m, int amount)
 {
-    int amt2, origfrom = from->supply[m], origto = to->supply[m];
+    int amt2;                                  /* material amount */
+    int origfrom = from->supply[m];    /* Material originally in from unit */
+    int origto = to->supply[m];                /* Material originally in to Unit */
 
     /* Constrain the amount of supply that may be unloaded. */
     amount = min(amount, origfrom);
     if (um_unload_max(from->type, m) >= 0) {
        amount = min(amount, um_unload_max(from->type, m));
     }
+    /* Now constrain the amount of material that can be loaded */
     if (um_load_max(to->type, m) >= 0) {
        amount = min(amount, um_load_max(to->type, m));
     }
+    /* amount is now the material that is possible to transfer, 
+     * now figure out the amount that can actually be put into
+     * the 'to' Unit. */
     amt2 = min(amount, um_storage_x(to->type, m) - origto);
 
-    /* Transfer overflow to side's treasury if it exists. */
+#if 0 /* Using the treasury to dump overflow is rather dubious. 
+       Presumably, we are doing the transfer action because we
+       want 'to' to get the stuff, not because we want to fill up the
+       treasury. Better to keep the material in 'from', and do a
+       second transfer action if necessary. */ 
+
+    /* Transfer overflow to side's treasury if it exists.  If it 
+     * doesn't, reduce the amount transferred to the amount that
+     * the 'to' unit can hold. */
     if (side_has_treasury(to->side, m)
         && um_gives_to_treasury(to->type, m)) {
-       to->side->treasury[m] += (amount - amt2);
+       /* Make sure the treasury does not overflow. */
+       to->side->treasury[m] += min(g_treasury_size() - to->side->treasury[m], amount - amt2);
     } else {
        amount = amt2;
     }
+  /* Also dubious if from->supply should be decremented with 
+  more than is actually moved to either 'to' or treasury. */
     from->supply[m] -= amount;
+
+#else
+
+    from->supply[m] -= amt2;
+
+#endif
+
     to->supply[m] += amt2;
+
     /* Make sure any displays of supply levels see the transfer. */
     update_unit_display(from->side, from, TRUE);
     update_unit_display(to->side, to, TRUE);
+
+#if 0          /* Not needed if we don't transfer overflow to treasury. */
+
     if (amount != amt2) {
        update_side_display(from->side, from->side, TRUE);
        update_side_display(to->side, to->side, TRUE);
     }
-    Dprintf("%s (had %d) transfers %d %s to %s (had %d) (%d to side)\n",
-           unit_desig(from), origfrom, amount, m_type_name(m),
-           unit_desig(to), origto, (amount - amt2));
-    return amount;
+
+#endif
+
+    Dprintf("%s (had %d) transfers %d %s to %s (had %d)\n",
+           unit_desig(from), origfrom, amt2, m_type_name(m),
+           unit_desig(to), origto);
+    return amt2;
 }
 
 /* Develop action. */
 
-/* If a side's tech level is under its max, develop can increase it. */
 
+/*! \brief Prepare for technical Development Action.
+ *
+ * Setup a Develop action.
+ * In order to build a specific unit type, a side may first have to develop
+ * the tech level needed for that unit. This is achieved by the develop action.
+ * \note Technical development is different from advances and advanced
+ * units.
+ * \see do_devop_action, do_check_action.
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param developer is the pointer to the \Unit doing the development.
+ * \param new_u is the new Unit type being developed.
+ * \return 
+ *   - TRUE action is queed.
+ *   - FALSE if 
+ *     - unit is null pointer,
+ *     - unit action is a null pointer, or
+ *     - developer is null pointer.
+ */
 int
-prep_develop_action(Unit *unit, Unit *unit2, int u3)
+prep_develop_action(Unit *unit, Unit *developer, int new_u)
 {
-    if (unit == NULL || unit->act == NULL || unit2 == NULL)
-      return FALSE;
+    if (unit == NULL || unit->act == NULL || developer == NULL) {
+       return FALSE;
+    }
     unit->act->nextaction.type = ACTION_DEVELOP;
-    unit->act->nextaction.args[0] = u3;
-    unit->act->nextaction.actee = unit2->id;
+    unit->act->nextaction.args[0] = new_u;
+    unit->act->nextaction.actee = developer->id;
     return TRUE;
 }
 
+/*! \brief Do Technical Development Action.
+ *
+ * Develop the tech level needed for building \new_u, if not already available.
+ * -# calculate contribution to tech by the developer \Unit.  Use the value
+ *    of uu_tech_per_develop divided by 100, plus a random value of zero or
+ *    one.
+ * -# Caclulate limit on tech change for the side
+ * -# If tech change exceeds limit, reset to limit
+ * -# If tech level changes,
+ *   - notify side of tech change.
+ *   - update vector of buildable Units.
+ * -# Adjust the tech levels of related Units
+ * -# Uuse up the ACP of the \Unit.
+ *
+ * \note Technical development is different from advances and advanced
+ * units.
+ *
+ * \see prep_develop_action, prob_fraction, uu_tech_per_develop,
+ *      u_tech_per_turn_max, update_canbuild_vector, adjust_tech_crossover,
+ *      use_up_acp, uu_acp_to_develop.
+ *
+ * \GDL
+ *    - <a href="xcdesign_241.html#GDL_ref_acp-to-develop">acp-to-develop</a>
+ *    - <a href="xcdesign_157.html#GDL_ref_init-tech">init-tech</a>
+ *    - <a href="xcdesign_157.html#GDL_ref_tech">tech</a>
+ *    - <a href="xcdesign_241.html#GDL_ref_tech-per-develop">tech-per-develop</a>
+ *    - <a href="xcdesign_241.html#GDL_ref_tech-per-turn-max">tech-per-turn-max</a>
+ *    - <a href="xcdesign_182.html#GDL_ref_unit-type">unit-type</a>
+ *
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param developer is the pointer to the \Unit acted upon.
+ * \param new_u is the Unit type of the increasing tech Unit.
+ * \return A_ANY_DONE.
+ */
 int
-do_develop_action(Unit *unit, Unit *unit2, int u3)
+do_develop_action(Unit *unit, Unit *developer, int new_u)
 {
-    int u2 = unit2->type, oldtech, lim;
-    Side *side = unit2->side;
-
-    oldtech = side->tech[u3];
-    side->tech[u3] += prob_fraction(uu_tech_per_develop(u2, u3));
+    int oldtech;       /* Side's starting tech level */
+    int lim;           /* limit on tech development */
+    Side *side;        /* Developer's side */
+
+    side = developer->side;
+    /* Save the initial tech level */
+    oldtech = side->tech[new_u];
+    side->tech[new_u] += prob_fraction(uu_tech_per_develop(developer->type, new_u));
     /* Silently apply the per-side-per-turn limit on tech gains. */
-    lim =  side->inittech[u3] + u_tech_per_turn_max(u3);
-    if (side->tech[u3] > lim)
-      side->tech[u3] = lim;
-    if (side->tech[u3] != oldtech) {
+    lim =  side->inittech[new_u] + u_tech_per_turn_max(new_u);
+    if (side->tech[new_u] > lim) {
+       side->tech[new_u] = lim;
+    }
+    if (side->tech[new_u] != oldtech) {
        /* (should do generic side display update?) */
-       notify_tech(side, u3, oldtech, side->tech[u3]);
+       notify_tech(side, new_u, oldtech, side->tech[new_u]);
        /* Update info for side_can_build. */
        update_canbuild_vector(side);
     }
     /* Adjust the tech levels of any related unit types. */
-    adjust_tech_crossover(side, u3);
-    use_up_acp(unit, uu_acp_to_develop(u2, u3));
+    adjust_tech_crossover(side, new_u);
+    use_up_acp(unit, uu_acp_to_develop(developer->type, new_u));
     return A_ANY_DONE;
 }
 
+/*! \brief Check for Technical Development Action.
+ *
+ * Check to see is tech development action is possible.  Tech development is
+ * on a unit basis, as opposed to advances, which may depend on each other.
+ * \note Technical development is different from advances and advanced
+ * units.
+ * <P>
+ * - Validate \Units acted on.
+ *   - unit must be in play,
+ *   - developer must be in play, and
+ *   - newunt must be a Unit type.
+ * - Check to see if the side is an independent side, and independents are 
+ *    allowed to develop.
+ * - the developer must be able to develop the new unit type
+ * - unit must be able to have enough acp for the developer to develop the 
+ *    new unit type
+ * - the side's tech level must not be at the side's maximum value already
+ * - the unit must have enough acp for the developer to develop the new unit
+ *    type
+ * - the developer must have all materials needed to develop the new unit type
+ *
+ * \see prep_develop_action, do_develop_action, in_play, is_unit_type,
+ *      g_indepside_can_develop, could_develop, can_have_enough_acp,
+ *      uu_acp_to_develop, u_tech_max, for_all_material_types.
+ *
+ * \GDL
+ *    - <a href="xcdesign_241.html#GDL_ref_acp-to-develop">acp-to-develop</a>
+ *    - <a href="xcdesign_157.html#GDL_ref_init-tech">init-tech</a>
+ *    - <a href="xcdesign_157.html#GDL_ref_tech">tech</a>
+ *    - <a href="xcdesign_182.html#GDL_ref_unit-type">unit-type</a>
+ *
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param developer is the pointer to the \Unit which does the development
+ * \param new_u is the new Unit type to be developed.
+ * \return
+ *   - A_ANY_ERROR if
+ *     - unit is not in play,
+ *     - developer is not in play,
+ *     - new_u in not a valid Unit type,
+ *     - the side is independent, and not allowed technical development, or
+ *     - the side has reached it's maximum tech level.
+ *   - A_ANY_CANNOT_DO if
+ *      - the developer cannot develop the new unit type, or
+ *      - the unit can never have enough ACP to develop the new Unit type.
+ *   - A_ANY_NO_ACP if the unit does not currently have enough acp to develop  
+ *     the new unit type.
+ *   - A_ANY_OK if the do_develop_action can be done.
+ */
 int
-check_develop_action(Unit *unit, Unit *unit2, int u3)
+check_develop_action(Unit *unit, Unit *developer, int new_u)
 {
-    int u, u2, m;
-    Side *side;
+    int m;             /* material type */
+    Side *side;        /* unit's side */
 
-    if (!in_play(unit))
+    if (!in_play(unit)) {
       return A_ANY_ERROR;
-    if (!in_play(unit2))
+    }
+    if (!in_play(developer)) {
       return A_ANY_ERROR;
-    if (!is_unit_type(u3))
+    }
+    if (!is_unit_type(new_u)) {
       return A_ANY_ERROR;
-    u = unit->type;  u2 = unit2->type;
+    }
     side = unit->side;
     /* Independent units might not do develop. */
-    if (side == indepside && g_indepside_can_develop() == FALSE)
+    if (side == indepside && g_indepside_can_develop() == FALSE) {
       return A_ANY_ERROR;
+    }
     /* This unit must be of a type that can develop the given type. */
-    if (uu_acp_to_develop(u2, u3) < 1)
+    if (!could_develop(developer->type, new_u)) {
       return A_ANY_CANNOT_DO;
-    if (!can_have_enough_acp(unit, uu_acp_to_develop(u2, u3)))
+    }
+    if (!can_have_enough_acp(unit, uu_acp_to_develop(developer->type, new_u))) {
       return A_ANY_CANNOT_DO;
+    }
     /* Max tech level means there's nothing more to learn. */
-    if (side->tech[u3] >= u_tech_max(u3))
+    if (side->tech[new_u] >= u_tech_max(new_u)) {
       return A_ANY_ERROR;
-    if (!has_enough_acp(unit, uu_acp_to_develop(u2, u3)))
+    }
+    if (!has_enough_acp(unit, uu_acp_to_develop(developer->type, new_u))) {
       return A_ANY_NO_ACP;
+    }
     /* Check that the unit has any required supplies. */
     for_all_material_types(m) {
-       if (unit2->supply[m] < um_to_develop(u2, m))
+       if (developer->supply[m] < um_to_develop(developer->type, m)) {
          return A_ANY_NO_MATERIAL;
+       }
     }
     return A_ANY_OK;
 }
 
-/* For all unit types, bring their tech level up to match the crossovers
-   from the given unit type. */
-
+/*!
+ * \brief Adjuxt for Tchnical Development Crossover.
+ *
+ * For all Unit types, bring their tech level up to match the crossovers
+ * from the given Unit type.
+ * - for all Unit types ( for all sides, presumably? )
+ *   - if the Unit type isn't the Unit type being developed
+ *     - calculate the crosstech value
+ *     - if the crosstech value increaes the tech level of the other \Unit
+ *       - change the tech level of the other \Unit.
+ *     - if the other uunit's tech level increases
+ *       - notify the \Side of a tech increase for the Unit.
+ *       - update the can build vector for the side.
+ *
+ * \see do_develop_action, for_all_unit_types, uu_tech_crossover, u_tech_max,
+ *      notify_tech, update_canbuild_vector.
+ *
+ *  \GDL
+ *    - <a href="xcdesign_157.html#GDL_ref_tech">tech</a>
+ *    - <a href="xcdesign_190.html#GDL_ref_tech-crossover">tech-crossover</a>
+ *    - <a href="xcdesign_190.html#GDL_ref_tech-max">tech-max</a>
+ *
+ * \param side is the pointer to \Side with the technical development.
+ * \param new_u is the new Unit type being developed.
+ */
 void
-adjust_tech_crossover(Side *side, int u)
+adjust_tech_crossover(Side *side, int new_u)
 {
-    int u2, oldtech, crosstech;
+    int other_u;       /* other unit type (iteration variable) */
+    int oldtech;        /* initial tech level of the other unit */
+    int crosstech;     /* crossover technical development of unit */
 
-    for_all_unit_types(u2) {
-       if (u2 != u) {
-           oldtech = side->tech[u2];
+    for_all_unit_types(other_u) {
+       if (other_u != new_u) {
+           oldtech = side->tech[other_u];
            /* Compute the crossover as a ratio of max tech levels for
                each type. */
            crosstech =
-             ((side->tech[u] * uu_tech_crossover(u, u2) * u_tech_max(u2)) /
-              (u_tech_max(u) * 100));
-           if (crosstech > side->tech[u2])
-             side->tech[u2] = crosstech;
-           if (side->tech[u2] != oldtech) {
+             ((side->tech[new_u] * uu_tech_crossover(new_u, other_u) * u_tech_max(other_u)) /
+              (u_tech_max(new_u) * 100));
+           if (crosstech > side->tech[other_u]) {
+               side->tech[other_u] = crosstech;
+           }
+           if (side->tech[other_u] != oldtech) {
                /* (should do generic side display update?) */
-               notify_tech(side, u2, oldtech, side->tech[u2]);
+               notify_tech(side, other_u, oldtech, side->tech[other_u]);
                /* Update info for side_can_build. */
                update_canbuild_vector(side);
            }
@@ -490,9 +2154,30 @@ adjust_tech_crossover(Side *side, int u)
     }
 }
 
-/* Notify the given side of any notable changes in technological
-   ability. */
-/* (to nlang.c?) */
+/*! \brief Notify of Technical Advance.
+ *
+ * Notify the given side of any notable changes in technological
+ * ability.
+ * For the given Unit, chck and notify the \Side if technology development allows
+ * the side to see a new Unit type, own a new Unit type, use a new Unit type, or
+ * build a new Unit type.
+ *
+ * \todo move to nlang.c?
+ *
+ * \see do_develop_action, adjust_tech_crossover, u_tech_to_see, u_tech_to_own,
+ *      u_tech_to_use, u_tech_to_build, notify.
+ *
+ * \GDL
+ *    - <a href="xcdesign_190.html#GDL_ref_tech-to-build">tech-to-build</a>
+ *    - <a href="xcdesign.html#GDL_ref_tech-to_own">tech-to_own</a>
+ *    - <a href="xcdesign_190.html#GDL_ref_tech-to-see">tech-to-see</a>
+ *    - <a href="xcdesign_190.html#GDL_ref_tech-to-use">tech-to-use</a>
+ *
+ * \param side is the pointer to the \Side owning the Unit.
+ * \param u is the Unit type.
+ * \param oldtech is the old technical level for the Unit.
+ * \param newtech is the new technical level for the Unit.
+ */
 void
 notify_tech(Side *side, int u, int oldtech, int newtech)
 {
@@ -516,299 +2201,537 @@ notify_tech(Side *side, int u, int oldtech, int newtech)
        notify(side, "You now have the technology to build new %s units",
               u_type_name(u));
     }
+    if ((oldtech < u_tech_to_change_type_to(u))
+       && (newtech >= u_tech_to_change_type_to(u))) {
+       notify(side, "You now have the technology to change type to %s units",
+              u_type_name(u));
+    }
 }
 
 /* Toolup action. */
 
-/* Before a unit can build another, it may need to take some time to
-   prepare by "tooling up". */
+/*! \brief Prepare for Toolup Action.
+ *
+ * Before a \Unit can build another, it may need to take some time to
+ * prepare by "tooling up". This is to simulate the amount of time
+ * it takes to build the first of a Unit.
+ * \see do_toolup_action, check_toolup_action.
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param constructor is a pointer to the \Unit which builds the new Unit.
+ * \param u3 is the type of Unit being built.
+ * \return
+ *   - TRUE if action is successfully queued.
+ */
 
 int
-prep_toolup_action(Unit *unit, Unit *unit2, int u3)
+prep_toolup_action(Unit *actor, Unit *constructor, int u3)
 {
-    if (unit == NULL || unit->act == NULL || unit2 == NULL)
-      return FALSE;
-    unit->act->nextaction.type = ACTION_TOOL_UP;
-    unit->act->nextaction.args[0] = u3;
-    unit->act->nextaction.actee = unit2->id;
+    assert_error(is_active(actor),
+                "Toolup Prep: Attempted to access an inactive actor");
+    assert_error(is_active(constructor),
+                "Toolup Prep: Attempted to access an inactive constructor");
+    assert_error(is_unit_type(u3),
+                "Toolup Prep: Encountered an invalid unit type to toolup for");
+    actor->act->nextaction.type = ACTION_TOOL_UP;
+    actor->act->nextaction.args[0] = u3;
+    actor->act->nextaction.actee = constructor->id;
     return TRUE;
 }
 
+/*! \brief Do Toolup Action.
+ *
+ * Do the tooup action.
+ * - If builder tooling pointer is NULL, initialize tooling for it.
+ * - Get current tooling points (tp), add in the builder \Unit tooling points,
+ *    and clip to the max tooling points for creating the new Unit type.
+ * - If the number of tooling points changes (can go negative?), 
+ *    notify the side.
+ * - Adjust the tooling on all other Units, via a crossover array.
+ * - update Unit display for the side.
+ * - use up ACP for the unit \Unit
+ *
+ * \see prep_toolup_action, check_tooup_action, init_unit_tooling,
+ *      uu_tp_per_toolup, uu_tp_max, notify_tp, adjust_tooling_crossover,
+ *      update_unit_display, use_up_acp, uu_acp_to_toolup.
+ *
+ * \param actor is the pointer to the \Unit initiating the action.
+ * \param constructor is pointer to the \Unit which is building the New unit.
+ * \param u3 is the Unit type for which to tool up.
+ * \return A_ANY_DONE always.
+ */
+
 int
-do_toolup_action(Unit *unit, Unit *unit2, int u3)
+do_toolup_action(Unit *actor, Unit *constructor, int u3)
 {
-    int oldtp, tp;
-
-    if (unit2->tooling == NULL)
-      init_unit_tooling(unit2);
-    /* Increase the tooling, clipping to its max. */
-    oldtp = tp = unit2->tooling[u3];
-    tp += uu_tp_per_toolup(unit2->type, u3);
-    tp = min(tp, uu_tp_max(unit2->type, u3));
-    unit2->tooling[u3] = tp;
-    if (unit2->tooling[u3] != oldtp) {
-       notify_tp(unit->side, unit2, u3, oldtp, unit2->tooling[u3]);
-    }
-    /* Adjust any related toolings. */
-    adjust_tooling_crossover(unit2, u3);
-    update_unit_display(unit->side, unit2, TRUE);
-    /* Consume acp. */
-    use_up_acp(unit, uu_acp_to_toolup(unit2->type, u3));
+    int oldtp = -1, tp = -1;
+    Side *side = NULL;
+    int u2 = NONUTYPE;
+
+    assert_error(is_active(actor),
+                "Create Action: Attempted to manipulate an inactive actor");
+    assert_error(is_active(constructor),
+"Create Action: Attempted to manipulate an inactive constructor");
+    assert_error(is_unit_type(u3),
+                "Create Action: Encountered an invalid unit type");
+    u2 = constructor->type;
+    side = actor->side;
+    // Initialize the constructor's tooling array, if necessary.
+    if (!constructor->tooling) 
+       init_unit_tooling(constructor);
+    // Increase the tooling, clipping to its max. 
+    oldtp = tp = constructor->tooling[u3];
+    tp = min(tp + uu_tp_per_toolup(u2, u3), uu_tp_max(u2, u3));
+    constructor->tooling[u3] = tp;
+    if (constructor->tooling[u3] != oldtp) 
+       notify_tp(side, constructor, u3, oldtp, constructor->tooling[u3]);
+    // Adjust any related toolings.
+    adjust_tooling_crossover(constructor, u3);
+    update_unit_display(side, constructor, TRUE);
+    // Consume resources for this toolup.
+    consume_materials(actor, constructor, um_consumption_per_tooledup, u3);
+    consume_materials(actor, constructor, um_consumption_per_toolup);
+    use_up_acp(actor, uu_acp_to_toolup(u2, u3));
     return A_ANY_DONE;
 }
 
+/*! \brief Check Toolup Action.
+ *
+ * Check to see if a toolup action may be performed.
+ *
+ * \see prep_toolup_action, do_toolup_action. in_play, is_unit_type,
+ *      uu_acp_to_toolup, can_have_enough_acp, uu_tp_max,
+ *      has_enough_acp.
+ *
+ * \param actor is the pointer to the \Unit initiating the action.
+ * \param constructor is pointer to \Unit which will do the tool up for the
+ *        new unit.
+ * \param u3 is the type of Unit for which to toolup.
+ * \return
+ *    - A_ANY_ERROR if
+ *      - unit is not in play,
+ *      - builder is not in play,
+ *      - new_u is not a Unit type, or
+ *      - tooling points equal or exceed the number needed to toolup for the
+ *        new Unit type.
+ *    - A_ANY_CANNOT_DO if
+ *      - the builder \Unit cannot toolup for the required Unit type 
+ *        (acp less than 1), or
+ *      - the unit \Unit can never have enough acp to produce the Unit type.
+ *    - A_ANY_NO_ACP if the unit \Unit doesn't have enough acp to toolup this turn.
+ *    - A_ANY_OK if the toolup is possible.
+ */
+
 int
-check_toolup_action(Unit *unit, Unit *unit2, int u3)
+check_toolup_action(Unit *actor, Unit *constructor, int u3)
 {
-    int acp, tp;
+    int rslt = A_ANY_OK;
 
-    if (!in_play(unit))
-      return A_ANY_ERROR;
-    if (!in_play(unit2))
-      return A_ANY_ERROR;
-    if (!is_unit_type(u3))
-      return A_ANY_ERROR;
-    acp = uu_acp_to_toolup(unit2->type, u3);
-    if (acp < 1)
-      return A_ANY_CANNOT_DO;
-    if (!can_have_enough_acp(unit, acp))
-      return A_ANY_CANNOT_DO;
-    tp = (unit2->tooling ? unit2->tooling[u3] : 0);
-    /* Check if tooling is already at its max. */
-    if (tp >= uu_tp_max(unit2->type, u3))
-      return A_ANY_ERROR;
-    if (!has_enough_acp(unit, acp))
-      return A_ANY_NO_ACP;
+    if (!valid(rslt = can_toolup_for(actor, constructor, u3)))
+       return rslt;
     return A_ANY_OK;
 }
 
-/* For all unit types, bring their tooling levels up to match the crossovers
-   from the given unit type. */
+/*! \brief Adjust Tooling Startup Crossover.
+ *
+ * For all Unit types, adjust any toolup crossover from the Unit toolup.
+ * - If the \Unit tooling pointer is NULL, return
+ * - For all Unit types
+ *   - for each Unit type not the same as the calling Unit's type,
+ *     - calculate crossover toolup points.
+ *     - if crossover value increases,
+ *       - set new toolup point value.
+ *       - notify side of Unit change.
+ *
+ * \see do_toolup_action, for_all_unit_types, uu_tp_crossover, uu_tp_max,
+ *      notify_tp.
+ *
+ * \param unit is a pointer to the \Unit perfroming the toolup
+ * \param u is the type of Unit that was tooled up.
+ */
 
 void
-adjust_tooling_crossover(Unit *unit, int u2)
+adjust_tooling_crossover(Unit *constructor, int u2)
 {
-    int u3, uucross, cross, oldtp3;
-
-    /* Perhaps nothing to cross over with. */
-    if (unit->tooling == NULL)
-      return;
+    int u = NONUTYPE, u3 = NONUTYPE;
+    int uucross = -1, oldtp = -1;
+    short int *tooling = NULL;
+
+    assert_error(is_active(constructor),
+"Toolup Action: Attempted to manipulate an out-of-play constructor");
+    assert_error(is_unit_type(u2),
+                "Toolup Action: Encountered an invalid unit type");
+    u = constructor->type;
+    // Perhaps nothing to cross over with.
+    if (!constructor->tooling) 
+       return;
+    tooling = constructor->tooling;
+    // Look through other utypes and find any to share tooling with.
     for_all_unit_types(u3) {
-       if (u3 != u2) {
-           uucross = uu_tp_crossover(u2, u3);
-           if (uucross > 0) {
-               oldtp3 = unit->tooling[u3];
-               /* Calculate the crossover as a ratio of max levels. */
-               cross = (unit->tooling[u2] * uucross * uu_tp_max(u2, u3)) /
-                       (uu_tp_max(u2, u3) * 100);
-               if (cross > oldtp3)
-                 unit->tooling[u3] = cross;
-               if (unit->tooling[u3] != oldtp3) {
-                   notify_tp(unit->side, unit, u2, oldtp3, unit->tooling[u3]);
-               }
-           }
+       if (u3 == u2)
+           continue;
+       uucross = uu_tp_crossover(u2, u3);
+       // Clobber any toolings which cannot be shared.
+       if (0 >= uucross) {
+           tooling[u3] = 0;
+           continue;
        }
+       oldtp = tooling[u3];
+       // Calculate the crossover as a ratio of max levels.
+       tooling[u3] = (tooling[u2] * uucross * uu_tp_max(u, u3)) 
+                      / (uu_tp_max(u, u2) * 100);
+       if (tooling[u3] != oldtp) 
+           notify_tp(constructor->side, constructor, u3, oldtp, tooling[u3]);
     }
 }
 
-/* Notify the given side/unit of any notable changes in tooling. */
-/* (to nlang.c?) */
+/*! \brief Notify of Tooling Startup Change.
+ *
+ * Notify the given \Side of any notable changes in tooling.
+ * If toolup points moved from not buildable to buildable, notify side.
+ *
+ * \todo move to nlang.c?
+ *
+ * \see do_toolup_action, adjust_toolup_crossover, notify.
+ *
+ *  \GDL
+ *    - <a href="xcdesign_242.html#GDL_ref_tp-to-build"></a>
+ *    - <a href="xcdesign_182.html#GDL_ref_unit-type">unit-type</a>
+ *
+ * \param side is a pointer to the \Side.
+ * \param unit is a pointer to the \Unit.
+ * \param u is the type of the Unit.
+ * \param oldtp is the old toolup points.
+ * \param newtp is the new toolup points.
+ * 
+ */
 void
-notify_tp(Side *side, Unit *unit, int u2, int oldtp, int newtp)
+notify_tp(Side *side, Unit *unit, int u, int oldtp, int newtp)
 {
-    if (oldtp < uu_tp_to_build(unit->type, u2)
-       && newtp >= uu_tp_to_build(unit->type, u2)) {
+    if (oldtp < uu_tp_to_build(unit->type, u)
+       && newtp >= uu_tp_to_build(unit->type, u)) {
        notify(side, "%s is now tooled to build %s units",
-              unit_handle(side, unit), u_type_name(u2));
+              unit_handle(side, unit), u_type_name(u));
     }
 }
 
-/* Create-in action. */
-
-/* This action creates the (incomplete) unit. */
+//! Consume materials needed by a build or create-as-build action.
 
-int
-prep_create_in_action(Unit *unit, Unit *unit2, int u3, Unit *dest)
+static void
+consume_materials_for_build(Unit *actor, Unit *constructor, int u3, int cp)
 {
-    if (unit == NULL || unit->act == NULL || unit2 == NULL || dest == NULL)
-      return FALSE;
-    unit->act->nextaction.type = ACTION_CREATE_IN;
-    unit->act->nextaction.args[0] = u3;
-    unit->act->nextaction.args[1] = dest->id;
-    unit->act->nextaction.actee = unit2->id;
-    return TRUE;
+    assert_error(is_active(actor),
+                "Construct Action: Attempted to access an inactive actor");
+    assert_error(is_active(constructor),
+"Construct Action: Attempted to access an inactive constructor");
+    assert_error(is_unit_type(u3),
+"Construct Action: Encountered an invalid unit type to construct");
+    consume_materials(actor, constructor, um_consumption_per_cp, u3, cp);
+    consume_materials(actor, constructor, um_consumption_per_built, u3);
+    consume_materials(actor, constructor, um_consumption_per_build);
 }
 
-int
-do_create_in_action(Unit *unit, Unit *unit2, int u3, Unit *dest)
+static void
+do_create_action_common_1(Unit *actor, Unit *creator, Unit *creation)
 {
-    int u2 = unit2->type, m, consum, consum2;
-    Unit *newunit;
-
-    if (u_advanced(u3)) {
-       Unit *oldunit = unit_at(unit2->x, unit2->y);
-       if (oldunit->type == u3) {
-           /* (should test that this kind of joining is allowed) */
-           oldunit->size += 1;
-           update_unit_display(oldunit->side, oldunit, TRUE);
-           garrison_unit(unit2, oldunit);
-           use_up_acp(unit, uu_acp_to_create(u2, u3));
-           return A_ANY_DONE;
-       }
+    int u2 = NONUTYPE, u3 = NONUTYPE;
+    int cab = FALSE;
+    int cp = -1;
+
+    assert_error(is_active(actor),
+                "Create Action: Attempted to manipulate inactive actor");
+    assert_error(is_active(creator),
+                "Create Action: Attempted to manipulate inactive creator");
+    assert_error(creation,
+                "Create Action: Attempted to manipulate null creation");
+    u2 = creator->type;
+    u3 = creation->type;
+    cab = uu_create_as_build(u2, u3);
+    cp = min((cab ? uu_cp_per_build(u2, u3) : uu_creation_cp(u2, u3)),
+            u_cp(u3));
+    // Consume resources for this create.
+    if (cab) {
+       consume_materials_for_build(actor, creator, u3, cp);
+       use_up_acp(actor, uu_acp_to_build(u2, u3));
     }
-    /* Make the new unit. */
-    newunit = create_unit(u3, FALSE);
-    if (newunit != NULL) {
-       /* Fill in various properties. */
-       set_created_unit_props(newunit, u2, unit->side, unit2->morale);
-       /* Transfer the builders stash of cps to newunit if permitted. */
-       if (uu_builder_can_reuse_cp(u2, u3)) {
-           newunit->cp += min(unit2->cp_stash, u_cp(u3) - newunit->cp);
-           unit2->cp_stash -= min(unit2->cp_stash, u_cp(u3) - newunit->cp);
-       }
-       /* Put the new unit inside the designated transport. */
-       enter_transport(newunit, dest);
-       /* Unit might have started out complete. */
-       if (completed(newunit)) {
-           garrison_unit(unit2, newunit);
-           make_unit_complete(newunit);
-       } else {
-           record_event(H_UNIT_CREATED, add_side_to_set(unit2->side, NOSIDES),
-                        side_number(unit2->side), newunit->id);
-       }
-       if (alive(unit2)) {
-           count_gain(unit2->side, newunit->type, build_gain);
-           /* Consume the creator's supplies as specified. */
-           for_all_material_types(m) {
-               consum = um_consumption_on_creation(u3, m);
-               consum2 = 0;
-               if (consum > unit2->supply[m]) {
-                   consum2 = consum - unit2->supply[m];
-                   consum = unit2->supply[m];
-               }
-               unit2->supply[m] -= consum;
-               
-               /* Use material from treasury if necessary. */
-               if (consum2 > 0) {
-                       if (side_has_treasury(unit2->side, m)
-                           && um_takes_from_treasury(unit2->type, m)) {  
-                                 unit2->side->treasury[m] -= consum2;      
-                       } else {
-                               /* Should never happen. */
-                               run_warning("Unit created even though material was insufficient"); 
-                       }
-                }
-           }
-       }
-       use_up_acp(unit, uu_acp_to_create(u2, u3));
-       return A_ANY_DONE;
-    } else {
-       /* We've hit a max number of units, nothing to be done. */
-       return A_ANY_ERROR;
+    else {
+       consume_materials(actor, creator, um_consumption_per_cp, u3, cp);
+       consume_materials(actor, creator, um_consumption_on_creation, u3);
+       consume_materials(actor, creator, um_consumption_per_create);
+       use_up_acp(actor, uu_acp_to_create(u2, u3));
+    }
+    // Fill in various properties.
+    set_created_unit_props(creation, creator, actor->side);
+    // Give the creator a handle to the new unit. 
+    creator->creation_id = creation->id;
+    // Transfer the creator's stash of CPs to newunit if permitted. 
+    if (uu_builder_can_reuse_cp(creator->type, u3)) {
+       creation->cp += min(creator->cp_stash, u_cp(u3) - creation->cp);
+       creator->cp_stash -= 
+           min(creator->cp_stash, u_cp(u3) - creation->cp);
     }
 }
 
-int
-check_create_in_action(Unit *unit, Unit *unit2, int u3, Unit *dest)
+static void
+do_create_action_common_2(Unit *actor, Unit *creator, Unit *creation)
 {
-    int rslt;
-
-    if (!in_play(dest))
-      return A_ANY_ERROR;
-    rslt = check_create_common(unit, unit2, u3, dest->x, dest->y);
-    if (rslt != A_ANY_OK)
-      return rslt;
-    if (u_advanced(u3)) {
-       Unit *oldunit = unit_at(unit2->x, unit2->y);
-       if (oldunit->type == u3)
-         return A_ANY_OK;
+    int u3 = NONUTYPE;
+
+    assert_error(actor,
+                "Create Action: Attempted to manipulate NULL actor");
+    assert_error(creator,
+                "Create Action: Attempted to manipulate NULL creator");
+    assert_error(in_play(creation),
+                "Create Action: Attempted to manipulate out-of-play creation");
+    u3 = creation->type;
+    // Unit might have started out complete. 
+    if (completed(creation)) {
+       if (uu_constructor_absorbed_by(creator->type, u3))
+           garrison_unit(creator, creation);
+       make_unit_complete(creation);
     }
-    if (!type_can_occupy(u3, dest))
-      return A_ANY_ERROR;
-    return A_ANY_OK;
+    else 
+       record_event(H_UNIT_CREATED, 
+                    add_side_to_set(actor->side, NOSIDES),
+                    side_number(actor->side), creation->id);
+    // Add creation to actor's side's tally of units.
+    if (alive(actor))
+       count_gain(actor->side, u3, build_gain);
 }
 
-/* Test for the constraints common to create-in and create-at. */
+/* Create-in action. */
 
-static int
-check_create_common(Unit *unit, Unit *unit2, int u3, int x, int y)
+/*! \brief Prepare for Create In Unit Action.
+ *
+ * This action creates the (incomplete) unit.
+ * \see do_create_in_action, check_create_in_action.
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param creator is the pointer to the \Unit which creates the new Unit.
+ * \param new_u the the type of \Unit to create.
+ * \param dest is the pointer to the \Unit in which to create the new Unit.
+ * \return 
+ *   - TRUE if action is queued.
+ *   - FALSE if
+ *     - the unit pointer is NULL,
+ *     - the unit action pointer is NULL,
+ *     - the creator pointer is NULL, or
+ *     - the dest pointer is NULL.
+ */
+int
+prep_create_in_action(Unit *unit, Unit *creator, int new_u, Unit *dest)
 {
-    int u, u2, m, tp, totsup;
+    if (unit == NULL || unit->act == NULL || creator == NULL || dest == NULL) {
+       return FALSE;
+    }
+    unit->act->nextaction.type = ACTION_CREATE_IN;
+    unit->act->nextaction.args[0] = new_u;
+    unit->act->nextaction.args[1] = dest->id;
+    unit->act->nextaction.actee = creator->id;
+    return TRUE;
+}
 
-    if (!in_play(unit))
-      return A_ANY_ERROR;
-    if (!in_play(unit2))
-      return A_ANY_ERROR;
-    if (!is_unit_type(u3))
-      return A_ANY_ERROR;
-    u = unit->type;  u2 = unit2->type;
-    if (uu_acp_to_create(u2, u3) < 1)
-      return A_ANY_CANNOT_DO;
-    if (!can_have_enough_acp(unit, uu_acp_to_create(u2, u3)))
-      return A_ANY_CANNOT_DO;
-    /* Check if type is allowed and if needed tech & advances exist. */
-    if (!side_can_build(unit->side, u3))
-      return A_ANY_CANNOT_DO;
-    /* Check if we hit a limit on the number of units. */
-    if (!new_unit_allowed_on_side(u3, unit->side))
-      return A_ANY_CANNOT_DO;
-    /* Check the tooling. */
-    tp = (unit2->tooling ? unit2->tooling[u3] : 0);
-    if (tp < uu_tp_to_build(u2, u3))
-      return A_ANY_ERROR;
-    if (distance(unit2->x, unit2->y, x, y) > uu_create_range(u2, u3))
-      return A_ANY_TOO_FAR;
-    if (unit2->transport != NULL
-        && !uu_occ_can_build(unit2->transport->type, u2))
-      return A_ANY_ERROR;
-    for_all_material_types(m) {
-       totsup = unit2->supply[m];
-       /* Add material in treasury if available to this unit. */
-       if (side_has_treasury(unit2->side, m)
-           && um_takes_from_treasury(unit2->type, m)) {
-             totsup += unit2->side->treasury[m]; 
-       }
-       if (totsup < um_to_create(u3, m))
-         return A_ANY_NO_MATERIAL;
-       if (totsup < um_consumption_on_creation(u3, m))
-         return A_ANY_NO_MATERIAL;
+/*! \brief Do Create In Unit Action.
+ *
+ * This action creates a \Unit "in" another Unit.
+ * - If the Unit being created is advanced
+ *   - Figure out if the destination unit is the creator's transport
+ *   - If the destination unit is the creator's transport
+ *     - increment destination unit's size by 1.
+ *     - garrison (destroy) the creator
+ *     - update the Unit display
+ *     - use up ACPs
+ *     - return
+ * - (If we fell through above code) create the new \Unit.
+ * - If the pointer to the new \Unit is not NULL
+ *    - Fill in new \Unit properties.
+ *    - if creation points can be passed to the new \Unit
+ *      - stuff new \Unit with as much as it can hold or is avalible,
+ *      - move balances to the correct places.
+ *    - Put the new \Unit in the transport (dest)
+ *    - If \Unit created complete
+ *      - garrison \Unit in transport
+ *      - make \Unit complete
+ *    - Else
+ *      - record the creation event.
+ *    - If creator is alive
+ *      - count the gain in \Units (scorekeeping?)
+ *      - for all materials (supplies)
+ *        - calculate the amount of material consumed in createing new \Unit
+ *        - if consumption greater than supply
+ *          - figure out amount lacking
+ *          - reduce supply by amount consumed
+ *          - if lacking supply from unit2
+ *            - remove need amount from treasury.
+ *          - if not in treasury
+ *            - generate run time warning (but still return good status).
+ *    - use ACP needed to create new \Unit.
+ *    - return
+ * - else return error (no memory for new \Unit?)
+ *
+ * \todo Add crosscheck to make sure that an advanced unit
+ *       does not exceed it's maximum size.
+ *
+ * \see prep_create_in_action, check_create_in_action, u_advanced,
+ *      update_unit_display, garrison_unit, use_up_acp, create_unit,
+ *      set_created_unit_props, uu_builder_can_reuse_cp, enter_transport,
+ *      make_unit_complete, completed, record_event, add_sid_to_set, alive,
+ *      count_gain, for_all_material_types, um_consumption_on_creation
+ *      side_has_treasury, um_takes_from_treasury, run_warning, 
+ *      use_up_acp, uu_acp_to_create.
+ *
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param creator is pointer to \Unit performing the creation.
+ * \param new_u is the new Unit type.
+ * \param dest is the \Unit to create the new Unit in.
+ * \return
+ *   - A_ANY_ERROR if the new \Unit could not be created.
+ *   - A_ANY_DONE otherwise.
+ */
+
+int
+do_create_in_action(Unit *actor, Unit *creator, int u3, Unit *transport)
+{
+    Unit *creation = NULL;
+    int u2 = NONUTYPE;
+
+    assert_error(is_active(actor),
+                "Create Action: Attempted to manipulate inactive actor");
+    assert_error(is_active(creator),
+                "Create Action: Attempted to manipulate inactive creator");
+    assert_error(in_play(transport),
+"Create Action: Attempted to manipulate out-of-play transport");
+    // Useful info.
+    u2 = creator->type;
+    // Special Case.
+    // Merge "creator" into its transport to increase transport's size.
+    // Transport must be advanced unit.
+    if (u_advanced(u3)
+       && creator->transport && (creator->transport == transport)
+       && (transport->type == u3)) {
+       // TODO: Should test whether this kidn of joining is allowed.
+       // TODO: Be more flexible with how much size is added.
+       transport->size += 1;
+       update_unit_display(transport->side, transport, TRUE);
+       garrison_unit(creator, transport);
+       use_up_acp(actor, uu_acp_to_create(u2, u3));
+       return A_ANY_DONE;
     }
-    if (!has_enough_acp(unit, uu_acp_to_create(u2, u3)))
-      return A_ANY_NO_ACP;
-    /* (should check that overall unit count limits not hit yet) */
+    // Create the new unit.
+    creation = create_unit(u3, FALSE);
+    // If creation succeeded...
+    if (creation) {
+       do_create_action_common_1(actor, creator, creation);
+       // Put the new unit inside the designated transport.
+       enter_transport(creation, transport);
+       do_create_action_common_2(actor, creator, creation);
+       return A_ANY_DONE;
+    }
+    // Else, we failed to create the unit.
+    // Perhaps we have reached the side limit on units?
+    else 
+       return A_ANY_ERROR;
+}
+
+/*! \brief Check for Create in Unit Action
+ *
+ * Check to see if it's possible to create a \Unit in another Unit.
+ *
+ * \see prep_create_in_action, do_create_in_action, in_play, 
+ *      u_advanced, unit_at, type_can_occupy.
+ *
+ * \return
+ *   - the return value from can_create_common, if it is not
+ *     A_ANY_OK;
+ *   - A_ANY_ERROR if
+ *     - destination \Unit is not in play, or
+ *     - the new \Unit cannot be created in the destination Unit;
+ *   - A_ANY_OK otherwise.
+ */
+int
+check_create_in_action(Unit *actor, Unit *creator, int uc, Unit *transport)
+{
+    int rslt = A_ANY_OK;
+
+    // Is transport unit in play?
+    if (!in_play(transport))
+       return A_ANY_ERROR;
+    // If common checks are not passed, then get out.
+    if (!valid(
+           rslt = 
+               can_create_common(
+                   actor, creator, uc, transport->x, transport->y)))
+       return rslt;
+    // Special Feature: Can we add a colonizer to an existing city?
+    if (u_advanced(uc)
+       && creator->transport && (creator->transport == transport)
+       && (transport->type == uc)) 
+       return A_ANY_OK;
+    // Can the new utype fit in the transport?
+    if (!type_can_occupy(uc, transport)) 
+       return A_ANY_ERROR;
     return A_ANY_OK;
 }
 
+/*! \brief Set Created Unit Properties.
+ *
+ * Set the properties of the newly created unit.
+ * Set various values:
+ *   - hp and hp2 to 1,
+ *   - cp to creation cp table value,
+ *   - the pointer to the original \Side,
+ *   - assign a unique unit number
+ *   - set all the initial supplies, and
+ *   - if morale is used, set the morale.
+ *   
+ * \todo Possibly should set the unit's morale from a global
+ *       side morale value if there isn't a specific value
+ *       for the unit.
+ * \see uu_creation_cp, set_unit_origside, assign_unit_number,
+ *      for_all_material_types, max, um_created_supply, min, 
+ *      UM_storage_x, u_morale_max, uu_createion_morale,
+ * \param newunit is a pointer to the new \Unit.
+ * \param creator_u is the unit type of the creating unit.
+ * \param side is the pointer to the creating \Side.
+ * \param creator_mor is the creating unit's morale.
+ */
 static void
-set_created_unit_props(Unit *newunit, int u2, Side *side, int u2mor)
+set_created_unit_props(Unit *newunit, Unit *creator, Side *side)
 {
-    int u3 = newunit->type, m, amt, mfrac, mor;
-
+    int u2 = NONUTYPE, u3 = NONUTYPE;
+    int m = NONMTYPE;
+    int amt;
+    int mfrac;
+    int mor;
+
+    u2 = creator->type;
+    u3 = newunit->type;
     newunit->hp = newunit->hp2 = 1;
-    newunit->cp = uu_creation_cp(u2, u3);
+    newunit->cp = 
+       (uu_create_as_build(u2, u3) ? uu_cp_per_build(u2, u3) 
+                                   : uu_creation_cp(u2, u3)); 
     set_unit_side(newunit, side);
     set_unit_origside(newunit, side);
     /* Always number the unit when first created. */
     assign_unit_number(newunit);
     /* Set all supplies to their just-created levels. */
     for_all_material_types(m) {
-       amt = newunit->supply[m];
-       amt = max(amt, um_created_supply(u3, m));
-       /* Clip to capacity. */
-       amt = min(amt, um_storage_x(u3, m));
-       newunit->supply[m] = amt;
+        amt = newunit->supply[m];
+        amt = max(amt, um_created_supply(newunit->type, m));
+        /* Clip to capacity. */
+        amt = min(amt, um_storage_x(newunit->type, m));
+        newunit->supply[m] = amt;
     }
     /* Set the created unit's morale as a ratio to the creator's morale. */
-    if (u_morale_max(u3) > 0) {
-       if (u_morale_max(u2) > 0) {
-           mfrac = (u2mor * 100) / u_morale_max(u2);
-           mor = (uu_creation_morale(u2, u3) * mfrac) / 100;
-           /* Scale to new unit's morale range. */
-           newunit->morale = (mor * u_morale_max(u3)) / 100;
-       } else {
-           /* (should get from global side morale or some such?) */
-           newunit->morale = u_morale_max(u3);
-       }
+    if (u_morale_max(newunit->type) > 0) {
+        if (u_morale_max(creator->type) > 0) {
+            mfrac = (creator->morale * 100) / u_morale_max(creator->type);
+            mor = (uu_creation_morale(creator->type, newunit->type) * mfrac) 
+                 / 100;
+            /* Scale to new unit's morale range. */
+            newunit->morale = (mor * u_morale_max(newunit->type)) / 100;
+        } else {
+            /* (should get from global side morale or some such?) */
+            newunit->morale = u_morale_max(newunit->type);
+        }
     }
 }
 
@@ -816,220 +2739,402 @@ set_created_unit_props(Unit *newunit, int u2, Side *side, int u2mor)
 
 /* Create a new unit of a given type, out in the open at a given location. */
 
+/*! \brief Prepare for Create Unit at Location.
+ *
+ * Prepare to create a unit in the open at the given location.
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param creator is a pointer to the \Unit creating the new Unit.
+ * \param new_u is the Unit type of the unit being created.
+ * \param x is the cell x co-ordinate.
+ * \param y is the cell y co-ordinate.
+ * \param z is the altitude of the unit.
+ * \return
+ *   - TRUE if action is queued.
+ *   - FALSE if
+ *     - Acting \Unit pointer is NULL, 
+ *     - Acting \Unit action pointer is NULL, or
+ *     - Creating \Unit is NULL;
+ */
 int
-prep_create_at_action(Unit *unit, Unit *unit2, int u3, int x, int y, int z)
+prep_create_at_action(Unit *unit, Unit *creator, int new_u, int x, int y, int z)
 {
-    if (unit == NULL || unit->act == NULL || unit2 == NULL)
-      return FALSE;
+    if (unit == NULL || unit->act == NULL || creator == NULL) {
+       return FALSE;
+    }
     unit->act->nextaction.type = ACTION_CREATE_AT;
-    unit->act->nextaction.args[0] = u3;
+    unit->act->nextaction.args[0] = new_u;
     unit->act->nextaction.args[1] = x;
     unit->act->nextaction.args[2] = y;
     unit->act->nextaction.args[3] = z;
-    unit->act->nextaction.actee = unit2->id;
+    unit->act->nextaction.actee = creator->id;
     return TRUE;
 }
 
+/*! \brief Do Create Unit at Location.
+ *
+ * Create the unit at the given location.
+ * - Try to allocate a new \Unit.
+ * - If allocated, 
+ *    - Set the default properties of the \Unit.
+ *    - If the \Unit can reuse creation points, adjust the new unit's and creator's 
+ *      creation points.
+ *    - If the new unit can occupy the cell
+ *      - enter the cell with the new \Unit.
+ *      .
+ *    - else if there is space in cell and the creating \Unit can transport
+ *      the new unit
+ *      - make the creating \Unit leave the cell
+ *      - make the new \Unit enter the cell
+ *      - make the creator \Unit eter the new unit as an occupant.
+ *      .
+ *    - else there was an error.
+ *    - if the new \Unit is completed on creation
+ *      - destroy creating \Unit, if neccessary.  This is for things
+ *        like creatinn a city from a colonizer that is "used up" in
+ *        the process of creating the new Unit.
+ *      - complete the new \Unit.
+ *      .
+ *    - else record the creation event.
+ *    - if the creating unit is still alive (not destroyed by creating the new unit)
+ *      - record any score gain from creating unit.
+ *      - use supplies for creation (local and/or treasury).
+ *      .
+ *    - use up creation ACP from the unit.
+ *    .
+ *  - else ran out of memory
+ *  .
+ * \see create_unit, set_created_unit_props, uu_builder_can_reuse_cp,
+ *      mn, u_cp, can_occupy_cell, enter_cell, can_occupy_cell_without,
+ *      can_occupy, leave_cell, enter_transport, run_error, completed,
+ *      garrison_unit, make_unit_complete, recod_event, add_side_to_set,
+ *      side_number, alive, count_gain, for_all_material_types,
+ *      um_consumption_on_creation, side_has_treasury, 
+ *      run_warning, use_up_acp.
+ * \param actor is the pointer to the \Unit initiating the action.
+ * \param creator is a pointer to the \Unit doing the creation.
+ * \param u3 is the Unit type to be created.
+ * \param x is the creation location's x co-ordiate.
+ * \param y is the creation location's y co-ordinate.
+ * \param z is the creation location's altitude.
+ * \return 
+ *   - A_ANY_ERROR if no memory for \Unit creation.
+ *   - A_ANY_OK if unit created.
+ */
+
 int
-do_create_at_action(Unit *unit, Unit *unit2, int u3, int x, int y, int z)
+do_create_at_action(Unit *actor, Unit *creator, int u3, int x, int y, int z)
 {
-    int u2 = unit2->type, m, consum, consum2;
-    Unit *newunit;
-
-    /* Make the new unit. */
-    newunit = create_unit(u3, FALSE);
-    if (newunit != NULL) {
-       /* Fill in various properties. */
-       set_created_unit_props(newunit, u2, unit->side, unit2->morale);
-       /* Transfer the builders stash of cps to newunit if permitted. */
-       if (uu_builder_can_reuse_cp(u2, u3)) {
-           newunit->cp += min(unit2->cp_stash, u_cp(u3) - newunit->cp);
-           unit2->cp_stash -= min(unit2->cp_stash, u_cp(u3) - newunit->cp);
-       }
-       /* Put it at a correct location. */
-       if (can_occupy_cell(newunit, x, y)) {
-           enter_cell(newunit, x, y);
-       } else if (can_occupy_cell_without(newunit, x, y, unit2)
-               && can_occupy(unit2, newunit)) {
-           /* Let the builder occupy its incomplete work. */
-           leave_cell(unit2);
-           enter_cell(newunit, x, y);
-           enter_transport(unit2, newunit);
-       } else {
-           /* This should never happen.  If it does, then the preflighting
-              in check_create_at_action has made a mistake. */
-           run_error("construction/occupation complications");
+    int u2 = NONUTYPE;
+    int t = NONTTYPE;
+    Unit *creation = NULL;
+
+    assert_error(is_active(actor),
+                "Create Action: Attempted to manipulate inactive unit");
+    assert_error(is_active(creator),
+                "Create Action: Attempted to manipulate inactive unit");
+    assert_error(is_unit_type(u3),
+                "Create Action: Encountered invalid unit type for new unit");
+    assert_error(inside_area(x, y),
+                "Create Action: Attempted to place new unit outside of world");
+    u2 = creator->type;
+    // TODO: Handle any ZOC violations as appropriate.
+    // Create the new unit.
+    creation = create_unit(u3, FALSE);
+    if (creation) {
+       do_create_action_common_1(actor, creator, creation);
+       // Put the unit where there is room for it. 
+       t = terrain_at(x, y);
+       // If there is room in the cell... 
+       if (type_can_occupy_cell(u3, x, y)
+           && type_survives_in_cell(u3, x, y)) {  
+           enter_cell(creation, x, y);
        }
-       /* (should) set its altitude? */
-       /* Unit might be complete right away. */
-       if (completed(newunit)) {
-           garrison_unit(unit2, newunit);
-           make_unit_complete(newunit);
-       } else {
-           record_event(H_UNIT_CREATED, add_side_to_set(unit2->side, NOSIDES),
-                        side_number(unit2->side), newunit->id);
+       // Else if the creator occupies its construction work...
+       else if (can_occupy_cell_without(creation, x, y, creator)
+                && type_survives_in_cell(u3, x, y) 
+                && can_occupy(creator, creation)) {  
+               leave_cell(creator);
+               enter_cell(creation, x, y);
+               enter_transport(creator, creation);
        }
-       if (alive(unit2)) {
-           count_gain(unit2->side, newunit->type, build_gain);
-           /* Consume the creator's supplies as specified. */
-           for_all_material_types(m) {
-               consum = um_consumption_on_creation(u3, m);
-               consum2 = 0;
-               if (consum > unit2->supply[m]) {
-                   consum2 = consum - unit2->supply[m];
-                   consum = unit2->supply[m];
-               }
-               /* Use material from treasury if necessary. */
-               if (consum2 > 0) {
-                       if (side_has_treasury(unit2->side, m)
-                           && um_takes_from_treasury(unit2->type, m)) {  
-                                 unit2->side->treasury[m] -= consum2;      
-                       } else {
-                               /* Should never happen. */
-                               run_warning("Unit created even though material was insufficient"); 
-                       }
-                }
-           }
+       // Else if the creator is going to die.
+       else if (can_occupy_cell_without(creation, x, y, creator)
+                && type_survives_in_cell(u3, x, y) 
+                && creator_always_dies_on_creation(creator->type, u3)) {  
+               leave_cell(creator);
+               enter_cell(creation, x, y);
        }
-       use_up_acp(unit, uu_acp_to_create(u2, u3));
+       // This should never happen. 
+       //  If it does, then 'check_create_at_action' has made a mistake.
+       else
+           run_error(
+               "Create Action: Tried to place creation where it cannot be");
+       // TODO: Adjust altitude.
+       do_create_action_common_2(actor, creator, creation);
        return A_ANY_DONE;
-    } else {
-       /* We've hit a max number of units, nothing to be done. */
-       return A_ANY_ERROR;
+    }
+    // Else, we failed to create the unit.
+    // Perhaps we have reached the side limit on units?
+    else {
+        return A_ANY_ERROR;
     }
 }
 
+/*! \brief Check for Create Unit at Location.
+ *
+ * Check to see if a \Unit may be created at cell(x,y) at altitude z.
+ * \see inside_area, type_can_occupy_cell,
+ *      type_can_occupy_enpty_type, type_can_occupy_cell_without,
+ *      terrain_at, ut_vanished_on, ut_wrecks_on,
+ *      type_can_sit_on_conn.
+ * \param actor is the pointer to the \Unit initiating the action.
+ * \param creator is thepointer to the \Unit creating the Unit.
+ * \param u3 is the type of Unit being created.
+ * \param x is the location's x co-ordinate.
+ * \param y is the location's y co-ordinate.
+ * \param z is the altitude of the new \Unit.
+ * \return
+ *   - result of can_create_common, if not A_ANY_OK
+ *   - A_ANY_ERROR if
+ *     - the creation location is not in the world,
+ *     - the new Unit can't occupy the desired cell, or the creator can't 
+ *       occupy the new Unit.
+ *     - the Unit vanishes or wrecks in the cell, or can't sit 
+ *       on the connection.
+ *   - A_ANY_OK if it's ok to create the unit.
+ */
+
 int
-check_create_at_action(Unit *unit, Unit *unit2, int u3, int x, int y, int z)
+check_create_at_action(
+    Unit *actor, Unit *creator, int u3, int x, int y, int z)
 {
-    int rslt, t;
-
-    if (!inside_area(x, y))
-      return A_ANY_ERROR;
-    rslt = check_create_common(unit, unit2, u3, x, y);
-    if (rslt != A_ANY_OK)
-      return rslt;
-    /* Check that the desired cell has room for the unit, either by
-       stacking, or by having the builder occupy its construction work. */
-    if (!(type_can_occupy_cell(u3, x, y)
-        || (can_occupy_type(unit2, u3)
-              && type_can_occupy_cell_without(u3, x, y, unit2))))
-      return A_ANY_ERROR;
+    int rslt = A_ANY_OK;
+    int u2 = NONUTYPE;
+    int t = NONTTYPE;
+
+    // If not inside the playing area, then error.
+    if (!inside_area(x, y)) 
+        return A_ANY_ERROR;
+    // TODO: Check altitude.
+    // If common checks are not passed, then error.
+    if (!valid(rslt = can_create_common(actor, creator, u3, x, y)))
+        return rslt;
+    // Useful info.
+    u2 = creator->type;
+    // Check that the desired cell has room for the unit.
     t = terrain_at(x, y);
-    /* Can't build a unit on hostile terrain, unless a connection
-       available for it to sit on. */
-    if ((ut_vanishes_on(u3, t) || ut_wrecks_on(u3, t))
-       && !type_can_sit_on_conn(u3, x, y))
-      return A_ANY_ERROR;
-    return A_ANY_OK;
+    // If there is room in the cell.
+    if (type_can_occupy_cell(u3, x, y)
+       && type_survives_in_cell(u3, x, y)) 
+       return A_ANY_OK;
+    // Else if in same cell, and creator dies or occupies its construction work.
+    if ((x == creator->x) && (y == creator->y)
+       && type_can_occupy_cell_without(u3, x, y, creator)
+       && type_survives_in_cell(u3, x, y)
+       && (type_can_occupy_empty_type(u2, u3)
+           || creator_always_dies_on_creation(u2, u3)))
+       return A_ANY_OK;
+    // Else, there is no room.
+    return A_ANY_ERROR;
 }
 
-/* Build action. */
+/* Tests if a creator always dies on creation. Note that the creator may die
+even if this test returns false, if its actual hp is less than hp-max. */
 
-/* This action makes progress on a construction effort, possibly completing
-   the new unit and making it available. */
+int
+creator_always_dies_on_creation(int u, int new_u)
+{
+       if (uu_hp_to_garrison(u, new_u) >= u_hp_max(u)
+           && uu_creation_cp(u, new_u) >= u_cp(new_u)) {
+               return TRUE;
+       }       
+       return FALSE;
+}
 
-int build_step_consumption(int u2, int u3, int m, int cp);
+/* Build action. */
 
+/*! \brief Prepare to Build Unit in Unit.
+ *
+ * Sets up build operation.
+ * \bug Shouldn't newunit be checked for NULL as well?  If it is 
+ *      NULL, then newunit->id will probably not work as intended.
+ * \param unit is the \Unit initiating the action.
+ * \param builder is the \Unit building the new Unit.
+ * \param newunit is the new Unit to build.
+ * \return 
+ *   - FALSE if 
+ *     - unit pointer to unit is NULL,
+ *     - pointer to unit action is NULL, or
+ *     - builder pointer to actee is NULL;
+ *   - TRUE otherwise.
+ */
 int
-prep_build_action(Unit *unit, Unit *unit2, Unit *newunit)
+prep_build_action(Unit *unit, Unit *builder, Unit *newunit)
 {
-    if (unit == NULL || unit->act == NULL || unit2 == NULL)
-      return FALSE;
+    if (unit == NULL || unit->act == NULL || builder == NULL) {
+       return FALSE;
+    }
     unit->act->nextaction.type = ACTION_BUILD;
     unit->act->nextaction.args[0] = newunit->id;
-    unit->act->nextaction.actee = unit2->id;
+    unit->act->nextaction.actee = builder->id;
     return TRUE;
 }
 
+/*! \brief Do Build Unit in Unit Action.
+ *
+ * Build a unit.
+ * - for all materials
+ *   - reduce the supply of the building \Unit by the proportional amount based
+ *     on construction points.
+ * - increase constrution points for the unit for this build
+ * - if \Unit completed,
+ *   - get rid of building \Unit, if neccessary
+ *   - make \Unit complete,
+ *   - update Unit display,
+ *   - use up ACP.
+ * - else
+ *   - update Unit display
+ *   - use up ACP
+ * \see for_all_material_types, side_has_treasury, um_takes_from_treasury
+ *      run_warning, uu_cp_per_build, completed, garrison_unit,
+ *      make_unit_complete, update_unit_display, use_up_acp.
+ * \param unit is the pointer to the \Unit initiating the action.
+ * \param builder is the pointer to \Unit building the new Unit.
+ * \param newunit is the pointer to \Unit being built.
+ * \return
+ *   - A_BUILD_COMPLETED if new \Unit is completed.
+ *   - A_ANY_DONE if build done.
+ */
+
 int
-do_build_action(Unit *unit, Unit *unit2, Unit *newunit)
+do_build_action(Unit *unit, Unit *builder, Unit *newunit)
 {
-    int u, u2, u3, m;
-
-    u = unit->type;  u2 = unit2->type;  u3 = newunit->type;
-    for_all_material_types(m) {
-       unit2->supply[m] -= build_step_consumption(u2, u3, m, newunit->cp);
-    }
-    newunit->cp += uu_cp_per_build(u2, u3);
+    int rslt = A_ANY_DONE;
+    int cp = -1;
+    int u2 = NONUTYPE, u3 = NONUTYPE;
+
+    assert_error(is_active(unit), 
+                "Build Action: Attempted to manipulate inactive unit");
+    assert_error(is_active(builder), 
+                "Build Action: Attempted to manipulate inactive unit");
+    assert_error(in_play(newunit), 
+                "Build Action: Attempted to manipulate out-of-play unit");
+    u2 = builder->type;
+    u3 = newunit->type;
+    // Calculate CP gained for this build.
+    cp = min(uu_cp_per_build(u2, u3), completenesses[u3] - newunit->cp);
+    // Consume resources for this build.
+    consume_materials_for_build(unit, builder, u3, cp);
+    use_up_acp(unit, uu_acp_to_build(u2, u3));
+    // Increment the new unit's CP.
+    newunit->cp += cp;
+    // Handle completeness.
     if (completed(newunit)) {
-       garrison_unit(unit2, newunit);
-       make_unit_complete(newunit);
-       update_unit_display(newunit->side, newunit, TRUE);
-       use_up_acp(unit, uu_acp_to_build(u2, u3));
-       return A_BUILD_COMPLETED;
+       if (uu_constructor_absorbed_by(u2, u3))
+           garrison_unit(builder, newunit);
+        make_unit_complete(newunit);
+       // TODO: Implement consumption-to-complete.
+       // TODO: Implement addition of default occs.
+       rslt = A_BUILD_COMPLETED;
     }
     update_unit_display(newunit->side, newunit, TRUE);
-    use_up_acp(unit, uu_acp_to_build(u2, u3));
-    return A_ANY_DONE;
-}
-
-/* Consumption per build is in terms of total material to complete,
-   this routine computes the consumption for a particular build action.
-   This is basically division of the total by the number of completion
-   points, but is careful about not missing any needed consumption
-   if the division rounds down. */
-
-int
-build_step_consumption(int u2, int u3, int m, int cp)
-{
-    int consumtot = um_consumption_per_build(u3, m);
-    int cpinc = uu_cp_per_build(u2, u3);
-    int consum, rslt;
-
-    consum = (cpinc * consumtot * 100);
-    /* Bug fix: if consumption really is 0, we return 0 here so that
-    "correction" below does not make it non-zero. */ 
-    if (consum == 0)
-        return 0;
-    consum /= (u_cp(u3));
-    rslt = consum / 100;
-    if (((cp + cpinc) * 100) / (u_cp(u3)) <= consum % 100)
-      ++rslt;
     return rslt;
 }
 
+/*! \brief Garrison Unit.
+ *
+ * This name is somewhat confusing.  It uses the uu_hp_to_garrison table
+ * to determine if the unit should be removed.  It is used to remove a
+ * building Unit upon creating a new Unit.  An example would be a 
+ * colonizer/settler/engineer disappearing when a villiage/town/city is
+ * built.  It is also sometimes used when a unit captures a unit, such as
+ * an army capturing a city, and being destroyed in the process of 
+ * capturing the city.
+ * - If the hit points to create/capture (hp_to_garrison) is greater than 
+ * the remaining hit points of the building \Unit
+ *   - remove the new \Unit from the cell,
+ *   - if the new \Unit is being transported by the building/capturing Unit
+ *     - force the new \Unit out of the building/capturing Unit.
+ *     - if the there is a transport availble (not currently implemented)
+ *       - put the new \Unit in the transport
+ *     - else
+ *       - put the new \Unit in the cell.
+ *   - if the new \Unit is being transported, but not by the 
+ *     building/capturing Unit
+ *     - set the alternate transport local variable to the transporting \Unit.
+ *   - for all occupants of the building/capturing \Unit
+ *     - if the occupant of the building \Unit can occupy the new
+ *       Unit
+ *       - remove the occupant from the new \Unit.
+ *       - update the Unit display.
+ *       - add the occupant to the new \Unit.
+ *     - else if the alternate transport can hold the occupant
+ *       - remove the ocupant from the building/capuring \Unit.
+ *       - update the Unit display.
+ *       - add the occupant to the alternate transport.
+ *     - else if the occupant can enter the cell
+ *       - remove the occupant from the building/capturing \Unit.
+ *       - update the Unit display.
+ *       - add the occupant to the cell.
+ *     - By default, leave the occupant in the building/capturing \Unit to be
+ *       destroyed with the building/capturing Unit.
+ *   - Set the temporary event data 1 to the id of the new \Unit.
+ *   - Kill the building/capturing Unit.
+ * - else reduce the building/capturing hp and hp2 by the hp to garrison
+ *   amount. \note if this occurs before damage is calculated, hp and hp2
+ *   may be different.
+ * \todo Add code to handle the garrison \Unit being put in a transport?
+ * \todo Add code to handle sub-occupants of doomed occupants?
+ * \todo Add code to post event for garrisoning damage?
+ * \see uu_hp_to_garrison, leave_cell, leave_trasnport, enter_transport,
+ *      can_occupy, update_unit_display, kill_unit.
+ *  \param builder is a pointer to the \Unit building/capturing the unit.
+ *  \param newunit is a pointer to the \Unit being built/captured.
+ */
 void
-garrison_unit(Unit *unit, Unit *unit2)
+garrison_unit(Unit *builder, Unit *newunit)
 {
-    int u = unit->type, u2 = unit2->type, x = unit->x, y = unit->y;
-    Unit *transport = NULL, *occ, *nextocc;
+    int x = builder->x;                /* x co-ordinate of builder */
+    int y = builder->y;                /* y co-ordinate of builder */
+    Unit *transport = NULL;    /* pointer to transport unit */
+    Unit *occ;                 /* pointer to occupant unit */
+    Unit *nextocc;                     /* pointer to next occupant unit */
 
     /* Maybe get rid of the building unit if it is to be the garrison. */
-    if (uu_hp_to_garrison(u, u2) >= unit->hp) {
+    if (uu_hp_to_garrison(builder->type, newunit->type) >= builder->hp) {
        /* But first get the about-to-be-killed garrisoning unit
           disconnected from everything. */
-       leave_cell(unit);
+       leave_cell(builder);
        /* Put new unit in place of the garrisoning one, if it was an
            occupant. */
-       if (unit2->transport == unit) {
-           leave_transport(unit2);
-           if (transport != NULL) { /* some other unit that could be transport? */
-               enter_transport(unit2, transport);
-           } else {
-               enter_cell(unit2, x, y);
-           }
+       if (newunit->transport == builder) {
+           leave_transport(newunit);
+           enter_cell(newunit, x, y);
        }
-
-       if (unit2->transport != NULL && unit2->transport != unit)
-         transport = unit2->transport;
+       if (newunit->transport != NULL && newunit->transport != builder)
+         transport = newunit->transport;
        /* for_all_occupants will not work here, 
           since leave_transport changes occ->nexthere */
-       for (occ = unit->occupant; occ != NULL; occ = nextocc) {
+       for (occ = builder->occupant; occ != NULL; occ = nextocc) {
            nextocc = occ->nexthere;
            /* Move the other occupants anywhere we can find. */
-           if (can_occupy(occ, unit2)) {
-               /* leave_cell won't work here, since "unit" already left cell */
+           if (can_occupy(occ, newunit)) {
+               // leave_cell won't work here, 
+               //  since "builder" already left cell */
                leave_transport(occ);
-               update_unit_display(unit->side, unit, TRUE);
-               enter_transport(occ, unit2);
+               update_unit_display(builder->side, builder, TRUE);
+               enter_transport(occ, newunit);
            } else if (transport != NULL && can_occupy(occ, transport)) {
                leave_transport(occ);
-               update_unit_display(unit->side, unit, TRUE);
+               update_unit_display(builder->side, builder, TRUE);
                enter_transport(occ, transport);
-           } else if (can_occupy_cell(occ, x, y)) {
+           } else if (type_can_occupy_cell(occ->type, x, y)
+                      && type_survives_in_cell(occ->type, x, y)) {
+               // We test for type_survives_in_cell here,
+               //   since we call enter_cell directly,
+               //   and thus bypass the unit-wrecking code in do_move_action.
                leave_transport(occ);
-               update_unit_display(unit->side, unit, TRUE);
+               update_unit_display(builder->side, builder, TRUE);
                enter_cell(occ, x, y);
            }
            /* Otherwise the occupant has to die along with the garrison. */
@@ -1037,85 +3142,83 @@ garrison_unit(Unit *unit, Unit *unit2)
        }
        /* Now we can get rid of the garrisoning unit without scrambling
           anything else. */
-       tmphevtdata1 = unit2->id;
-       kill_unit(unit, H_UNIT_GARRISONED);
+       tmphevtdata1 = newunit->id;
+       kill_unit(builder, H_UNIT_GARRISONED);
     } else {
        /* Note that if this all happens before damage is reckoned,
           hp and hp2 might be different. */
-       unit->hp -= uu_hp_to_garrison(u, u2);
-       unit->hp2 -= uu_hp_to_garrison(u, u2);
+       builder->hp -= uu_hp_to_garrison(builder->type, newunit->type);
+       builder->hp2 -= uu_hp_to_garrison(builder->type, newunit->type);
        /* (should record loss of hp as garrison event?) */
     }
 }
 
+/*! \brief Check for Build Unit in Unit Action.
+ *
+ * Check to see if a Unit can continue to be built.
+ * \see prep_build_action, do_build_action, in_play, uu_acp_to_build,
+ *      can_have_enough_acp, uu_cp_per_build, uu_tp_to_build,
+ *     fillsized, dostamce. uu_build_range, completed, uu_occ_can_build,
+ *     has_enough_acp, um_to_build.
+ * \param actor is the pointer to the \Unit initiating the action.
+ * \param builder is the pointer to \Unit building the new Unit.
+ * \param buildee is the pointer to \Unit being built.
+ */
+
 int
-check_build_action(Unit *unit, Unit *unit2, Unit *newunit)
+check_build_action(Unit *actor, Unit *builder, Unit *buildee)
 {
-    int u, u2, u3, acpcost, m, tp;
-
-    if (!in_play(unit))
-      return A_ANY_ERROR;
-    if (!in_play(unit2))
-      return A_ANY_ERROR;
-    if (!in_play(newunit))
-      return A_ANY_ERROR;
-    u = unit->type;  u2 = unit2->type;  u3 = newunit->type;
-    acpcost = uu_acp_to_build(u2, u3);
-    if (acpcost < 1)
-      return A_ANY_CANNOT_DO;
-    if (!can_have_enough_acp(unit, acpcost))
-      return A_ANY_CANNOT_DO;
-    if (uu_cp_per_build(u2, u3) <= 0)
-      return A_ANY_ERROR;
-
-/* This causes games that use obsoleting advances to hang. We now assume
-that if we were allowed to create the unit (which checks side_can_build)
-we should also be allowed to continue building on it. */
-
-#if 0
-
-    if (!side_can_build(unit->side, u3))
-      return A_ANY_ERROR;
+    int rslt = A_ANY_OK;
+    int u3 = NONUTYPE;
 
-#endif
-
-    /* Check the tooling. */
-    tp = (unit2->tooling ? unit2->tooling[u3] : 0);
-    if (tp < uu_tp_to_build(u2, u3))
-      return A_ANY_ERROR;
-    /* A mistake to be working on a complete unit. */
-    if (fullsized(newunit))
-      return A_ANY_ERROR;
-    /* Check the distance to the unit being worked on. */
-    if (distance(unit->x, unit->y, newunit->x, newunit->y)
-       > uu_build_range(u, u3))
-      return A_ANY_ERROR;
-    /* Note that we should be able to build when inside the incomplete
-       unit we're building. */
-    if (unit2->transport != NULL
-       && completed(unit2->transport)
-        && !uu_occ_can_build(unit2->transport->type, u2))
-      return A_ANY_ERROR;
-    if (!has_enough_acp(unit, acpcost))
-      return A_ANY_NO_ACP;
-    for_all_material_types(m) {
-       if (unit2->supply[m] < um_to_build(u2, m))
-         return A_ANY_NO_MATERIAL;
-       if (unit2->supply[m] < build_step_consumption(u2, u3, m, newunit->cp))
-         return A_ANY_NO_MATERIAL;
-    }
+    if (!in_play(buildee))
+       return A_ANY_ERROR;
+    u3 = buildee->type;
+    if (!valid(rslt = can_build(actor, builder, buildee)))
+      return rslt;
+    if (fullsized(buildee)) 
+       return A_ANY_ERROR;
     return A_ANY_OK;
 }
 
-/* Do all the little things to make a fully operational unit. */
+/*!
+ * \brief Complete Unit.
+ *
+ * Do all the little things to make a fully operational unit.
+ *   - if a unit has multiple parts ( fleet or army, for example),
+ *     it is not created at full size, but at a size of 1, so
+ *     construction points and hit points are set appropriately.
+ *   - Give the unit a name.
+ *   - set the view coverage area of the unit.
+ *   - if unit creation cuases a change in control of the cell,
+ *     remove enemy units.
+ *   - handle material supplied, created, and/or shared for created
+ *     unit.
+ *   - initialize action state.
+ *  
+ * \see max, u_cp, u_parts, u_hp, make_up_unit_name, cover_area,
+ * Kick_out_enemy_users, for_all_material_types, um_completed_supply,
+ * um_storage_x, try_sharing, init_unit_actorstate, init_unit_plan,
+ * set_unit_acp_for_turn, make_unit_vector, clear_unit_vector, 
+ * add_unit_to_vector, for_all_sides, trusted_side, add_side_to_set, 
+ * record_event, side_number, see_all_cell, printf
+ * \param unit is the unit to be completed.
+ */
 
 void
 make_unit_complete(Unit *unit)
 {
-    int u = unit->type, m;
+    int u = NONUTYPE, u2 = NONUTYPE;
+    int m = NONMTYPE;
     SideMask observers;
-    Side *side2;
+    Side *side = NULL, *side2 = NULL;
+    int i = 0, imax = -1;
+    Unit *unit2 = NULL;
 
+    assert_error(in_play(unit),
+                "Complete Action: Attempted to access an out-of-play unit");
+    u = unit->type;
+    side = unit->side;
     /* Make this a "complete" but not a "fullsized" unit. */
     unit->cp = max(unit->cp, u_cp(u) / u_parts(u));
     unit->hp = unit->hp2 = u_hp(u) / u_parts(u);
@@ -1123,25 +3226,98 @@ make_unit_complete(Unit *unit)
        one) was assigned just after its creation. */
     make_up_unit_name(unit);
     /* It also starts viewing its surroundings. */
-    cover_area(unit->side, unit, unit->transport, -1, -1, unit->x, unit->y);
+    cover_area(side, unit, unit->transport, -1, -1, unit->x, unit->y);
     /* Kick out enemy users if we control this cell. */
-    kick_out_enemy_users(unit->side, unit->x, unit->y);
+    kick_out_enemy_users(side, unit->x, unit->y);
+    /* Update the cancarry vector if this is a transport. */
+    if (u_is_transport(u)) 
+       update_cancarry_vector(side);
     /* Set all the supplies up to their unit-just-completed levels. */
     for_all_material_types(m) {
        unit->supply[m] = max(unit->supply[m], um_completed_supply(u, m));
        unit->supply[m] = min(unit->supply[m], um_storage_x(u, m));
     }
+    // Add any incomplete or complete occs that come as "part of the package".
+    // TODO: Warn on occupancy failures.
+    // TODO: Notify on creation failures.
+    for_all_unit_types(u2) {
+       if (!uu_complete_occs_on_completion(u, u2)
+           && !uu_incomplete_occs_on_completion(u, u2))
+           continue;
+       if (!type_can_occupy(u2, unit)) {
+           run_warning(
+"Cannot fit any implicitly created %s units into newly completed %s",
+                       u_type_name(u2), medium_long_unit_handle(unit));
+           continue;
+       }
+       if (0 < (imax = uu_complete_occs_on_completion(u, u2))) {
+           // TODO: Handle dice specs or probabilities.
+           for (i = 0; i < imax; ++i) {
+               if (!type_can_occupy(u2, unit)) {
+                   run_warning(
+"Cannot fit any more implictly created %s units into newly completed %s",
+                               u_type_name(u2), medium_long_unit_handle(unit));
+                   break;
+               }
+               if (!(unit2 = create_unit(u2, FALSE))) {
+                   notify(side, 
+"Failed to implicitly create %s unit in newly completed %s",
+                          u_type_name(u2), medium_long_unit_handle(unit));
+                   break;
+               }
+               set_created_unit_props(unit2, unit, side);
+               unit2->cp = u_cp(u2);
+               enter_transport(unit2, unit);
+               make_unit_complete(unit2);
+               record_event(
+                   H_UNIT_CREATED, add_side_to_set(side, NOSIDES),
+                   side_number(side), unit2->id);
+               count_gain(side, u2, build_gain);
+           }
+       }
+       if (0 < (imax = uu_incomplete_occs_on_completion(u, u2))) { 
+           // TODO: Handle dice specs or probabilities.
+           for (i = 0; i < imax; ++i) {
+               if (!type_can_occupy(u2, unit)) {
+                   run_warning(
+"Cannot fit any more implictly created %s units into newly completed %s",
+                               u_type_name(u2), medium_long_unit_handle(unit));
+                   break;
+               }
+               if (!(unit2 = create_unit(u2, FALSE))) {
+                   notify(side, 
+"Failed to implicitly create %s unit in newly completed %s",
+                          u_type_name(u2), medium_long_unit_handle(unit));
+                   break;
+               }
+               set_created_unit_props(unit2, unit, side);
+               unit2->cp = 0;
+               if (completed(unit2))
+                   make_unit_complete(unit2);
+               enter_transport(unit2, unit);
+               record_event(
+                   H_UNIT_CREATED, add_side_to_set(side, NOSIDES),
+                   side_number(side), unit2->id);
+               count_gain(side, u2, build_gain);
+           }
+       }
+    }
+#if (1)
+    /* The new unit may not need any materials due to being assigned 
+       a stationary goal. Let the economy code decide wheter or not to fill 
+       it up with materials. */ 
     /* Also see if anybody here is willing to share to make up any
        deficiencies before the end of the turn. */
     for_all_material_types(m) {
        if (unit->transport)
          try_sharing(unit->transport, unit, m);
     }
+#endif
     init_unit_actorstate(unit, FALSE);
     init_unit_plan(unit);
     /* Put this unit into action immediately, at full acp. */
     if (unit->act) {
-       compute_acp(unit);
+       set_unit_acp_for_turn(unit);
        if (unit->act->initacp > 0) {
           /* Make_unit_complete may be called by advanced units at
              turn 0 before compose_actionvectors has been called! */
@@ -1149,7 +3325,8 @@ make_unit_complete(Unit *unit)
                unit->side->actionvector = make_unit_vector(max(numunits, 100));
                clear_unit_vector(unit->side->actionvector);
           }
-          unit->side->actionvector = add_unit_to_vector(unit->side->actionvector, unit, 0);
+          unit->side->actionvector = 
+           add_unit_to_vector(unit->side->actionvector, unit, 0);
        }
     }
     /* Inform all sides that should know about the completion. */
@@ -1164,7 +3341,8 @@ make_unit_complete(Unit *unit)
     }
     record_event(H_UNIT_COMPLETED, observers, side_number(unit->side),
                 unit->id);
-    /* Make sure the image of the newly completed unit (and its name) is drawn. */
+    /* Make sure the image of the newly completed unit 
+       (and its name) is drawn. */
     all_see_cell(unit->x, unit->y);
     /* (should add to any per-side tallies) */
     Dprintf("%s is completed\n", unit_desig(unit));
@@ -1172,171 +3350,304 @@ make_unit_complete(Unit *unit)
 
 /* Repair action. */
 
+/*!
+ * \brief Prepare for Unit Repair Action.
+ */
+
 int
-prep_repair_action(unit, unit2, unit3)
-Unit *unit, *unit2, *unit3;
+prep_repair_action(Unit *actor, Unit *repairer, Unit *repairee)
 {
-    if (unit == NULL || unit->act == NULL || unit2 == NULL || unit3 == NULL)
-      return FALSE;
-    unit->act->nextaction.type = ACTION_REPAIR;
-    unit->act->nextaction.args[0] = unit3->id;
-    unit->act->nextaction.actee = unit2->id;
+    if (!is_active(actor) || !is_active(repairer) || !in_play(repairee))
+       return FALSE;
+    if (!repairer->act)
+       return FALSE;
+    repairer->act->nextaction.type = ACTION_REPAIR;
+    repairer->act->nextaction.args[0] = repairee->id;
+    repairer->act->nextaction.actee = repairer->id;
     return TRUE;
 }
 
+/*!
+ * \brief Do Repair Unit Action.
+ *
+ * Use a unit to repair another unit.
+ *   - Calculate amount of hitpoints that can be repaired.
+ *   - Adjust the repaired unit's hitpoints.
+ *   - Use up any materials required.
+ *   - Use up any ACP needed.
+ * \see uu_repair, add_to_unit_hp, prob_fraction,
+ *      for_all_material_types, um_comsumption_per_repair,
+ *      use_up_acp, uu_acp_to_repair.
+ * \return A_ANY_DONE always.
+ */
+
 int
-do_repair_action(unit, unit2, unit3)
-Unit *unit, *unit2, *unit3;
+do_repair_action(Unit *acpsrc, Unit *repairer, Unit *repairee)
 {
-    int u, u2, u3, rep, m;
-
-    u = unit->type;  u2 = unit2->type;  u3 = unit3->type;
-    rep = uu_repair(u2, u3);
-    /* Add to the repairee's hit points. */
-    add_to_unit_hp(unit3, prob_fraction(rep));
-    /* Eat supplies used up by repair. */
-    for_all_material_types(m) {
-       unit2->supply[m] -= um_consumption_per_repair(u3, m);
+    int u2 = NONUTYPE, u3 = NONUTYPE;
+
+    assert_error(is_active(acpsrc),
+                "Repair Action: Attempted to manipulate an inactive unit");
+    assert_error(is_active(repairer),
+                "Repair Action: Attempted to manipulate an inactive unit");
+    assert_error(in_play(repairee),
+                "Repair Action: Attempted to manipulate an out-of-play unit");
+    // Useful info.
+    u2 = repairer->type;
+    u3 = repairee->type;
+    // If at turn start, then we consider auto-repair mechanisms.
+    if (at_turn_start) {
+       // Hp-recovery mechanism.
+       if ((repairer == repairee)
+           && (0 < u_hp_recovery(u2)) 
+           && (repairee->hp >= u_hp_to_recover(u2))) {
+           add_to_unit_hp(repairee, prob_fraction(u_hp_recovery(u2)));
+       }
+       // Auto-repair mechanism.
+       if (0 < uu_auto_repair(u2, u3)) {
+           add_to_unit_hp(repairee, prob_fraction(uu_auto_repair(u2, u3)));
+           consume_materials(acpsrc, repairer, um_consumption_per_repair);
+           consume_materials(acpsrc, repairer, um_consumption_per_repaired, 
+                             u3);
+       }
+    }
+    // Else during turn, then we consider explicit repair.
+    else {
+       add_to_unit_hp(repairee, prob_fraction(uu_hp_per_repair(u2, u3)));
+       consume_materials(acpsrc, repairer, um_consumption_per_repair);
+       consume_materials(acpsrc, repairer, um_consumption_per_repaired, u3);
+       use_up_acp(acpsrc, uu_acp_to_repair(u2, u3));
     }
-    use_up_acp(unit, uu_acp_to_repair(u2, u3));
     return A_ANY_DONE;
 }
 
+/*!
+ * \brief Check for Repair Unit Action.
+ *
+ * Check to see if the repair action can be done.
+ * Validate:
+ *   - All units are in play.
+ *   - The repairng unit can repair the repaired unit.
+ *   - Sufficient materials are on hand to do the repair.
+ *   - the unit has enought ACP to do the repair this turn.
+ * \see in_play, uu_acp_to_repair, can_have_enough_acp, uu_hp_to_repair,
+ *      for_all_material_types, um_to_repair, um_consumption_per_repair,
+ *      has_enough_acp.
+ */
+
 int
-check_repair_action(unit, unit2, unit3)
-Unit *unit, *unit2, *unit3;
+check_repair_action(Unit *actor, Unit *repairer, Unit *repairee)
 {
-    int u, u2, u3, acp, m;
+    int rslt = A_ANY_OK;
 
-    if (!in_play(unit))
-      return A_ANY_ERROR;
-    if (!in_play(unit2))
-      return A_ANY_ERROR;
-    if (!in_play(unit3))
-      return A_ANY_ERROR;
-    u = unit->type;  u2 = unit2->type;  u3 = unit3->type;
-    acp = uu_acp_to_repair(u2, u3);
-    if (acp < 1)
-      return A_ANY_CANNOT_DO;
-    if (!can_have_enough_acp(unit, acp))
-      return A_ANY_CANNOT_DO;
-    if (uu_repair(u2, u3) <= 0)
-      return A_ANY_ERROR;
-    if (unit3->hp >= u_hp(u3))
-      return A_ANY_ERROR;
-    if (unit2->hp < uu_hp_to_repair(u2, u3))
-      return A_ANY_ERROR;
-    for_all_material_types(m) {
-       if (unit2->supply[m] < um_to_repair(u3, m))
-         return A_ANY_NO_MATERIAL;
-       if (unit2->supply[m] < um_consumption_per_repair(u3, m))
-         return A_ANY_NO_MATERIAL;
-    }
-    if (!has_enough_acp(unit, acp))
-      return A_ANY_NO_ACP;
+    // Is the repairee in play?
+    if (!in_play(repairee))
+       return A_ANY_ERROR;
+    // Can explicit repair occur during turn?
+    if (!at_turn_start && !valid(rslt = can_repair(actor, repairer, repairee)))
+       return rslt;
+    // Can auto-repair occur at turn start?
+    if (at_turn_start 
+       && !valid(rslt = can_auto_repair(repairer, repairee)))
+       return rslt;
     return A_ANY_OK;
 }
 
 /* Disband action. */
 
-/* The disband action destroys a unit in an "orderly" fashion, and can be
-   undertaken voluntarily. */
-
+/*!
+ * \brief Prepare for Unit Disband Action.
+ *
+ * Set up to do a disband action.
+ * The disband action destroys a unit in an "orderly" fashion, and can be
+ * undertaken voluntarily.
+ * \param unit is a pointer to the \Unit initiating the action.
+ * \param disbanded is a pointer to the unit being disbanded.
+ * \return
+ *    - true if the action is queued;
+ *    - false if
+ *      - unit pointer is NULL,
+ *      - the unit action pointer is NULL, or
+ *      - the disbanded pointer is NULL.
+ */
 int
-prep_disband_action(unit, unit2)
-Unit *unit, *unit2;
+prep_disband_action(Unit *unit, Unit *disbanded)
 {
-    if (unit == NULL || unit->act == NULL || unit2 == NULL)
+    if (unit == NULL || unit->act == NULL || disbanded == NULL)
       return FALSE;
     unit->act->nextaction.type = ACTION_DISBAND;
-    unit->act->nextaction.actee = unit2->id;
+    unit->act->nextaction.actee = disbanded->id;
     return TRUE;
 }
 
+/*!
+ * \brief Do Unit Disband Action.
+ *
+ * Disband the unit by:
+ *   - distributing as much of it's supplies as possble,
+ *   - if it has more hit points than needed to disband, recover
+ *     as much of it's disbanding materials as possible, 
+ *   - kill the unit, and
+ *   - use it's ACP.
+ * \see for_all_material_types, um_supply_per_disband, distribute_material.
+ *      hp_per_disband, for_all_material_types, um_recycleable, 
+ *      distribute_material, kill_unit, use_up_acp, u_acp_to_disband.
+ *
+ * \GDL
+ *    - <A href="xcdesign.html#GDL_ref_acp-to-disband">acp-to-disband</A>
+ *    .
+ * \param unit is a pointer to the \Unit initiating the action.
+ * \param disbanded is a pointer to the unit being disbanded.
+ * \return A_ANY_OK always.
+ */
 int
-do_disband_action(unit, unit2)
-Unit *unit, *unit2;
+do_disband_action(Unit *unit, Unit *disbanded)
 {
-    int u2, m, amt, disb;
+    int m, amt, disb;
 
-    u2 = unit2->type;
     /* Recover some percentage of the unit's supply. */
     for_all_material_types(m) {
-       if (um_supply_per_disband(u2, m) > 0 && unit2->supply[m] > 0) {
-           amt = (unit2->supply[m] * um_supply_per_disband(u2, m)) / 100;
+       if (um_supply_per_disband(disbanded->type, m) > 0 && disbanded->supply[m] > 0) {
+           amt = (disbanded->supply[m] * um_supply_per_disband(disbanded->type, m)) / 100;
            /* Unit always loses the amount, whether or not distributed. */
-           unit2->supply[m] -= amt;
-           distribute_material(unit2, m, amt);
+           disbanded->supply[m] -= amt;
+           distribute_material(disbanded, m, amt);
        }
     }
     /* Remove hit points or kill the unit directly. */
-    disb = u_hp_per_disband(u2);
-    if (disb < unit2->hp) {
-       unit2->hp -= disb;
-       unit2->hp2 = unit2->hp;
+    disb = u_hp_per_disband(disbanded->type);
+    if (disb < disbanded->hp) {
+       disbanded->hp -= disb;
+       disbanded->hp2 = disbanded->hp;
     } else {
        /* Pass around whatever we can get out of the unit itself. */
        for_all_material_types(m) {
-           if (um_recycleable(u2, m) > 0) {
-               distribute_material(unit2, m, um_recycleable(u2, m));
+           if (um_recycleable(disbanded->type, m) > 0) {
+               distribute_material(disbanded, m, um_recycleable(disbanded->type, m));
            }
        }
-       kill_unit(unit2, H_UNIT_DISBANDED);
+       kill_unit(disbanded, H_UNIT_DISBANDED);
     }
-    use_up_acp(unit, u_acp_to_disband(u2));
+    use_up_acp(unit, u_acp_to_disband(disbanded->type));
     return A_ANY_DONE;
 }
 
-/* Given a unit and a quantity of material, pass it out to nearby units. */
+/*
+ * \brief Distribute Material to Units.
+ *
+ * \todo The adjacent distribution code and the ranged distribution
+ * code are not the same.  Question: why not?  FIXME in general: why is
+ * the algorithm here so different from run_economy?  Should
+ * perhaps merge some of the code or at least ideas.  But I'm not
+ * sure run_economy is quite right either in terms of making sure
+ * that it transfers supplies rather than losing them due to
+ * being full. 
+ * <P> Stanley M. Sutton comment. 
+ * <P> To be really accurate, this should be iterative, and 
+ * prioritorized.  If all units in range are full, the algorithym
+ * should check to see if the full units can transfer supplies
+ * to non-full units within their range, and so on.
+ * Since this could use an appreciable amount of ACP if there are ACP
+ * costs involved, it should really be solved by a global optimization
+ * algorithm that can figure out the best way to disribute all supplies
+ * to be distruted with the minimum outlay of ACP, perhaps limited by 
+ * available ACP, a doctrine, a plan, or a player settable value as a
+ * percentage of the turn's available ACP, or a player setable maximem
+ * number.
+ * <P>Should we distribute material to other cccupants on the
+ * same transport before checking the stack?
+ * <P>Should we check for units inside transports on the same
+ * cell?
+ * \parm unit is the \Unit distributing material.
+ * \param m is the type of material being distributed.
+ * \param amt is the amount of material being distributed.
+ * \see give_away, for_all_stack, unit_trusts_unit, for_all_directions,
+ *      interior_point_in_dir, 
+ * Given a unit and a quantity of material, pass it out to nearby units.
+ */
 
 void
-distribute_material(unit, m, amt)
-Unit *unit;
-int m, amt;
+distribute_material(Unit *unit, int m, int amt)
 {
-    int dir, x1, y1;
+    int dir, x1, y1, dist;
     Unit *unit2;
 
     /* Distribute to transport first. */
-    if (amt > 0 && unit->transport != NULL) {
+    if (unit->transport != NULL) {
        amt = give_away(unit->transport, m, amt);
-       if (amt > 0 && unit->transport->transport != NULL)
-         amt = give_away(unit->transport->transport, m, amt);
+       if (unit->transport->transport != NULL) {
+               amt = give_away(unit->transport->transport, m, amt);
+       }
     }
     /* Then to any unit in the cell. */
-    if (amt > 0) {
-       for_all_stack(unit->x, unit->y, unit2) {
-           if (unit2 != unit && unit_trusts_unit(unit, unit2)) {
+    for_all_stack_with_occs(unit->x, unit->y, unit2) {
+       if (amt <= 0) {
+               break;
+       }
+       if (unit2 != unit && unit_trusts_unit(unit, unit2)) {
                amt = give_away(unit2, m, amt);
-           }
-       }
+       }
     }
     /* Then to any unit in an adjacent cell. */
-    if (amt > 0) {
-       for_all_directions(dir) {
-           if (interior_point_in_dir(unit->x, unit->y, dir, &x1, &y1)) {
+    for_all_directions(dir) {
+       if (amt <= 0) {
+               break;
+       }
+       if (interior_point_in_dir(unit->x, unit->y, dir, &x1, &y1)) {
                for_all_stack(x1, y1, unit2) {
-                   if (unit_trusts_unit(unit, unit2)) {
-                       amt = give_away(unit2, m, amt);
-                   }
+                       if (amt <= 0) {
+                               break;
+                       }
+                       if (unit_trusts_unit(unit, unit2)) {
+                               amt = give_away(unit2, m, amt);
+                       }
                }
-           }
-           if (amt == 0)
-             break;
        }
     }
+    /* Then to any unit within range.  This in addition to the above
+     * code for adjacent cells because the latter does not check in-length
+     * and out-length.
+     */
+       for_all_cells_within_range(unit->x, unit->y, 
+                                  um_outlength (unit->type, m), x1, y1) {
+           if (amt <= 0) {
+               break;
+           }
+           if (!inside_area(x1, y1)) {
+               continue;
+           }
+           if (!terrain_visible(unit->side, x1, y1)) {
+               continue;
+           }
+           dist = distance(unit->x, unit->y, x1, y1);
+           /* Include all occupants like try_transfer_to_cell does for
+              run_economy.  */
+           for_all_stack_with_occs(x1, y1, unit2) {
+               if (amt <= 0) {
+                       goto done;
+               }
+               if (is_active(unit2)
+                   && unit_trusts_unit(unit, unit2)
+                   && um_inlength (unit2->type, m) >= dist) {
+                   amt = give_away (unit2, m, amt);
+               }
+           }
+       }
+ done:;
 }
 
 /* Give as much as possible of the given material to the unit,
    return the amount left to give away. */
 
 static int
-give_away(unit, m, amt)
-Unit *unit;
-int m, amt;
+give_away(Unit *unit, int m, int amt)
 {
     int space, add;
 
+    /* We can't give away a negative amount. */
+    if (amt <= 0) {
+       return amt;
+    }
     space = um_storage_x(unit->type, m) - unit->supply[m];
     add = (amt < space ? amt : space);
     unit->supply[m] += add;
@@ -1347,22 +3658,18 @@ int m, amt;
 }
 
 int
-check_disband_action(unit, unit2)
-Unit *unit, *unit2;
+check_disband_action(Unit *unit, Unit *disbanded)
 {
-    int u, u2, acp;
+    int acp;
 
     if (!in_play(unit))
       return A_ANY_ERROR;
-    if (!in_play(unit2))
+    if (!in_play(disbanded))
       return A_ANY_ERROR;
-    u = unit->type;  u2 = unit->type;
-    acp = u_acp_to_disband(u2);
+    acp = u_acp_to_disband(disbanded->type);
     if (acp < 1)
       return A_ANY_CANNOT_DO;
-    if (!can_have_enough_acp(unit, acp))
-      return A_ANY_CANNOT_DO;
-    if (u_hp_per_disband(unit2->type) <= 0)
+    if (u_hp_per_disband(disbanded->type) <= 0)
       return A_ANY_CANNOT_DO;
     if (!has_enough_acp(unit, acp))
       return A_ANY_NO_ACP;
@@ -1376,9 +3683,7 @@ Unit *unit, *unit2;
 /* (New unit in same cell if possible or else in random adjacent cell.) */
 
 int
-prep_transfer_part_action(unit, unit2, parts, unit3)
-Unit *unit, *unit2, *unit3;
-int parts;
+prep_transfer_part_action(Unit *unit, Unit *unit2, int parts, Unit *unit3)
 {
     if (unit == NULL || unit->act == NULL || unit2 == NULL)
       return FALSE;
@@ -1390,9 +3695,7 @@ int parts;
 }
 
 int
-do_transfer_part_action(unit, unit2, parts, unit3)
-Unit *unit, *unit2, *unit3;
-int parts;
+do_transfer_part_action(Unit *unit, Unit *unit2, int parts, Unit *unit3)
 {
     int u2 = unit2->type, acp, part_hp;
 
@@ -1402,8 +3705,9 @@ int parts;
        unit3 = create_unit(u2, TRUE);
        if (unit3 != NULL) {
            unit3->hp = parts * part_hp;
-           /* (Cap the hp now - occupancy calcs below might use unit parts
-               to determine available capacity) */
+           /* (Cap the hp now - 
+               occupancy calcs below might use unit parts to determine 
+               available capacity) */
            unit3->hp = min(unit3->hp, u_hp(unit3->type));
            unit3->hp2 = unit3->hp;
            set_unit_side(unit3, unit->side);
@@ -1411,12 +3715,17 @@ int parts;
            /* Always number the unit when first created. */
            assign_unit_number(unit3);
            /* (should fill in more slots of new unit, such as supply?) */
-           if (can_occupy_cell(unit3, unit2->x, unit2->y)) {
+           if (type_can_occupy_cell(unit3->type, unit2->x, unit2->y)
+               && type_survives_in_cell(unit3->type, unit2->x, unit2->y)) {
+               /* Calling type_survives_in_cell is redundant since unit3 is 
+                   the same type as unit2, which is already in the cell, 
+                   but we do it anyway for consistency. */
                enter_cell(unit3, unit2->x, unit2->y);
            } else {
                /* (should add code to enter something else here) */
                /* This should never happen. */
-               run_warning("transfer_part complications, leaving unit offworld");
+               run_warning(
+"transfer_part complications, leaving unit offworld");
            }
        } else {
            /* We have a problem. */
@@ -1443,9 +3752,7 @@ int parts;
 }
 
 int
-check_transfer_part_action(unit, unit2, parts, unit3)
-Unit *unit, *unit2, *unit3;
-int parts;
+check_transfer_part_action(Unit *unit, Unit *unit2, int parts, Unit *unit3)
 {
     int u2, acp;
 
@@ -1455,11 +3762,15 @@ int parts;
       return A_ANY_ERROR;
     if (parts <= 0)
       return A_ANY_ERROR;
-    /* unit3 can be null. */
+    /* unit3 can be NULL, which implies an unit it to be detached. */
     u2 = unit2->type;
-    acp = u_acp_to_transfer_part(u2);
-    if (acp < 1)
+    /* If unit3 is not NULL, then we need to check to make sure that it 
+       is compatible with the donor unit. */
+    if (unit3 && 
+       ((u_parts(unit3->type) <= 0) 
+        || !uu_can_transfer_parts_to(u2, unit3->type)))
       return A_ANY_CANNOT_DO;
+    acp = u_acp_to_transfer_part(u2);
     /* Check if type is allowed and if needed tech & advances exist. */
     if (!side_can_build(unit->side, u2))
       return A_ANY_CANNOT_DO;
@@ -1478,9 +3789,7 @@ int parts;
 /* Change-type action. */
 
 int
-prep_change_type_action(unit, unit2, u3)
-Unit *unit, *unit2;
-int u3;
+prep_change_type_action(Unit *unit, Unit *unit2, int u3)
 {
     if (unit == NULL || unit->act == NULL || unit2 == NULL)
       return FALSE;
@@ -1493,47 +3802,40 @@ int u3;
 /* Actually change the type of a unit. */
 
 int
-do_change_type_action(unit, unit2, u3)
-Unit *unit, *unit2;
-int u3;
+do_change_type_action(Unit *unit, Unit *unit2, int u3)
 {
     int u, u2;
+    int acpdebt = 0;
 
     u = unit->type;  u2 = unit2->type;
-    change_unit_type(unit2, u3, H_UNIT_TYPE_CHANGED);
+    acpdebt = uu_acp_to_change_type(u2, u3);
+    change_unit_type(unit2, u3, H_UNIT_TYPE_CHANGED, NULL);
     update_unit_display(unit2->side, unit2, TRUE);
-    use_up_acp(unit, uu_acp_to_change_type(u2, u3));
+    if (!acp_indep(unit) && unit->act) {
+       if (type_acp_max(u) > 0)
+         acpdebt = (acpdebt * type_acp_max(u3)) / type_acp_max(u);
+       else
+         acpdebt = 0;
+       use_up_acp(unit, min(acpdebt, unit->act->acp - u_acp_min(u3)));
+    }
     return A_ANY_DONE;
 }
 
+//! Check the 'change-type' action.
+/*!
+    Arbiter Function.
+*/
+
 int
-check_change_type_action(unit, unit2, u3)
-Unit *unit, *unit2;
-int u3;
+check_change_type_action(Unit *unit, Unit *unit2, int u3)
 {
-    int u, u2, acp, m;
+    int rslt = A_ANY_OK;
 
-    if (!in_play(unit))
-      return A_ANY_ERROR;
-    if (!in_play(unit2))
-      return A_ANY_ERROR;
-    if (!is_unit_type(u3))
-      return A_ANY_ERROR;
-    u = unit->type;  u2 = unit2->type;
-    acp = uu_acp_to_change_type(u2, u3);
-    if (acp < 1)
-      return A_ANY_CANNOT_DO;
-    if (!can_have_enough_acp(unit, acp))
-      return A_ANY_CANNOT_DO;
-    if (!side_can_build(unit2->side, u3))
-      return A_ANY_CANNOT_DO;
-    if (!has_enough_acp(unit, acp))
-      return A_ANY_NO_ACP;
-    /* Check that the unit has any required supplies. */
-    for_all_material_types(m) {
-       if (unit2->supply[m] < um_to_change_type(u2, m))
-         return A_ANY_NO_MATERIAL;
-    }
+    assert_return(in_play(unit), A_ANY_ERROR);
+    assert_return(in_play(unit2), A_ANY_ERROR);
+    assert_return(is_unit_type(u3), A_ANY_ERROR);
+    if (!valid(rslt = can_change_type_to(unit, unit2, u3)))
+      return rslt;
     return A_ANY_OK;
 }
 
@@ -1544,9 +3846,7 @@ int u3;
 /* (what about occs, garrisons, plans?) */
 
 int
-prep_change_side_action(unit, unit2, side)
-Unit *unit, *unit2;
-Side *side;
+prep_change_side_action(Unit *unit, Unit *unit2, Side *side)
 {
     if (unit == NULL || unit->act == NULL || unit2 == NULL)
       return FALSE;
@@ -1557,9 +3857,7 @@ Side *side;
 }
 
 int
-do_change_side_action(unit, unit2, side)
-Unit *unit, *unit2;
-Side *side;
+do_change_side_action(Unit *unit, Unit *unit2, Side *side)
 {
     int rslt;
 
@@ -1575,9 +3873,7 @@ Side *side;
 }
 
 int
-check_change_side_action(unit, unit2, side)
-Unit *unit, *unit2;
-Side *side;
+check_change_side_action(Unit *unit, Unit *unit2, Side *side)
 {
     int u, u2, acp;
 
@@ -1615,9 +3911,7 @@ Side *side;
    possible, or should there be a "can-dig-under-enemy" parm?  */
 
 int
-prep_alter_cell_action(unit, unit2, x, y, t)
-Unit *unit, *unit2;
-int x, y, t;
+prep_alter_cell_action(Unit *unit, Unit *unit2, int x, int y, int t)
 {
     if (unit == NULL || unit->act == NULL || unit2 == NULL)
       return FALSE;
@@ -1630,27 +3924,35 @@ int x, y, t;
 }
 
 int
-do_alter_cell_action(unit, unit2, x, y, t)
-Unit *unit, *unit2;
-int x, y, t;
+do_alter_cell_action(Unit *unit, Unit *unit2, int x, int y, int t)
 {
-    int u, u2, oldt, acpr, acpa, m, amt, excess;
+    int u, u2, oldt, acpr, acpa, m, amt, excess, space;
 
     u = unit->type;  u2 = unit2->type;
     oldt = terrain_at(x, y);
     /* Change the terrain to the new type. */
     change_terrain_type(x, y, t);
     for_all_material_types(m) {
-       amt = tm_material_per_remove_terrain(oldt, m);
-       unit2->supply[m] += amt;
-       amt = tm_consumption_per_add_terrain(t, m);
-       unit2->supply[m] -= amt;
-       excess = unit2->supply[m] - um_storage_x(unit2->type, m);
+       amt = tm_material_per_remove_terrain(oldt, m) - tm_consumption_per_add_terrain(t, m);
+       space = um_storage_x(unit2->type, m) - unit2->supply[m];
+       /* First fill up unit2 as far as there is room. */
+       unit2->supply[m] += min(amt, space);
+       /* Compute the excess we couldn't store. */
+       excess = amt - space;
+       /* Try to give away the same amount to make room for the excess. */
        if (excess > 0) {
+           /* But first clip it to available supplies. */
+           excess = min(excess, unit2->supply[m]);
            unit2->supply[m] -= excess;
            distribute_material(unit2, m, excess);
        }
     }
+    /* Then try to fill up unit2 again with the remaining excess. */
+    space = um_storage_x(unit2->type, m) - unit2->supply[m];
+    /* The check for available space is redundant now, but will be needed
+    in the future when distribute_material has been improved. */
+    unit2->supply[m] += min(excess, space);
+
     /* Note that we still charge acp even if terrain type doesn't change. */
     acpr = ut_acp_to_remove_terrain(u2, oldt);
     acpa = ut_acp_to_add_terrain(u2, t);
@@ -1659,9 +3961,7 @@ int x, y, t;
 }
 
 int
-check_alter_cell_action(unit, unit2, x, y, t)
-Unit *unit, *unit2;
-int x, y, t;
+check_alter_cell_action(Unit *unit, Unit *unit2, int x, int y, int t)
 {
     int u, u2, m, oldt, acpr, acpa;
 
@@ -1687,7 +3987,8 @@ int x, y, t;
       return A_ANY_ERROR;
     if (!has_enough_acp(unit, acpr + acpa))
       return A_ANY_NO_ACP;
-    /* We have to have a minimum level of supply to be able to do the action. */
+    /* We have to have a minimum level of supply to be able to do the
+       action. */
     for_all_material_types(m) {
        if (unit2->supply[m] < um_to_remove_terrain(u2, m))
          return A_ANY_NO_MATERIAL;
@@ -1704,9 +4005,7 @@ int x, y, t;
 /* Add terrain; border, connection, or coating. */
 
 int
-prep_add_terrain_action(unit, unit2, x, y, dir, t)
-Unit *unit, *unit2;
-int x, y, dir, t;
+prep_add_terrain_action(Unit *unit, Unit *unit2, int x, int y, int dir, int t)
 {
     if (unit == NULL || unit->act == NULL || unit2 == NULL)
       return FALSE;
@@ -1720,9 +4019,7 @@ int x, y, dir, t;
 }
 
 int
-do_add_terrain_action(unit, unit2, x, y, dir, t)
-Unit *unit, *unit2;
-int x, y, dir, t;
+do_add_terrain_action(Unit *unit, Unit *unit2, int x, int y, int dir, int t)
 {
     int u = unit->type, oldval, newval, m, amt;
     Side *side;
@@ -1751,7 +4048,14 @@ int x, y, dir, t;
     /* Consume any material necessary to the action. */
     for_all_material_types(m) {
        amt = tm_consumption_per_add_terrain(t, m);
-       unit2->supply[m] -= amt;
+        if (side_has_treasury(unit2->side, m)
+           && um_takes_from_treasury(unit2->type, m)
+           && (amt > unit2->supply[m])) {
+           amt -= unit2->supply[m];
+           unit2->supply[m] = 0;
+           unit2->side->treasury[m] -= amt;
+       } else
+           unit2->supply[m] -= amt;
     }
     /* Let everybody see what has happened. */
     for_all_sides(side) {
@@ -1765,11 +4069,9 @@ int x, y, dir, t;
 }
 
 int
-check_add_terrain_action(unit, unit2, x, y, dir, t)
-Unit *unit, *unit2;
-int x, y, dir, t;
+check_add_terrain_action(Unit *unit, Unit *unit2, int x, int y, int dir, int t)
 {
-    int u, u2, m, acp;
+    int u, u2, m, acp, treas;
 
     if (!in_play(unit))
       return A_ANY_ERROR;
@@ -1790,14 +4092,19 @@ int x, y, dir, t;
      if (!can_have_enough_acp(unit, acp))
        return A_ANY_CANNOT_DO;
    if (distance(unit->x, unit->y, x, y) > ut_alter_range(u2, t))
-      return A_ANY_ERROR;
+      return A_ANY_TOO_FAR;
     if (!has_enough_acp(unit, acp))
       return A_ANY_NO_ACP;
     /* We have to have certain amounts supply to be able to do the action. */
     for_all_material_types(m) {
        if (unit2->supply[m] < um_to_add_terrain(u2, m))
          return A_ANY_NO_MATERIAL;
-       if (unit2->supply[m] < tm_consumption_per_add_terrain(t, m))
+        if (side_has_treasury(unit2->side, m)
+           && um_takes_from_treasury(u2, m))
+           treas = unit2->side->treasury[m];
+        else
+           treas = 0;
+       if ((unit2->supply[m] + treas) < tm_consumption_per_add_terrain(t, m))
          return A_ANY_NO_MATERIAL;
     }
     return A_ANY_OK;
@@ -1808,9 +4115,7 @@ int x, y, dir, t;
 /* Remove a border, connection, or coating. */
 
 int
-prep_remove_terrain_action(unit, unit2, x, y, dir, t)
-Unit *unit, *unit2;
-int x, y, dir, t;
+prep_remove_terrain_action(Unit *unit, Unit *unit2, int x, int y, int dir, int t)
 {
     if (unit == NULL || unit->act == NULL || unit2 == NULL)
       return FALSE;
@@ -1824,11 +4129,9 @@ int x, y, dir, t;
 }
 
 int
-do_remove_terrain_action(unit, unit2, x, y, dir, t)
-Unit *unit, *unit2;
-int x, y, dir, t;
+do_remove_terrain_action(Unit *unit, Unit *unit2, int x, int y, int dir, int t)
 {
-    int u = unit->type, oldval, newval, m, amt, excess;
+    int u = unit->type, oldval, newval, m, amt, excess, space;
     Side *side;
 
     switch (t_subtype(t)) {
@@ -1857,14 +4160,25 @@ int x, y, dir, t;
     }
     for_all_material_types(m) {
        amt = tm_material_per_remove_terrain(t, m);
-       unit2->supply[m] += amt;
-       /* Clip to available storage and move leftovers around. */
-       excess = unit2->supply[m] - um_storage_x(unit2->type, m);
+       space = um_storage_x(unit2->type, m) - unit2->supply[m];
+       /* First fill up unit2 as far as there is room. */
+       unit2->supply[m] += min(amt, space);
+       /* Compute the excess we couldn't store. */
+       excess = amt - space;
+       /* Try to give away the same amount to make room for the excess. */
        if (excess > 0) {
+           /* But first clip it to available supplies. */
+           excess = min(excess, unit2->supply[m]);
            unit2->supply[m] -= excess;
            distribute_material(unit2, m, excess);
        }
     }
+    /* Then try to fill up unit2 again with the remaining excess. */
+    space = um_storage_x(unit2->type, m) - unit2->supply[m];
+    /* The check for available space is redundant now, but will be needed
+    in the future when distribute_material has been improved. */
+    unit2->supply[m] += min(excess, space);
+
     /* Let everybody see what has happened. */
     for_all_sides(side) {
        if (active_display(side)) {
@@ -1877,9 +4191,7 @@ int x, y, dir, t;
 }
 
 int
-check_remove_terrain_action(unit, unit2, x, y, dir, t)
-Unit *unit, *unit2;
-int x, y, dir, t;
+check_remove_terrain_action(Unit *unit, Unit *unit2, int x, int y, int dir, int t)
 {
     int u, u2, m, acp;
 
@@ -1902,10 +4214,11 @@ int x, y, dir, t;
     if (!can_have_enough_acp(unit, acp))
       return A_ANY_CANNOT_DO;
     if (distance(unit->x, unit->y, x, y) > ut_alter_range(u2, t))
-      return A_ANY_ERROR;
+      return A_ANY_TOO_FAR;
     if (!has_enough_acp(unit, acp))
       return A_ANY_NO_ACP;
-    /* We have to have a minimum level of supply to be able to do the action. */
+    /* We have to have a minimum level of supply to be able to do the
+       action. */
     for_all_material_types(m) {
        if (unit2->supply[m] < um_to_remove_terrain(u2, m))
          return A_ANY_NO_MATERIAL;
@@ -1913,6 +4226,23 @@ int x, y, dir, t;
     return A_ANY_OK;
 }
 
+//! Should action movies be played?
+/*! \note Stupid hack. */
+
+int
+should_play_movies(void)
+{
+    Side *side = NULL;
+
+    for_all_sides(side) {
+       if (side == indepside)
+         continue;
+       if (!side_has_ai(side))
+         return TRUE;
+    }
+    return FALSE;
+}
+
 /* Execute a given action on a given unit. */
 
 /* (assumes unit can act in the first place - valid?) */
@@ -2144,10 +4474,17 @@ execute_action(Unit *unit, Action *action)
        /* should be error */
        break;
     }
+    /* The action may have been blasted if the unit was wrecked, 
+    so we use latest_action instead. */
     Dprintf("%s action %s result is %s, %d acp left\n",
-           unit_desig(unit), action_desig(action), hevtdefns[rslt].name,
+           unit_desig(unit), action_desig(latest_action), hevtdefns[rslt].name,
            (unit->act ? unit->act->acp : -9999));
-    if (unit->plan) {
+    /* Not sure what to do if the action was blasted, so we also test 
+    that it still exists. In reality act and plan are blasted together, 
+    so this test may be redundant. Note: using latest_action will not 
+    work here since it changes all the time. */
+    if (unit->plan
+        && unit->act) {
        unit->plan->lastaction = *action;
        unit->plan->lastresult = rslt;
     }
@@ -2276,7 +4613,7 @@ action_desc_from_list(Side *side, Obj *lis, Unit *unit, Action *action,
            strcat(buf, c_string(item));
        } else if (symbolp(item)) {
            symname = c_string(item);
-           if (strcmp(symname, "actor") == 0) {
+           if (strcmp(symname, "unit") == 0) {
                sprintf(buf+strlen(buf), "%s", unit_handle(side, unit));
            } else if (strcmp(symname, "actee") == 0) {
                if (action->actee == unit->id)
@@ -2306,6 +4643,8 @@ play_action_movies(Unit *unit, Action *action)
     char *soundname;
     Obj *rest, *head, *parms, *msgdesc;
 
+    if (!should_play_movies())
+      return;
     for_all_list(g_action_movies(), rest) {
        head = car(rest);
        if (consp(head)
@@ -2367,47 +4706,127 @@ play_action_movies(Unit *unit, Action *action)
 int
 can_have_enough_acp(Unit *unit, int acp)
 {
-    int u = unit->type, maxacp, minacp;
+    if (!type_can_have_enough_acp(unit->type, acp)) {
+       if (acp < new_acp_for_turn(unit))
+         return TRUE;
+    }
+    else
+      return TRUE;
+    return FALSE;
+}
+
+int
+type_can_have_enough_acp(int u, int acp)
+{
+    int maxacp, minacp;
 
     /* Acp-independent units always have enough acp. */
-    if (acp_indep(unit))
+    if (u_acp_independent(u))
        return TRUE;
-
+    /* Else determine the basic ACP for the unit. */
     maxacp = u_acp(u);
     if (u_acp_turn_max(u) >= 0)
       maxacp = min(maxacp, u_acp_turn_max(u));
     maxacp = (u_acp_max(u) < 0 ? maxacp : u_acp_max(u));
     minacp = u_acp_min(u);
-    return (maxacp - acp >= minacp);
+    return (maxacp + u_free_acp(u) - acp >= minacp);
 }
 
 int
 has_enough_acp(Unit *unit, int acp)
 {
-    /* Acp-independent units always have enough acp. */
-    if (acp_indep(unit))
-       return TRUE;
+    int u = unit->type;
 
-    if (unit->act == NULL)
+    /* ACP-indep units always have enough ACP. */
+    if (acp_indep(unit))
+      return TRUE;
+    /* If the ACP required is 0, then allow the action. */
+    if (!acp)
+      return TRUE;
+    /* If an unit cannot act, then it cannot have enough ACP. */
+    if (!unit->act)
       return FALSE;
-    return ((unit->act->acp - acp) >= u_acp_min(unit->type));
+    return ((unit->act->acp + u_free_acp(u) - acp) >= u_acp_min(unit->type));
 }
 
-/* This is true iff the unit has enough of each sort of supply to act. */
+/* What is the maximum ACP that can be gained from being on any terrain
+   at night? */
+int
+type_max_night_acp_from_any_terrains(int u)
+{
+    int t = NONTTYPE, u3 = NONUTYPE;
+    int acp = 0, maxacp = 0;
+
+    if (!cache__type_max_night_acp_from_any_terrains) {
+       cache__type_max_night_acp_from_any_terrains = 
+         (int *)xmalloc(numutypes * sizeof(int));
+       for_all_unit_types(u3) {
+           for_all_terrain_types(t) {
+               if (t_is_cell(t) /* || connector || coating */) {
+                   acp = ut_night_adds_acp(u3, t);
+                   maxacp = max(acp, maxacp);
+               }
+           }
+           cache__type_max_night_acp_from_any_terrains[u3] = maxacp;
+       }
+    }
+    return cache__type_max_night_acp_from_any_terrains[u];
+}
 
+/* What is the maximum ACP that can be gained from having any occupant? */
+/* (To do this calculation truthfully, we need to use a knapsack algorithm,
+    because it may be that some combination of occ types yields the best
+    results. Nonetheless, the function, in its current form, at least tells
+    us whether or not any occ type will boost the ACP.) */
 int
-has_supply_to_act(Unit *unit)
+type_max_acp_from_any_occs(int u)
 {
-    int m;
+    int u2 = NONUTYPE, u3 = NONUTYPE;
+    int acp = 0, maxacp = 0;
 
-    for_all_material_types(m) {
-       if (unit->supply[m] < um_to_act(unit->type, m))
-         return FALSE;
+    if (!cache__type_max_acp_from_any_occs) {
+       cache__type_max_acp_from_any_occs = (int *)xmalloc(numutypes * 
+                                                          sizeof(int));
+       for_all_unit_types(u3) {
+           for_all_unit_types(u2) {
+               acp = uu_occ_adds_acp(u3, u2);
+               if (acp) {
+                   if (type_can_occupy_empty_type(u2, u3))
+                       maxacp = max(acp, maxacp);
+               }
+           }
+           cache__type_max_acp_from_any_occs[u3] = maxacp;
+       }
     }
-    return TRUE;
+    return cache__type_max_acp_from_any_occs[u];
+}
+
+/* What is the maximum ACP that an unit type can have? */
+int
+type_max_acp(int u)
+{
+    int u3 = NONUTYPE;
+    int acp = 0;
+
+    if (!cache__type_max_acp) {
+       cache__type_max_acp = (int *)xmalloc(numutypes * sizeof(int));
+       for_all_unit_types(u3) {
+           if (u_acp_max(u3) >= 0) {
+               cache__type_max_acp[u3] = u_acp_max(u3);
+               continue;
+           }
+           acp = u_acp(u3);
+           acp += type_max_night_acp_from_any_terrains(u3);
+           acp += type_max_acp_from_any_occs(u3);
+           /* (Should consider multiplicative effects.) */
+           cache__type_max_acp[u3] = acp;
+       }
+    }
+    return cache__type_max_acp[u];
 }
 
-/* Make the consumed acp disappear, but not go below the minimum possible. */
+//! Make the consumed acp disappear, but not go below the minimum possible.
+/*! \note u_free_acp does not need to be explicitly considered here. */
 
 void
 use_up_acp(Unit *unit, int acp)
@@ -2416,14 +4835,14 @@ use_up_acp(Unit *unit, int acp)
 
     /* This can sometimes be called on dead or non-acting units,
        so check first. */
-    if (alive(unit) && unit->act && acp > 0) {
+    if (alive(unit) && !u_acp_independent(unit->type) && unit->act && acp > 0) {
        oldacp = unit->act->acp;
        newacp = oldacp - acp;
        acpmin = u_acp_min(unit->type);
        unit->act->acp = max(newacp, acpmin);
        /* Maybe modify the unit's display. */
        if (oldacp != unit->act->acp) {
-               update_unit_acp_display(unit->side, unit, TRUE);
+           update_unit_acp_display(unit->side, unit, TRUE);
        }
     }
 }
@@ -2436,7 +4855,7 @@ construction_possible(int u2)
     int u;
 
     for_all_unit_types(u) {
-       if (uu_acp_to_create(u, u2) > 0
+       if (could_create(u, u2)
            && uu_tp_max(u, u2) >= uu_tp_to_build(u, u2))
          return TRUE;
     }
@@ -2453,7 +4872,7 @@ any_construction_possible(void)
        any_construction = FALSE;
        for_all_unit_types(u) {
            for_all_unit_types(u2) {
-               if (uu_acp_to_create(u, u2) > 0) {
+               if (could_create(u, u2)) {
                    any_construction = TRUE;
                    return any_construction;
                }
@@ -2477,8 +4896,10 @@ storage_possible(int m)
                /* Skip utypes that cannot store m. */
                if (!um_storage_x(u, m))
                    continue;
-               /* This utype will give m to a treasury if it exists. */
-               if (um_gives_to_treasury(u, m)) {
+               /* This utype will give m to a treasury if it exists,
+               but might not give ALL in backdrop model 1. */
+               if (um_gives_to_treasury(u, m)
+                   && (g_backdrop_model() != 1)) {
                        /* Test if all sides that can have this unit also
                        have a treasury that will recieve m. */
                        for_all_sides(side) {
@@ -2525,7 +4946,7 @@ action_desig(Action *act)
     if (act->type == ACTION_NONE)
       return "[]";
     if (actiondesigbuf == NULL)
-      actiondesigbuf = xmalloc(BUFSIZE);
+      actiondesigbuf = (char *)xmalloc(BUFSIZE);
     str = actiondesigbuf;
     sprintf(str, "[%s", actiondefns[act->type].name);
     slen = strlen(actiondefns[act->type].argtypes);