]> granicus.if.org Git - xconq/blobdiff - kernel/run.c
commits for 7.5.0 pre-release tarball
[xconq] / kernel / run.c
index b4970af5522df9b6566687a22ce1e636526cd703..4d3a480dd463f8b1a92c482e53bf754c73753a7e 100644 (file)
@@ -12,31 +12,18 @@ any later version.  See the file COPYING.  */
 #include "kernel.h"
 #include "kpublic.h"
 
-/* This is for storing basic stuff about the most recently executed
-   action. */
+/* This is for storing the most recently executed action. */
 
-typedef struct a_action_record {
-    Unit *actor;               /* Pointer to the actor if it still exists. */
-    short x, y, z;             /* Actor's location at the time of action. */
-    ActionType type;           /* Type of action. */
-    HistEventType result;      /* Its result. */               
-} ActionRecord;
+Action *latest_action = NULL;
 
-static ActionRecord *latest_action = NULL;
+/* The last known position of the latest actor. */
 
-int latest_action_x, latest_action_y;
-
-/* Functions in run2.c, only called from this file. */
-
-extern void run_people(void);
-extern void run_advanced_units(void);
-extern void run_turn_start(void);
-extern void run_restored_turn_start(void);
-extern void run_turn_end(void);
+int latest_action_x;
+int latest_action_y;
 
 static void compose_actionvectors(void);
 static void init_movement(void);
-static void clear_task_outcomes(void);
+static void clear_aicontrolled_outcomes(void);
 static int move_some_units(int lim);
 static int side_move_some_units(Side *side, int lim);
 static int unit_still_acting(Unit *unit);
@@ -57,13 +44,16 @@ static void auto_pick_new_plan(Unit *unit);
 
 /* Advanced unit support. */
 
+extern void allocate_used_cells(Unit *unit);   /* Used in move.c */
+
 static void run_side_research(void);
 static void run_population(Unit *unit);
-static void run_construction(Unit *unit);
 static void run_research(Unit *unit);
-static void allocate_used_cells(Unit *unit);
 static int auto_pick_new_build_task(Unit *unit);
 
+static void take_all_from_treasury(Unit *unit);
+static void give_all_to_treasury(Unit *unit);
+
 /* Priority of sides that are now moving. */
 
 int curpriority;
@@ -233,7 +223,7 @@ run_game(int maxactions)
     need_ai_planning = FALSE;
     /* Make sure the action record is allocated. */
     if (latest_action == NULL)
-      latest_action = (ActionRecord *) xmalloc(sizeof(ActionRecord));
+      latest_action = (Action *) xmalloc(sizeof(Action));
     if (beforestart) {
        /* If we haven't started yet, see if it's time. */
        test_for_game_start();
@@ -259,6 +249,13 @@ run_game(int maxactions)
            cur_unit_priority = highest_unit_priority;
            compose_actionvectors();
            update_all_progress_displays("", -1);
+           /* Make sure the research window is popped up for sides
+           without a research task. */
+           for_all_sides(side) {
+                   if (side_has_display(side)) {
+                       update_research_display(side);
+                   }
+           }
            /* Game might have been ended by new turn init. */
            test_for_game_end();
            if (endofgame) {
@@ -300,7 +297,7 @@ run_game(int maxactions)
               one advance each turn. */
            run_side_research();
            if (last_taskexecs > 0)
-             clear_task_outcomes();
+             clear_aicontrolled_outcomes();
            /* Move some units around. */
            numacted += move_some_units(maxactions);
            if (cur_unit_priority < lowest_unit_priority) {
@@ -391,7 +388,7 @@ run_game(int maxactions)
    problems.  This generates massive amounts of saved data very
    quickly, be careful using it! */
 
-static int save_run_states = 1;
+static int save_run_states = 0;
 
 void
 save_run_state(char *suffix)
@@ -553,7 +550,7 @@ exceeded_rt_per_turn(void)
 int
 units_still_acting(Side *side)
 {
-    int curactor;
+    int curactor, a;
     Unit *unit;
     UnitVector *av = side->actionvector;
 
@@ -575,10 +572,19 @@ units_still_acting(Side *side)
     /* Try not to let a side not be researching something. */
     if (numatypes > 0
        && g_side_can_research()
-       && side->research_topic == NOADVANCE
-       /* (should also test that any advances are available) */
-       )
-      return TRUE;
+       && side->research_topic == NOADVANCE) {
+       /* Check that the side can research something. */
+       for_all_advance_types(a) {
+           if (side_can_research(side, a)) {
+               /* Popup the research dialog if the side has a 
+                  display. */
+               if (side_has_display(side)) {
+                   update_research_display(side);
+               }
+               return TRUE;
+           }
+       }
+    }
     return FALSE;
 }
 
@@ -647,8 +653,8 @@ compose_actionvectors(void)
        clear_unit_vector(side->actionvector);
        for_all_side_units(side, unit) {
            if (unit->act 
-               && (unit->act->initacp > 0
-                     || acp_indep(unit))) {
+               && ((unit->act->initacp > 0)
+                   || acp_indep(unit))) {
                priority = unit_priority(unit);
                if (priority == cur_unit_priority) {
                    side->actionvector =
@@ -656,6 +662,17 @@ compose_actionvectors(void)
                    /* Clear any delay flags. */
                    if (unit->plan)
                      unit->plan->delayed = FALSE;
+                   /* Clear any busy flags. */
+                   if (unit->busy) {
+                       /* The busy flag should have been cleared when the unit 
+                          moved. If it is still set, it could mean that a 
+                          broadcasted action was never received by the host 
+                          and rebroadcasted. */
+                       Dprintf(
+"Busy flag still set for %s at start of turn.\n", 
+                               unit_desig(unit));
+                       unit->busy = FALSE;
+                   }
                }
            }
            if (unit->plan) {
@@ -694,7 +711,7 @@ unit_priority(Unit *unit)
 }
 
 static void
-clear_task_outcomes(void)
+clear_aicontrolled_outcomes(void)
 {
     Unit *unit;
 
@@ -705,7 +722,7 @@ clear_task_outcomes(void)
        ai-controlled units. */
     for_all_units(unit) {
        if (ai_controlled(unit))
-         unit->plan->last_task_outcome = TASK_UNKNOWN;
+         clear_task_outcome(unit);
     }
 }
 
@@ -736,7 +753,8 @@ move_some_units(int lim)
 static int
 side_move_some_units(Side *side, int lim)
 {
-    int num, foundanytomove, curactor0, curactor, numdelayed;
+    int num, foundanytomove, curactor0, curactor, numcouldact = 0, numfollowing;
+    int numdelayed = 0;
     Unit *unit;
     UnitVector *av = side->actionvector;
 
@@ -754,11 +772,13 @@ side_move_some_units(Side *side, int lim)
       curactor0 = 0;
   try_again:
     foundanytomove = FALSE;
+    numcouldact = 0;
     numdelayed = 0;
+    numfollowing = 0;
     /* Iterate through all units in the action vector, starting with
        the "current" (most recently moved) unit. */
     /* Note that the action vector may get resized/reallocated as
-       units act (such as when a unit is capture), so we can't cache
+       units act (such as when a unit is captured), so we can't cache
        it into a local var here. */
     for (curactor = curactor0; curactor < side->actionvector->numunits;
         ++curactor) {
@@ -767,11 +787,18 @@ side_move_some_units(Side *side, int lim)
        Dprintf("Considering moving %s with plan %s\n",
                unit_desig(unit), plan_desig(unit->plan));
 #endif
+       /* If the unit cannot act anymore, then skip it forthwith. */
+       if (!has_acp_left(unit))
+         continue;
        /* Count and skip over deliberately delayed units. */
        if (unit->plan && unit->plan->delayed) {
+           ++numcouldact;
            ++numdelayed;
            continue;
        }
+       /* Count the units which are in formations and can still act. */
+       if (unit->plan && unit->plan->formation && unit_still_acting(unit))
+         ++numfollowing;
        /* Default AIs to the slow play rate. */
        current_play_rate = slow_play_rate;
        /* AIs should play as fast as possible if turns are sequential,
@@ -784,7 +811,8 @@ side_move_some_units(Side *side, int lim)
            && unit->side->ingame 
            && !unit->side->finishedturn
            && has_acp_left(unit)
-           && (unit->plan && unit->plan->formation)) {
+           && (unit->plan && unit->plan->formation
+               && !is_in_formation(unit))) {
            num += move_one_unit_multiple(unit, lim - num);
            foundanytomove = TRUE;
        }
@@ -799,16 +827,16 @@ side_move_some_units(Side *side, int lim)
            num += move_one_unit_multiple(unit, lim - num);
            foundanytomove = TRUE;
        }
+       /* Execute any tasks or pending actions that the unit has. */
        if (unit_still_acting(unit)
            && (unit->plan && !unit->plan->waitingfortasks)) {
            num += move_one_unit_multiple(unit, lim - num);
            foundanytomove = TRUE;
        } else if (unit_still_acting_no_plan(unit)) {
-           num += move_one_unit_multiple(unit, lim - num);
-           foundanytomove = TRUE;
-       }
-       if (unit_still_acting(unit)) {
-           foundanytomove = TRUE;
+           if (has_pending_action(unit) || (unit->plan && unit->plan->tasks)) {
+               num += move_one_unit_multiple(unit, lim - num);
+               foundanytomove = TRUE;
+           }
        }
        /* See if we exceeded the limit on the number of moves that
           we're allowed to do this time.  If so, memorize the unit
@@ -827,6 +855,8 @@ side_move_some_units(Side *side, int lim)
            }
            return num;
        }
+       /* Increment the count of units that could act. */
+       ++numcouldact;
     }
     /* If started in middle of list, and didn't find anything to do,
        rescan from beginning. */
@@ -834,8 +864,13 @@ side_move_some_units(Side *side, int lim)
        curactor0 = 0;
        goto try_again;
     }
-    /* Now clear all the delay flags and rescan the action vector. */
-    if (!foundanytomove && numdelayed > 0) {
+    /* See if any at all could act, and let the 'run_game' logic deal 
+       with it. */
+    if (!numcouldact) 
+      return 0;
+    /* Clear all the delay flags and rescan the action vector, if no other 
+       non-delayed actors left. */
+    if (!foundanytomove && (0 >= (numcouldact - numdelayed))) {
        av = side->actionvector;
        for (curactor = 0; curactor < av->numunits; ++curactor) {
            unit = unit_in_vector(av, curactor);
@@ -848,6 +883,16 @@ side_move_some_units(Side *side, int lim)
     if (!foundanytomove && 0 /* not at max priority */) {
        /* (should recompose action vector for new unit priority?) */
     }
+    /* Set waiting-for-tasks to true for any units in a formation, which 
+       still are acting (have ACP, are not skipped, etc...). */
+    if (numfollowing > 0) {
+       for (curactor = 0; curactor < av->numunits; ++curactor) {
+           unit = unit_in_vector(av, curactor);
+           if (unit->plan && unit->plan->formation 
+               && unit_still_acting(unit) && !(unit->plan->tasks))
+             set_waiting_for_tasks(unit, TRUE);
+       }
+    }
     side->curactor_pos = 0;
     side->curactor = NULL;
     side->curactor_id = 0;
@@ -868,19 +913,18 @@ unit_still_acting(Unit *unit)
       return FALSE;
     if (!has_acp_left(unit))
       return FALSE;
-       if (unit->plan
-            && (unit->plan->asleep
-               || unit->plan->reserve))
-               return FALSE;
-       /* Conditions that require further action provided
-       that it was not ruled out above. */
-       if (acp_indep(unit)
-            && can_build(unit)
-            && !unit->buildingdone)
-               return TRUE;
-       if (has_pending_action(unit))
-               return TRUE;
-       if (unit->plan)
+    if (unit->plan
+        && (unit->plan->asleep
+           || unit->plan->reserve))
+      return FALSE;
+    /* Conditions that require further action provided
+       that it was not ruled out above. */
+    // HACK: We need to check action allowance flags rather than doing this.
+    if (acp_indep(unit))
+      return TRUE;
+    if (has_pending_action(unit))
+      return TRUE;
+    if (unit->plan)
       return TRUE;
     return FALSE;
 }
@@ -899,9 +943,8 @@ unit_still_acting_no_plan(Unit *unit)
       return FALSE;
     /* Conditions that require further action provided that it was not
        ruled out above. */
-    if (acp_indep(unit)
-       && can_build(unit)
-       && !unit->buildingdone)
+    // HACK: We need to check action allowance flags rather than doing this.
+    if (acp_indep(unit))
       return TRUE;
     if (has_pending_action(unit))
       return TRUE;
@@ -914,7 +957,7 @@ unit_still_acting_no_plan(Unit *unit)
 static int
 move_one_unit_multiple(Unit *unit, int lim)
 {
-    int num = 0, buzz = 0, acp1;
+    int num = 0, buzz = 0, acp1, i;
     int rslt;
 
     /* If unit is incapable of acting right now, get out of here. */
@@ -923,60 +966,62 @@ move_one_unit_multiple(Unit *unit, int lim)
             && !acp_indep(unit)))
       return 0;
     acp1 = unit->act->acp;
-    while (is_active(unit)
-          && has_acp_left(unit)
-          && ((unit->plan
-               && !unit->plan->asleep
-               && !unit->plan->reserve
-               && !unit->plan->delayed
-               )
+    while (is_active(unit) && has_acp_left(unit)
+          && ((unit->plan && !unit->plan->asleep
+               && !unit->plan->reserve && !unit->plan->delayed)
               || has_pending_action(unit))
           && num < lim
           && buzz < lim) {
-#if 1 /* enable for more intense debugging */
+#if (1) /* enable for more intense debugging */
        Dprintf("  Moving %s (%d/%d, buzz %d) with plan %s\n",
                unit_desig(unit), num, lim, buzz, plan_desig(unit->plan));
 #endif
+        /* Unit may be dead, and thus cannot complete the rest of its actions.
+           Although kill_unit removes the unit from action vector, we may 
+           not have had a chance to go back up to side_move_some_units to 
+           discover this.
+           Tell side_move_some_units to go find another unit to move.
+           (Note that execute_action does check whether the unit is alive 
+           or not, but why check in each called function when we can 
+           nip things in the bud right here, right now? None of the 
+           called functions can reasonably do anything with a dead unit.)
+        */
+        if (!alive(unit)) {
+            Dprintf("Tried to act with dead unit, %s!\n", unit_desig(unit));
+            break;
+        }
+#if (0)
        /* Skip over AI-run units that have executed a task during
           this run step, so that the AI gets a chance to react to the
           result. */
-       if (unit->plan
+       if (ai_controlled(unit)
            && unit->plan->last_task_outcome != TASK_UNKNOWN
-           && unit->plan->last_task_outcome != TASK_PREPPED_ACTION
-           && side_has_ai(unit->side)
-           && !unit->plan->aicontrol)
+           && unit->plan->last_task_outcome != TASK_PREPPED_ACTION)
          break;
-       /* Do acp-independent construction. */
-       if (acp_indep(unit)) {
-           if (!unit->buildingdone) {
-               run_construction(unit);
-               gamestatesafe = FALSE;
-           }       
-           /* Sides without ai never proceed beyond the first unit in the
-           actionvector if we return 1 here. Why? */
-           return 0;
-       } else if (has_pending_action(unit)) {
-
-           /* Save this info now in case the actor dies etc. */
+#endif
+       if (has_pending_action(unit)) {
+           /* Save the action now in case the actor dies or wrecks. */
            latest_action->type = unit->act->nextaction.type;
-           latest_action->actor = unit;
-           latest_action->x = latest_action_x = unit->x;
-           latest_action->y = latest_action_y = unit->y;
-           latest_action->z = unit->z;
+           for (i = 0; i < MAXACTIONARGS; ++i) {
+               latest_action->args[i] = unit->act->nextaction.args[i];
+           }
+           latest_action->actee = unit->act->nextaction.actee;
+           latest_action->next = unit->act->nextaction.next;
 
+           /* Also save the latest known position of the actor. */
+           latest_action_x = unit->x;
+           latest_action_y = unit->y;
            /* Execute the action directly. */
            rslt = execute_action(unit, &(unit->act->nextaction));
-           
-           /* Save the result. */
-           latest_action->result = rslt;
-                   
            /* Trigger ai reaction for certain actions. */ 
-           need_ai_action_reaction = action_reaction_needed(latest_action->type, rslt);
-
+           need_ai_action_reaction = 
+               action_reaction_needed(latest_action->type, rslt);
            /* Clear the action.  Note that the unit might have changed
               to a non-acting type, so we have to check for act struct. */
            if (unit->act)
              unit->act->nextaction.type = ACTION_NONE;
+           /* Also clear the busy flag. */
+           unit->busy = FALSE;
            /* In any case, the game state is irrevocably altered. */
            gamestatesafe = FALSE;
            ++num;
@@ -997,10 +1042,18 @@ move_one_unit_multiple(Unit *unit, int lim)
                gamestatesafe = FALSE;
                ++buzz;
            }
+#if 0      
+           /* This replanning caused buzzing. It is sufficient to call 
+               ai_decide_plan at the start of each turn and after 
+               force_replan. Possibly, we should test for an empty task queue 
+               here, and replan in that case only. However, the AI works fine 
+               without any replanning. */
+
            /* Flag so that we run AI code in the near future (after
               run_game exits). */
            if (side_has_ai(unit->side))
              need_ai_planning = TRUE;
+#endif
            /* Get out of here if unit is set not to do anything on
               its own. */
            if (unit->plan->waitingfortasks
@@ -1082,12 +1135,13 @@ finish_turn(Side *side)
        nextpriority = 9999;
        for_all_sides(side2) {
            if (!side2->finishedturn
-/*             && side2->priority > curpriority */
+               /* && side2->priority > curpriority */
                && side2->priority < nextpriority) {
                nextpriority = side2->priority;
            }
            if (!side2->finishedturn && side2->priority < curpriority)
-             run_warning("%s not finished, but priority is %d, less than current %d",
+             run_warning(
+"%s not finished, but priority is %d, less than current %d",
                          side_desig(side2), side2->priority, curpriority);
        }
        if (nextpriority > curpriority)
@@ -1198,6 +1252,10 @@ end_the_game(void)
            update_turn_display(side, TRUE);
            /* (should update side's view of all sides?) */
            update_side_display(side, side, TRUE);
+           /* Update legends and their positions as new terrain comes into view. */
+           place_legends(side);
+           /* Redraw legends in new positions. */
+           update_area_display(side);
        }
     }
     dump_statistics();
@@ -1211,8 +1269,10 @@ end_the_game(void)
 void
 run_side_research(void)
 {
-    int a, m, consump, maxrp, rp, amt;
+    int a, m, consump, amt, totalweight = 0;
+    long maxrp, rp; 
     Side *side;
+    Obj *choice = NULL, *nextgoal = NULL;
 
     /* No research if there are no advances. */
     if (numatypes == 0)
@@ -1232,7 +1292,7 @@ run_side_research(void)
        /* Our wise men are waiting for something to do. */
        if (side->research_topic == NOADVANCE) {
            if (side_has_ai(side)) {
-               ;
+               /* Do nothing. ai_plan_research will pick a new advance. */
            } else if (side->autoresearch) {
                auto_pick_side_research(side);
            }
@@ -1243,7 +1303,7 @@ run_side_research(void)
        a = side->research_topic;
        /* Compute the maximum number of rps that our material limits
           allow us to add. */
-       maxrp = 999999;
+       maxrp = VARHI;
        for_all_material_types(m) {
            consump = am_consumption_per_rp(a, m);
            if (consump > 0) {
@@ -1254,48 +1314,92 @@ run_side_research(void)
                maxrp = min(maxrp, rp);
            }
        }
-       /* Add 1 rp per turn by default (Why?). */
-       if (maxrp == 999999)
-         maxrp = 1;
+       /* If research is not limited by materials something is wrong. */
+       if (maxrp == VARHI) {
+           run_error("research is not limited by materials");
+       }
        /* Don't spend more than needed to complete the advance! */
        maxrp = min(maxrp, a_rp(a) - side->advance[a]);
-       side->advance[a] += maxrp;
-       /* Make sure the research window is updated. */
-       if (side_has_display(side)) {
-           update_side_display(side, side, TRUE);
-       }
-       if (side->advance[a] >= a_rp(a)) {
-           side->advance[a] = DONE;
-           /* Update research and build vectors. */
-           update_canresearch_vector(side);
-           update_canbuild_vector(side);
-           notify(side, "Your wise men discover %s!", a_type_name(a));
-           side->research_topic = NOADVANCE;
-           if (side_has_ai(side)) {
-               ;
-           } else if (side->autoresearch) {
-               auto_pick_side_research(side);
+       /* Only proceed if we are still doing some research. */
+       if (maxrp > 0) {
+           side->advance[a] += maxrp;
+           /* Make sure the research window is updated. */
+           if (side_has_display(side)) {
+               update_research_display(side);
            }
-       }
-       /* Consume the materials. */
-       for_all_material_types(m) {
-           consump = am_consumption_per_rp(a, m);
-           if (consump > 0) {
-               amt = maxrp * consump;
-               side->treasury[m] -= amt;
+           if (side->advance[a] >= a_rp(a)) {
+               side->advance[a] = DONE;
+               /* Update research and build vectors. */
+               update_canresearch_vector(side);
+               update_canbuild_vector(side);
+               /* (TODO: Replace "Your wise men discover" with a custom 
+                   string.) */
+               notify(side, "Your wise men discover %s!", a_type_name(a));
+               side->research_topic = NOADVANCE;
+               nextgoal = lispnil;
+               choice = lispnil;
+               if (a == side->research_goal) {
+                   side->research_goal = NONATYPE;
+                   nextgoal = a_ai_next_goal(a);
+               }
+               if (nextgoal != lispnil) {
+                   if (consp(nextgoal)) {
+                       choice = choose_side_research_goal_from_weighted_list(
+                                   nextgoal, &totalweight, side);
+                   }
+                   else {
+                       choice = eval(nextgoal);
+                   }
+               }
+               if (choice != lispnil) {
+                   if (symbolp(choice))
+                     choice = eval_symbol(choice);
+                   if (atypep(choice)) {
+                       if (is_advance_type(c_number(choice)))
+                         side->research_goal = c_number(choice);
+                       else
+                         run_warning(
+"Invalid research goal provided by advance, %s, upon reserach completion",
+                                     a_type_name(a));
+                   }
+                   else
+                     run_warning(
+"Invalid research goal provided by advance, %s, upon reserach completion",
+                                 a_type_name(a));
+               }
+               if (side_has_ai(side)) {
+                   /* Do nothing. ai_plan_research will pick a new advance. */
+               } else if (side->autoresearch) {
+                   auto_pick_side_research(side);
+               }
+               /* Make sure the research window is updated. */
+               if (side_has_display(side)) {
+                   update_research_display(side);
+               }
+           }
+           /* Consume the materials. */
+           for_all_material_types(m) {
+               consump = am_consumption_per_rp(a, m);
+               if (consump > 0) {
+                   amt = maxrp * consump;
+                   side->treasury[m] -= amt;
+               }
            }
        }
     }
 }
 
 /*     Advanced unit and advance code for Xconq.
-       Copyright (C) 1998 Hans Ronne. */
+       Copyright (C) 1998 Hans Ronne.
+       Copyright (C) 2004 Eric A. McDonald.
+*/
 
 void
 update_canresearch_vector(Side *side)
 {
     int a, a2;
 
+    update_side_research_goal_availability(side);
     for_all_advance_types(a) {
        /* We can't research advances that are already done. */
        if (has_advance(side, a)) {
@@ -1309,11 +1413,42 @@ update_canresearch_vector(Side *side)
                side->canresearch[a] = FALSE;
                break;
            }
+           if (aa_precludes(a2, a) && has_advance(side, a2)) {
+               side->canresearch[a] = FALSE;
+               break;
+           }
        }
     }
 }
 
-/* Call this whenever the list of buildable types changes. */
+void
+update_side_research_goal_availability(Side *side)
+{
+    int updated = TRUE;
+    int a = NONATYPE, a2 = NONATYPE;
+
+    assert_error(side, "Attempted to access a NULL side");
+    while (updated) {
+       updated = FALSE;
+       for_all_advance_types(a) {
+           if (side->research_precluded[a])
+             continue;
+           for_all_advance_types(a2) {
+               if ((aa_precludes(a2, a) && has_advance(side, a2)) 
+                   || (side->research_precluded[a2] 
+                       && aa_needed_to_research(a, a2))) {
+                       side->research_precluded[a] = TRUE;
+                       updated = TRUE;
+                       break;
+                   }
+           } /* a2 */
+           if (updated)
+             break;
+       } /* a */
+    } /* while updated */
+}
+
+/* Call this whenever the list of buildable/developable types changes. */
 
 void
 update_canbuild_vector(Side *side)
@@ -1324,36 +1459,44 @@ update_canbuild_vector(Side *side)
        /* Start out optimistic, then following code may disallow some
            types. */
        side->canbuild[u] = TRUE;
+       side->candevelop[u] = TRUE;
        /* Units with zero cp are unbuildable by definition. */
        if (u_cp(u) == 0) {
            side->canbuild[u] = FALSE;
+           side->candevelop[u] = FALSE;
            continue;
        }
        /* First test if this unit type is at all allowed on our side. */
        if (!type_allowed_on_side(u, side)) {
            side->canbuild[u] = FALSE;
+           side->candevelop[u] = FALSE;
            continue;
        }
        /* Then test if we have the required tech to both build and own 
           this type. */
        if (u_tech_to_build(u) > 0) {
+           /* Don't "continue" in this group, because we need to set
+              both build and develop cases correctly. */
            if (side->tech[u] < u_tech_to_own(u)
-               || side->tech[u] < u_tech_to_build(u)) {
-               side->canbuild[u] = FALSE;
-               continue;
-           }
+               || side->tech[u] < u_tech_to_build(u))
+             side->canbuild[u] = FALSE;
+           if (side->tech[u] >= u_tech_max(u))
+             side->candevelop[u] = FALSE;
        }
+       /* Consider the effect of advances on ability to build/develop. */
        if (numatypes > 0) {
            /* Test for an obsoleting advance. */
            a = u_obsolete(u);
            if (a != NONATYPE && has_advance(side, a)) {
                side->canbuild[u] = FALSE;
+               side->candevelop[u] = FALSE;
                continue;
            }
            /* Then test for required advances. */
            for_all_advance_types(a) {
                if (ua_needed_to_build(u, a) && !has_advance(side, a)) {
                    side->canbuild[u] = FALSE;
+                   side->candevelop[u] = FALSE;
                    break;
                }
            }
@@ -1361,41 +1504,61 @@ update_canbuild_vector(Side *side)
     }
 }
 
-void take_all_from_treasury(Unit *unit);
-
 void
+update_cancarry_vector(Side *side)
+{
+    Unit *unit;
+    int u;
+
+    for_all_unit_types(u) {
+       side->cancarry[u] = FALSE;
+       for_all_side_units(side, unit) {
+           if (mobile(unit->type)
+               && could_carry(unit->type, u)) {
+               side->cancarry[u] = TRUE;
+               break;
+           }
+       }
+    }
+}
+
+static void
 take_all_from_treasury(Unit *unit)
 {
-       int m, amount;
+    int m, amount;
        
-         /* Borrow materials from treasury if it exists. */
-       for_all_material_types(m) {
-               if (side_has_treasury(unit->side, m)
-                  && um_takes_from_treasury(unit->type, m)) {
-                       amount= min(unit->side->treasury[m], 
-                                          /* Don't exceed the unit's storage capacity. */
-                                           um_storage_x(unit->type, m) - unit->supply[m]);
-                       unit->supply[m] += amount;
-                       unit->side->treasury[m] -= amount;                      
-               }
+    /* Borrow materials from treasury if it exists. */
+    for_all_material_types(m) {
+       if (side_has_treasury(unit->side, m)
+           && um_takes_from_treasury(unit->type, m)) {
+           /* Don't exceed the unit's storage capacity unless there is no
+               capacity, in which case take the lot. */
+           if (um_storage_x(unit->type, m) <= 0)
+               amount = unit->side->treasury[m];
+           else
+               amount = min(unit->side->treasury[m], 
+                            um_storage_x(unit->type, m) - unit->supply[m]);
+           unit->supply[m] += amount;
+           unit->side->treasury[m] -= amount;                  
        }
+    }
 }
 
-void give_all_to_treasury(Unit *unit);
-
-void
+static void
 give_all_to_treasury(Unit *unit)
 {
-       int m;
+    int m, amount;
        
-       /* Return all unused materials to treasury. */
-       for_all_material_types(m) {
-               if (side_has_treasury(unit->side, m)
-                  && um_gives_to_treasury(unit->type, m)) {
-                       unit->side->treasury[m] += unit->supply[m];
-                       unit->supply[m] = 0;                    
-               }
+    /* Return all unused materials to treasury. */
+    for_all_material_types(m) {
+       if (side_has_treasury(unit->side, m)
+           && um_gives_to_treasury(unit->type, m)) {
+           amount = min(unit->supply[m], 
+                        g_treasury_size() - unit->side->treasury[m]);
+           unit->side->treasury[m] += amount;
+           unit->supply[m] -= amount;          
        }
+    }
 }
 
 /* Called from run_turn_start. */
@@ -1407,10 +1570,12 @@ run_people()
 
 /* Main city emulating routine. Called by run_turn_start in run2.c. */
 
+static int *rau_incrs;
+
 void
 run_advanced_units()
 {
-    Unit *unit;
+    Unit *unit, *unit2;
                
     for_all_units(unit) {
        Side    *side;
@@ -1420,6 +1585,10 @@ run_advanced_units()
        if (!u_advanced(unit->type))
          continue;
 
+       /* Skip if this is an indep which cannot produce or consume materials. */
+       if (indep(unit) &! g_indepside_has_economy())
+         continue;
+
        /* Units still under construction or off-area can't do anything. */
        if (!completed(unit) || !in_play(unit))
          continue;
@@ -1433,9 +1602,6 @@ run_advanced_units()
        if (!nummtypes)
          continue;
 
-       if (!user_defined())
-         allocate_area_users();
-
        /* Make sure landuse is optimize before collecting materials. */
        allocate_used_cells(unit);
 
@@ -1445,6 +1611,7 @@ run_advanced_units()
        /* Collect materials from cells controlled by the city. */
        for_all_cells_within_reach(unit, x, y) {
            int m;
+           
            if (!inside_area(x, y))
                continue;
            if (user_at(x, y) == unit->id)
@@ -1464,33 +1631,45 @@ run_advanced_units()
           each turn. */
 
        for_all_material_types(m) {
-           Unit *unit2;
-
+           
            /* First compute additive effect of each occupant/facility. */
-           for_all_occupants(unit, unit2)
-             unit->production[m] += um_occ_add_production(unit2->type, m);
+           for_all_occupants(unit, unit2) {
+               if (is_active(unit2)) {
+                   unit->production[m] += um_occ_add_production(unit2->type, m);
+               }
+           }
            /* Then compute additive effect of each completed advance. */
            if (unit->side) {
                for_all_advance_types(a)
                  if (unit->side->advance[a] == DONE)
                    unit->production[m] += am_adv_add_production(a, m);
            }
+
            /* Then factor in multiplicative effect (in %) of each
                occupant/facility. */
-           for_all_occupants(unit, unit2)
-             unit->production[m] *= (float) um_occ_mult_production(unit2->type, m) / 100;
+           for_all_occupants(unit, unit2) {
+               if (is_active(unit2)) {
+                     unit->production[m] =
+                       (unit->production[m] * um_occ_mult_production(unit2->type, m)) / 100;
+               }
+           }
            /* Then factor in multiplicative effect (in %) of each
                completed advance. */
            if (unit->side) {
                for_all_advance_types(a)
                  if (unit->side->advance[a] == DONE)
-                   unit->production[m] *= (float) am_adv_mult_production(a, m) / 100;
+                   unit->production[m] =
+                     (unit->production[m] * am_adv_mult_production(a, m))
+                     / 100;
            }
+
            {
-               int m2, anyconversion = FALSE, incrs[MAXMTYPES], tot = 0;
+               int m2, anyconversion = FALSE, tot = 0;
 
                for_all_material_types(m2) {
-                   incrs[m2] = 0;
+                   if (rau_incrs == NULL)
+                     rau_incrs = (int *) xmalloc(nummtypes * sizeof(int));
+                   rau_incrs[m2] = 0;
                    if (mm_conversion(m, m2) > 0
                        && unit->side->c_rates != NULL
                        && unit->side->c_rates[m2] > 0) {
@@ -1503,20 +1682,37 @@ run_advanced_units()
                        if (mm_conversion(m, m2) > 0
                            && unit->side->c_rates != NULL
                            && unit->side->c_rates[m2] > 0) {
-                           incrs[m2] += unit->side->c_rates[m2];
+                           rau_incrs[m2] += unit->side->c_rates[m2];
                        }
                    }
                    for_all_material_types(m2) {
-                       if (incrs[m2] >= tot && unit->production[m] > 0) {
-                           incrs[m2] -= tot;
-                           unit->supply[m2] += 1;
+                       if (rau_incrs[m2] >= tot 
+                           && unit->production[m] > 0) {
+                           rau_incrs[m2] -= tot;
+                           unit->production[m2] += 1;
                            unit->production[m] -= 1;
                        }
                    }
                }
            }
-           /* Finally add production to unit supply. */
-           unit->supply[m] += unit->production[m];
+       }
+           /* Finally add production to unit supply. Check that we have room and 
+           transfer any excess materials to the treasury if possible. */
+       for_all_material_types(m) {
+           int space, amount;
+
+           space = um_storage_x(unit->type, m) - unit->supply[m];
+           if (unit->production[m] <= space) {
+               unit->supply[m] += unit->production[m];
+           } else {
+               unit->supply[m] = um_storage_x(unit->type, m);
+               amount = unit->production[m] - space;
+               if (side_has_treasury(unit->side, m)
+                   && um_gives_to_treasury(unit->type, m)) {
+                       amount = min(amount, g_treasury_size() - unit->side->treasury[m]);
+                       unit->side->treasury[m] += amount;
+               }
+           }
        }
        /* Growth or starvation. */
        run_population(unit);
@@ -1528,25 +1724,16 @@ run_advanced_units()
            allocate_used_cells(unit);
            /* Also reflect any changes of the city size text. */
            for_all_sides(side) {
-               if (side->see_all
-                   || side_sees_unit(side, unit) 
-                   || side_tracking_unit(side, unit)) {
-                   update_cell_display(side, unit->x, unit->y, UPDATE_ALWAYS);
+               if (side->see_all) {
+                   update_cell_display(side, unit->x, unit->y, 
+                                       UPDATE_ALWAYS);
+               } else if (side_sees_unit(side, unit) 
+                   || side_tracking_unit(side, unit)
+                   || cover(side, unit->x, unit->y) > 0) {
+                       see_cell(side, unit->x, unit->y);
                }
            }
        }
-
-#if 0          /* This is now done from the normal run code. */
-
-       /* Run acp-independent construction. */
-       if (acp_indep(unit))
-         run_construction(unit);
-       /* Do unit-based research. */
-       if (u_can_research(unit->type))
-         run_research(unit);
-
-#endif
-
     }
 }
 
@@ -1556,15 +1743,16 @@ run_advanced_units()
 int
 production_at(int x, int y, int m)
 {
-    int prod, c;
-
-    prod = tm_production(terrain_at(x, y), m);
-    /* Add bonuses for connection types. */
-    for_all_connection_types(c) {
-       if (aux_terrain_defined(c)
-           && any_connections_at(x, y, c)
-           && tm_production(c, m) > 0)
-         prod += tm_production(c, m);
+    int prod = 0, t2 = NONTTYPE;
+
+    prod = tm_prod_from_terrain(terrain_at(x, y), m);
+    /* Add bonuses for all aux terrain types. */
+    for_all_aux_terrain_types(t2) {
+       if (aux_terrain_defined(t2)
+           && aux_terrain_at(x, y, t2)
+           && (tm_prod_from_terrain(t2, m) > 0)) {
+           prod += tm_prod_from_terrain(t2, m);
+       }
     }
     return prod;
 }
@@ -1579,7 +1767,44 @@ run_population(Unit *unit)
     int a, m, u2;
     Side *side = unit->side;
 
-    /* First check if we have the required advances for the next size. */
+    /* If we have no people we are done. */
+    if (!g_people())
+        return;
+    /* Loot the treasury. */
+    take_all_from_treasury(unit);
+    /* Consume necessary materials (food) in proportion to unit size. */
+    for_all_material_types(m) {
+       unit->supply[m] -= unit->size * um_consumption_per_size(u, m);
+       if (unit->supply[m] < 0) {
+           /* Don't allow negative supply. */
+           unit->supply[m] = 0;
+           /* Trigger starvation. */
+           starved = TRUE;
+       }
+    }
+    /* Return remaining materials to treasury. */
+    give_all_to_treasury(unit);
+    /* Starvation! (Size Loss) */
+    if (starved && (unit->size > u_size_min(u))) {
+       /* Shrink size by one. */
+       unit->size -= 1;
+       /* Run warning. */
+       if (unit->size > 0) {
+           notify(side, "The people in %s are starving!",
+                  unit_handle(side, unit));
+       } else {
+           notify(side, "%s is no more. The people starved to death.", 
+                  unit_handle(side, unit));
+           kill_unit(unit, H_UNIT_STARVED);
+       }
+       /* Done with handling starvation. */
+       return;
+    }
+    /* Growth (Size Gain) */
+    /* First check if we have reached our max size. */
+    if (unit->size >= u_size_max(u)) 
+      return;
+    /* Then check if we have the required advances for the next size. */
     for_all_advance_types(a) {
        if (side->advance[a] != DONE 
            && ua_size_limit_without_adv(u, a) <= unit->size) {
@@ -1595,7 +1820,7 @@ run_population(Unit *unit)
            Unit *unit2;
 
            for_all_occupants(unit, unit2) {                    
-               if (unit2->type == u2) {
+               if (is_active(unit2) && unit2->type == u2) {
                    hasocc = TRUE;
                    break;
                }
@@ -1606,233 +1831,49 @@ run_population(Unit *unit)
                return;
            }
        }
-    }
-                                       
-    /* Loot the treasury. */
+    } 
+    /* Loot the treasury again, in case storage space was limiting before 
+       consumption. */
     take_all_from_treasury(unit);
-
-    /* Consume necessary materials (food) in proportion to unit size. */
-    for_all_material_types(m) {
-       unit->supply[m] -= unit->size * um_consumption_per_size(u, m);
-       if (unit->supply[m] < 0) {
-           /* Don't allow negative supply. */
-           unit->supply[m] = 0;
-           /* Trigger starvation. */
-           starved = TRUE;
-       }
-    }
-    /* Starvation! */
-    if (starved) {
-       /* Shrink size by one. */
-       unit->size -= 1;
-       /* Run warning. */
-       if (unit->size > 0) {
-           notify(side, "The people in %s are starving!",
-                  unit_handle(side, unit));
-       } else {
-           /* Kill the unit, but first return borrowed material to
-               treasury. */
-               give_all_to_treasury(unit);
-               notify(side, "%s is no more. The people starved to death.", 
-                       unit_handle(side, unit));
-               kill_unit(unit, H_UNIT_STARVED);
-       }
-       /* Done with handling starvation. */
-       return;
-    }
-
     /* Now check if we have enough supplies left to grow in size. */
-    /* (Should check for granary effect). */
+    /*! \todo Consider occupant effects on growth consumption. */
     for_all_material_types(m) {
        if (unit->supply[m] < unit->size * um_consumption_to_grow(u, m)) {
-               /* Return borrowed stuff to treasury. */
-               give_all_to_treasury(unit);                     
-               return;
+           /* Return borrowed stuff to treasury. */
+           give_all_to_treasury(unit);                 
+           return;
        }
     }
     /* If we got this far we are ready for a size increase! */
     for_all_material_types(m) {
-      int consump;
-      Unit *occ;
-
-      consump = unit->size * um_consumption_to_grow(u, m);
-      for_all_occupants(unit, occ) {
-       /* (Should use utype property instead). */
-       if (strcmp(u_type_name(occ->type), "Granary") == 0)
-         consump /= 2;
-      }
-      /* Use up more supplies as required to prepare growth. */
-      unit->supply[m] -= consump;
+       int consump = unit->size * um_consumption_to_grow(u, m);
+       /*! \todo Consider occupant effects on growth consumption. */
+       /* Use up more supplies as required to prepare growth. */
+       unit->supply[m] -= consump;
     }
     /* Then increase the size. */
     unit->size += 1;
-    /* And bragg about it. */
+    /* And brag about it. */
     notify(side, "%s prospers and reaches size %d.", 
           unit_handle(side, unit), unit->size);
-
     /* Return borrowed stuff to treasury. */
     give_all_to_treasury(unit);                
 }
 
+#if (0) // A few leftover snippets worth considering.
 void
 run_construction(Unit *unit)
 {                      
-    int builds = unit->size;
 
     /* Skip if this is an indep which cannot build. */
-    if (indep(unit) &g_indepside_can_build())
+    if (indep(unit) && !g_indepside_can_build())
       return;
 
-    /* Replan for passive units under ai control. */
-    if ((!side_has_display(unit->side)
-        || ai_controlled(unit)
-        || unit->autoplan)
-       && (unit->plan->type == PLAN_NONE
-           || unit->plan->type == PLAN_PASSIVE)) { 
-       auto_pick_new_plan(unit);
-    }
-
-    /* Loot the treasury. */
-    take_all_from_treasury(unit);
-
-    while (builds) {
-       Unit *unit2 = NULL;
-       int u2 = NONUTYPE;
-       int found;
-       int limited = FALSE;
-       int actionresult;
-       TaskOutcome taskresult;
-       int m;
-
-       if (unit->plan
-           && unit->plan->tasks) {
-           unit2 = find_unit(unit->plan->tasks->args[1]);
-           u2 = unit->plan->tasks->args[0];
-       }
-       /* Check if we lack a build task or just completed one. */
-       if (unit->plan->tasks == NULL
-           || unit->plan->tasks->type != TASK_BUILD
-           || (unit->plan->tasks->type == TASK_BUILD
-               && unit->plan->tasks->args[2] >= unit->plan->tasks->args[3])) {
-           /* Find any incomplete occupant that is hanging around.
-              This is also how we pick up old tasks after saving a
-              game. */
-           found = FALSE;
-           for_all_occupants(unit, unit2) {
-               if (in_play(unit2) && !fullsized(unit2)) {
-                   found = TRUE;
-                   break;
-               }
-           }
-           /* Resume building of incomplete occupant. */
-           if (found){
-               resume_build_task(unit, unit2, 1, 0, 0);
-               u2 = unit2->type;
-           } else {
-               /* Else select a new unit type to build. */
-               if  (!side_has_display(unit->side)
-                    || ai_controlled(unit)
-                    || unit->autobuild) {
-                   /* ai control. */
-                   u2 = auto_pick_new_build_task(unit);
-               } else {
-                   /* Human control. */
-                   clear_task_agenda(unit->plan);
-                   set_waiting_for_tasks(unit, TRUE);
-                   unit->buildingdone = TRUE;
-                   goto end;
-               }
-               /* Emergency exit. Happens if "Idle" is manually
-                  selected or if the city is full. */
-               if (!is_unit_type(u2))
-                 goto end;
-           }
-       }
-       /* unit2 has either not been created or is complete. */
-       if (unit2 == NULL || fullsized(unit2)) {
-           /* First check if there is enough supplies for creation. */ 
-           for_all_material_types(m) {
-               if (unit->supply[m] < um_consumption_on_creation(u2, m)) {
-                   unit->buildingdone = TRUE;
-                   goto end;
-               }
-           }
-           /* Then consume materials as required. */
-           for_all_material_types(m) {
-               unit->supply[m] -= um_consumption_on_creation(u2, m);
-           }
-           /* unit2 is still in progress. */
-       } else {
-           /* Check if any material limits its construction. */
-           for_all_material_types(m) {
-               if (um_consumption_per_cp(u2, m) > 0) {
-                   limited = TRUE;
-                   break;
-               }
-           }
-           if (limited) {
-               /* First check if there is enough supplies for one build. */
-               for_all_material_types(m) {
-                   if (unit->supply[m] < um_consumption_per_cp(u2, m)) { 
-                       unit->buildingdone = TRUE;
-                       goto end;
-                   }
-               }
-               /* Then consume materials as required. */
-               for_all_material_types(m) {
-                   unit->supply[m] -= um_consumption_per_cp(u2, m);
-               }
-               /* Else limit total builds to unit size as fallback. */
-           } else {
-               --builds;
-               if (!builds)
-                 unit->buildingdone = TRUE;
-           }
-       }
-                                               
-       /* Prepare the build action. */
-       taskresult = execute_task(unit);
-       /* Does happen when the city is full. */
-       if (taskresult == TASK_FAILED || taskresult == TASK_UNKNOWN) {
-           Dprintf("Task %s failed for %s!\n", 
-                   task_desig(unit->plan->tasks), unit_desig(unit));
-           /* Prevents infinite loop. */
-           unit->buildingdone = TRUE;
-           goto end;
-       }
-       /* Do not execute pending action if we lack one or need to
-          pick a new task!  The latter is important since we will
-          continue to build on the old unit and get an error if a new
-          build task has not been assigned. */
-       if (has_pending_action(unit) && taskresult != TASK_IS_COMPLETE) {
-           actionresult = execute_action(unit, &unit->act->nextaction);
-           /* Happens if create unit failed due to design limits on numbers. */
-           if (actionresult == A_ANY_ERROR) {
-               Dprintf("Action %s failed for %s. Clearing the task agenda.\n", 
-                       action_desig(&unit->act->nextaction), 
-                       unit_desig(unit));
-               /* Clear tasks so that a new build task is picked. */
-               clear_task_agenda(unit->plan);
-               /* Alert the human player to the fact. */
-               if  (side_has_display(unit->side)
-                    && !ai_controlled(unit)
-                    && !unit->autobuild) {
-                       set_waiting_for_tasks(unit, TRUE);
-               }
-               unit->buildingdone = TRUE;
-               goto end;
-           }
-       }
-    }
-
-end:
-    /* Return any borrowed material to treasury. */
-    give_all_to_treasury(unit);
     update_unit_acp_display(unit->side, unit, TRUE);
-
     /* Things have changed. */
     gamestatesafe = FALSE;
 }
+#endif
 
 /* Do research until supply of its limiting material is gone. */
 
@@ -1842,8 +1883,8 @@ run_research(Unit *unit)
     int m, a, lim = PROPHI;
 
     /* Check if independent units are allowed to do research. */
-    if (indep(unit) &g_indepside_can_research())
-      return; 
+    if (indep(unit) && !g_indepside_can_research())
+       return; 
     /* First test if we are already done, and select new research in
        that case. */
     if (has_advance(unit->side, unit->curadvance) 
@@ -1852,36 +1893,31 @@ run_research(Unit *unit)
        unit->curadvance = NOADVANCE;
        /* Pick new research manually for human players. */
        if (side_has_display(unit->side)
-           && !side_has_ai(unit->side)
-           && !unit->autoresearch)
+           && !side_has_ai(unit->side))
          unit_research_dialog(unit);
        /* Pick new research automatically for AIs. */
        else
          auto_pick_unit_research(unit);
     } 
-
     /* Only proceed if we now have a new advance. */
     a = unit->curadvance; 
     if (a == DONE)
-       return;
+      return;
     /* Loot the treasury. */
     take_all_from_treasury(unit);
-
     /* Loop until break. */
     while (1) {
-    
        /* Find the material whose supply limits current research. */
        for_all_material_types(m) {
-               if (am_consumption_per_rp(a, m) > 0) {
-                       lim = min(lim, (float) unit->supply[m] / am_consumption_per_rp(a, m));
-               }
+           if (am_consumption_per_rp(a, m) > 0) {
+               lim = min(lim, (int)((float) unit->supply[m] / 
+                              am_consumption_per_rp(a, m)));
+           }
        }
-       /* Don't do more research than needed to complete the advance, though. */
+       /* Don't do more research than needed to complete the advance though. */
        lim = min(lim,  a_rp(a) - unit->side->advance[a]);
-
        /* Then do research to the limit. */
        unit->side->advance[a] += lim;                          
-
        /* Reduce all supplies accordingly. */          
        for_all_material_types(m) {
            if (am_consumption_per_rp(a, m) > 0) {
@@ -1898,23 +1934,25 @@ run_research(Unit *unit)
            update_canresearch_vector(unit->side);
            update_canbuild_vector(unit->side);
            /* Notify the units side about it. */
+           /* (TODO: Change "wise men in" to be a customizable string.) */
+           /* (TODO: Change "discover" to be a customizable string.) */
            notify(unit->side, "Your wise men in %s discover %s!",
-                                       unit->name, a_type_name(a));
+                  unit->name, a_type_name(a));
            /* Pick new research for all involved units. */
            if (side_has_display(unit->side) 
                  && !side_has_ai(unit->side)) {
                for_all_side_units(unit->side, unit2) {
-                       if (!u_advanced(unit2->type))
-                           continue;
-                       /* Reallocate units on auto that took part in this
-                       advance. */
-                       if (unit2->curadvance == a && unit2->autoresearch) { 
-                               auto_pick_unit_research(unit2);
-                       /* Detect idle units on non-auto. */
-                       } else if (unit2->curadvance == a) {
-                               unit2->curadvance = 0;
-                               unit_research_dialog(unit2);
-                       }
+                   if (!u_advanced(unit2->type))
+                       continue;
+                   /* Reallocate units on auto that took part in this
+                      advance. */
+                   if (unit2->curadvance == a) { 
+                       auto_pick_unit_research(unit2);
+                   /* Detect idle units on non-auto. */
+                   } else if (unit2->curadvance == a) {
+                       unit2->curadvance = 0;
+                       unit_research_dialog(unit2);
+                   }
                }
            } else {
                for_all_side_units(unit->side, unit2) {
@@ -1926,8 +1964,8 @@ run_research(Unit *unit)
            }
        /* Research ended because we ran out of materials. */
        } else {
-               unit->researchdone = TRUE;
-               break;
+           unit->researchdone = TRUE;
+           break;
        }
     }
     /* Return all materials to treasury. */
@@ -1943,112 +1981,123 @@ run_research(Unit *unit)
 void
 allocate_used_cells(Unit *unit)
 {
-    int        x, y, a, i, m, mlim = 0, lim = 0;
-    int u = unit->type;
-    Unit *unit2;
-
-    /* Set max used cells to unit size. */
-    unit->maxcells = unit->size;
-    if (u_use_own_cell(u))
-      ++(unit->maxcells);
-    /* First compute additive effect of each occupant/facility. */
-    for_all_occupants(unit, unit2)
-      unit->maxcells += uu_occ_add_maxcells(u, unit2->type);
-    /* Then compute additive effect of completed advances. */
-    for_all_advance_types(a)
-      unit->maxcells += ua_adv_add_maxcells(u, a);
-    /* Then factor in multiplicative effect (in %) of each
-       occupant/facility. */
-    for_all_occupants(unit, unit2)
-      unit->maxcells *= (float) uu_occ_mult_maxcells(u, unit2->type) / 100;
-    /* Then factor in multiplicative effect (in %) of completed advances. */
-    for_all_advance_types(a)
-      unit->maxcells *= (float) ua_adv_mult_maxcells(u, a) / 100;
-       
-    /* Check the number of used cells. */
-    unit->usedcells = 0;
-    for_all_cells_within_reach(unit, x, y) {
-       if (!inside_area(x, y))
-         continue;
-       if (user_at(x, y) == unit->id)
-         unit->usedcells += 1;
-    }
-    /* Find the limiting material for population maintenance. */
-    for_all_material_types(m) {
-       if (um_consumption_per_size(u, m) > lim) {
-           lim = um_consumption_per_size(u, m);
-           mlim = m;
+       int     x, y, a, i, m, mlim = 0, lim = 0;
+       int u = unit->type;
+       Unit *unit2;
+
+       /* Set max used cells to unit size. */
+       unit->maxcells = unit->size;
+       if (u_use_own_cell(u))
+           ++(unit->maxcells);
+       /* First compute additive effect of each occupant/facility. */
+       for_all_occupants(unit, unit2) {
+               if (is_active(unit2)) {
+                       unit->maxcells += uu_occ_add_maxcells(u, unit2->type);
+               }
        }
-    }
-
-    /* Free all of this unit's doubtful cells within reach. */
-    for_all_cells_within_reach(unit, x, y) {
-       /* Skip if not inside area */
-       if (!inside_area(x, y))
-         continue;
-       /* Free cells used by the unit itself if it is independent or
-           played by an AI. */
-       if (user_at(x, y) == unit->id
-           && (indep(unit) || side_has_ai(unit->side))) {
-           set_user_at(x, y, NOUSER);
-           unit->usedcells -= 1;
-       } else if (user_at(x, y) != NOUSER && unit_at(x, y) != NULL) {
-           /* Also free cells used by enemy side if we have a unit in
-               the cell. */
-           for_all_stack(x, y, unit2) {
-               if (unit2->side && unit2->side == unit->side) {
-                   kick_out_enemy_users(unit->side, x, y);
-                   break;
+       /* Then compute additive effect of completed advances. */
+       for_all_advance_types(a) {
+               if (has_advance(unit->side, a)) {
+                       unit->maxcells += ua_adv_add_maxcells(u, a);
+               }
+       }
+       /* Then factor in multiplicative effect (in %) of each
+       occupant/facility. */
+       for_all_occupants(unit, unit2) {
+               if (is_active(unit2)) {
+                       unit->maxcells = (unit->maxcells * uu_occ_mult_maxcells(u, unit2->type)) / 100;
+               }
+       }
+       /* Then factor in multiplicative effect (in %) of completed advances. */
+       for_all_advance_types(a) {
+               if (has_advance(unit->side, a)) {
+                       unit->maxcells = (unit->maxcells * ua_adv_mult_maxcells(u, a)) / 100;
+               }
+       }
+       /* Check the number of used cells. */
+       unit->usedcells = 0;
+       for_all_cells_within_reach(unit, x, y) {
+               if (!inside_area(x, y))
+                   continue;
+               if (user_at(x, y) == unit->id)
+                   unit->usedcells += 1;
+       }
+       /* Find the limiting material for population maintenance. */
+       for_all_material_types(m) {
+               if (um_consumption_per_size(u, m) > lim) {
+                       lim = um_consumption_per_size(u, m);
+                       mlim = m;
                }
-           }
        }
-    }
-    /* May want to use own cell automatically. */
-    if (u_use_own_cell(u) && user_at(unit->x, unit->y) == NOUSER) {
-       set_user_at(unit->x, unit->y, unit->id);
-       unit->usedcells += 1;
-    }
-    /* Then select new cells up to unit size */
-    for (i = unit->usedcells + 1; i <= unit->maxcells; i++) {
-       int prod, tmpprod = 0, tmpx = unit->x, tmpy = unit->y;
 
+       /* Free all of this unit's doubtful cells within reach. */
        for_all_cells_within_reach(unit, x, y) {
-           /* Skip if not inside area */
-           if (!inside_area(x, y))
-             continue;
-           /* Skip if cell already is in use */
-           if (user_at(x, y) != NOUSER)
-             continue;
-           /* Skip if cell is invisible to unit */
-           if (!terrain_visible(unit->side, x, y))
-             continue;
-           /* Skip if untrusted side has a unit in the cell */
-           if (unit_at(x, y) != NULL) {
-               int enemy = FALSE;
-               for_all_stack(x, y, unit2) {
-                   if (!trusted_side(unit->side, unit2->side)) {
-                       enemy = TRUE;
-                       break;
-                   }
+               /* Skip if not inside area */
+               if (!inside_area(x, y))
+                   continue;
+               /* Free cells used by the unit itself if it is independent or
+               played by an AI. */
+               if (user_at(x, y) == unit->id
+                   && (indep(unit) || side_has_ai(unit->side))) {
+                       set_user_at(x, y, NOUSER);
+                       unit->usedcells -= 1;
+               } else if (user_at(x, y) != NOUSER && unit_at(x, y) != NULL) {
+                       /* Also free cells used by enemy side if we have a unit in
+                       the cell. */
+                       for_all_stack(x, y, unit2) {
+                               if (unit2->side && unit2->side == unit->side) {
+                                       kick_out_enemy_users(unit->side, x, y);
+                                       break;
+                               }
+                       }
                }
-               if (enemy)
-                 continue;
-           }
-           /* Make this tmp used cell if it produces more limiting
-              material than previous tmp used cell or if the previous
-              tmp cell is already in use. */
-           prod = production_at(x, y, mlim);
-           if ((prod > tmpprod) || (user_at(tmpx, tmpy) != NOUSER)) {
-               tmpprod = prod;
-               tmpx = x;  tmpy = y;
-           }
        }
-       /* Make tmp used cell permanently used if it is unused. */
-       if (user_at(tmpx, tmpy) == NOUSER) {
-           set_user_at(tmpx, tmpy, unit->id);
-           unit->usedcells += 1;
+       /* May want to use own cell automatically. */
+       if (u_use_own_cell(u) && user_at(unit->x, unit->y) == NOUSER) {
+               set_user_at(unit->x, unit->y, unit->id);
+               unit->usedcells += 1;
+       }
+       /* Then select new cells up to unit size */
+       for (i = unit->usedcells + 1; i <= unit->maxcells; i++) {
+               int prod, tmpprod = 0, tmpx = unit->x, tmpy = unit->y;
+
+               for_all_cells_within_reach(unit, x, y) {
+                       /* Skip if not inside area */
+                       if (!inside_area(x, y))
+                           continue;
+                       /* Skip if cell already is in use */
+                       if (user_at(x, y) != NOUSER)
+                           continue;
+                       /* Skip if cell is invisible to unit */
+                       if (!terrain_visible(unit->side, x, y))
+                           continue;
+                       /* Skip if untrusted side has a unit in the cell */
+                       if (unit_at(x, y) != NULL) {
+                               int enemy = FALSE;
+                               for_all_stack(x, y, unit2) {
+                                       if (!trusted_side(unit->side, unit2->side)) {
+                                               enemy = TRUE;
+                                               break;
+                                       }
+                               }
+                               if (enemy)
+                                   continue;
+                       }
+                       /* Make this tmp used cell if it produces more limiting
+                       material than previous tmp used cell or if the previous
+                       tmp cell is already in use. */
+                       prod = production_at(x, y, mlim);
+                       if ((prod > tmpprod) || (user_at(tmpx, tmpy) != NOUSER)) {
+                               tmpprod = prod;
+                               tmpx = x;  tmpy = y;
+                       }
+               }
+               /* Make tmp used cell permanently used if it is unused. */
+               if (user_at(tmpx, tmpy) == NOUSER) {
+                       set_user_at(tmpx, tmpy, unit->id);
+                       unit->usedcells += 1;
+               }
        }
-    }
 }
 
 /* Can't use a cell occupied by an enemy unit. */
@@ -2079,70 +2128,71 @@ kick_out_enemy_users(Side *side, int x, int y)
 
 /* Now picks new advance at random rather than by number. */
 
+static int *apr_type;
+
 void
 auto_pick_unit_research(Unit *unit)
 {
     int a;
-    int type[MAXATYPES];
     int numtypes = 0;
 
+    if (apr_type == NULL)
+      apr_type = (int *) xmalloc(numutypes * sizeof(int));
+
     /* Get researchable advance types. */
     for_all_advance_types(a) {
        if (side_can_research(unit->side, a)) {
            /* Add to list of researchable advances. */
-           type[numtypes++] = a;
+           apr_type[numtypes++] = a;
        }
     }
     if (numtypes)
       /* Pick one of them at random. */
-      unit->curadvance = type[xrandom(numtypes)];
+      unit->curadvance = apr_type[xrandom(numtypes)];
     else
       unit->curadvance = NOADVANCE;
 }
 
-/* Now picks new advance at random rather than by number. */
+/* Try to pick a good advance to research. */
 
 void
 auto_pick_side_research(Side *side)
 {
-    int a;
-    int type[MAXATYPES];
-    int numtypes = 0;
-
-    /* Get researchable advance types. */
-    for_all_advance_types(a) {
-       if (side_can_research(side, a)) {
-           /* Add to list of researchable advances. */
-           type[numtypes++] = a;
-       }
-    }
-    if (numtypes > 0)
-      /* Pick one of them at random. */
-      side->research_topic = type[xrandom(numtypes)];
-    else
-      side->research_topic = NONATYPE;
+    ai_pick_side_research(side);
 }
 
+#if (0)
+static int *apnbt_types;
+
 int
 auto_pick_new_build_task(Unit *unit)
 {
-    int prefs[MAXUTYPES] = {0};
     int enemy_city_near = FALSE;
     int x, y, x1, y1, u; 
     int city_has_shore = FALSE;
     int numtypes = 0;
+    Side *side = unit->side;
     Unit *unit2;
-       
-    /* Reevaluate the current plan every time. */
-      auto_pick_new_plan(unit);
 
+    if (apnbt_types == NULL)
+      apnbt_types = (int *) xmalloc(numutypes * sizeof(int));
+    /* Zero the apnbt vector! */
+    for_all_unit_types(u) {
+       apnbt_types[u] = 0;
+    }
+    /* Reevaluate the current plan every time. */
+    auto_pick_new_plan(unit);
     /* Check if the unit borders on a water cell. */   
     for_all_cells_within_range(unit->x, unit->y, 1, x, y) {
-       if (t_liquid(terrain_at(wrapx(x), y))) {
+       if (!inside_area(x, y))
+           continue;
+       if (t_liquid(terrain_at(x, y))) {
            /* Also check if that water cell borders on another water cell.
               (we don't want to build battleships in the city pond) */
            for_all_cells_within_range(x, y, 1, x1, y1) {
-               if (t_liquid(terrain_at(wrapx(x1), y1))
+               if (!inside_area(x1, y1))
+                   continue;
+               if (t_liquid(terrain_at(x1, y1))
                    /* Don't count the first water cell. */
                    && (x != x1 || y != y1)) {
                    city_has_shore = TRUE;
@@ -2153,94 +2203,108 @@ auto_pick_new_build_task(Unit *unit)
              break;                            
        }
     }          
-
     /* Check if we have an enemy city within our tactical range. */
     for_all_units(unit2) {
        if (u_advanced(unit2->type)
            && distance(unit->x, unit->y, unit2->x, unit2->y)
-           >= u_ai_tactical_range(unit->type)
-           && enemy_side(unit->side, unit2->side)
+           <= u_ai_enemy_alert_range(unit->type)
+           && enemy_side(side, unit2->side)
            /* Only count cities that we can actually see. */
-           && side_sees_image(unit->side, unit2)) {
+           && side_sees_image(side, unit2)) {
            enemy_city_near = TRUE;
            break;
        }
     }
-       
     /* Calculate unit values. */       
     for_all_unit_types(u) {
-       if (side_can_build(unit->side, u)
-           && could_create(unit->type, u)
+       if (side_can_build(side, u)
+           && could_create(unit->type, u)) {
            /* Don't build immobile units for which there is no room. */
-           && (mobile(u) || type_can_occupy(u, unit))
-           /* Don't build ships if we don't have a shore. */
-           && (!u_naval_mobile(u) || city_has_shore)) {
-           
+           if (!mobile(u) 
+               && !type_can_occupy(u, unit)) {
+               continue;
+           }
+           /* Don't build ships (naval-only movers) 
+               if we don't have a shore. */
+          if (u_naval_mobile(u)
+              && !city_has_shore
+              && !u_air_mobile(u)
+              && !u_ground_mobile(u)) {
+               continue;
+           }
            switch (unit->plan->type) {
-             case PLAN_COLONIZING:
-               prefs[u] = u_colonizer_worth(u);
-               break;                                  
              case PLAN_IMPROVING:                      
-               prefs[u] = u_facility_worth(u);
+               apnbt_types[u] = u_facility_worth(u);
                break;                                  
              case PLAN_EXPLORATORY:
-               prefs[u] = u_explorer_worth(u);
+               apnbt_types[u] = u_ai_explorer_worth(u);
                break;                                  
              case PLAN_OFFENSIVE:
                if (enemy_city_near) {
-                   /* Build siege units. */
-                   prefs[u] = u_siege_worth(u);
+                   /* Build 50% siege units. */
+                   if (probability(50))
+                       apnbt_types[u] = u_siege_worth(u);
+                   else        
+                       apnbt_types[u] = u_siege_worth(u);
                } else  {
-                   /* Build attack units. */
-                   prefs[u] = u_offensive_worth(u);
+                   /* Build only attack units. */
+                   apnbt_types[u] = u_offensive_worth(u);
                }
                break;                                  
              case PLAN_DEFENSIVE:
-               prefs[u] = occ_can_defend_transport(u, unit->type) 
+               apnbt_types[u] = occ_can_defend_transport(u, unit->type) 
                  * u_defensive_worth(u);
                break;                                  
-             case PLAN_RANDOM: 
-               prefs[u] = u_random_worth(u);
-               break;                                  
              case PLAN_NONE:
              case PLAN_PASSIVE:
              case NUMPLANTYPES:
-               prefs[u] = 0;
+               apnbt_types[u] = 0;
                break;                                  
            }
        }
-       if (prefs[u] <= 0)
-         prefs[u] = 0;
+       if (apnbt_types[u] <= 0)
+         apnbt_types[u] = 0;
        else ++numtypes;
     }                  
-
     /* Try again with random choice if we found nothing to build. */
     if (numtypes == 0) {
        for_all_unit_types(u) {
-           if (side_can_build(unit->side, u)
-               && could_create(unit->type, u)
-               /* Don't build immobile units for which there is no room. */
-               && (mobile(u) || type_can_occupy(u, unit))
-               /* Don't build ships if we don't have a shore. */
-               && (!u_naval_mobile(u) || city_has_shore)) {
-               
-               prefs[u] = u_random_worth(u);
-               if (prefs[u] <= 0)
-                 prefs[u] = 0;
+           if (side_can_build(side, u)
+               && could_create(unit->type, u)) {
+                /* Don't build immobile units for which there is no room. */
+                if (!mobile(u) 
+                    && !type_can_occupy(u, unit)) {
+                    continue;
+                }
+                /* Don't build ships (naval-only movers) 
+                   if we don't have a shore. */
+                if (u_naval_mobile(u)
+                   && !city_has_shore
+                   && !u_air_mobile(u)
+                   && !u_ground_mobile(u)) {
+                    continue;
+                }
+               apnbt_types[u] = u_random_worth(u);
+               if (apnbt_types[u] <= 0)
+                 apnbt_types[u] = 0;
                else ++numtypes;
            }
        }
     }
-                       
     if (numtypes > 0) {
        /* Use prefs weight to pick unit type to build. */
-       u = select_by_weight(prefs, numutypes);
+       u = select_by_weight(apnbt_types, numutypes);
        if (is_unit_type(u))
-         set_build_task(unit, u, 1, 0, 0); 
+         set_construct_task(unit, u, 1, -1, unit->x, unit->y); 
        else
          u = NONUTYPE;
     } else
       u = NONUTYPE;
+    if (u == NONUTYPE) {
+       set_unit_reserve(side, unit, TRUE, FALSE);
+       notify(side, "%s unable to pick build task, waiting one turn.", 
+              unit_handle(side, unit));
+    }
     return u;  
 }
 
@@ -2260,7 +2324,6 @@ auto_pick_new_plan(Unit *unit)
     /* Init plan if necessary. */
     if (!unit->plan)
       init_unit_plan(unit);    
-
     /* First count our facilities, defenders and mobile types. */
     for_all_occs_with_occs(unit, unit2) {
        if (u_facility(unit2->type))
@@ -2277,7 +2340,6 @@ auto_pick_new_plan(Unit *unit)
        set_unit_plan_type(unit->side, unit, PLAN_DEFENSIVE);
        return;
     }  
-
     /* Check out the tactical neighbourhood. */
     for_all_cells_within_range(unit->x, unit->y, 
                               u_ai_tactical_range(unit->type), x, y) {
@@ -2312,7 +2374,6 @@ auto_pick_new_plan(Unit *unit)
            }           
        }
     }
-
     if (enemy_total > 0
        && can_build_attackers(unit->side, unit->type)) {
        /* Always build attackers if any enemy unit is near. */
@@ -2321,10 +2382,6 @@ auto_pick_new_plan(Unit *unit)
               && can_build_explorers(unit->side, unit->type)) {
        /* Then build explorers if we have any invisible cells nearby. */
        set_unit_plan_type(unit->side, unit, PLAN_EXPLORATORY);
-    } else if (my_advanced + my_colonizers < 7
-              && can_build_colonizers(unit->side, unit->type)) {
-       /* Build colonizers if we have < 7 colonizers or places nearby. */
-       set_unit_plan_type(unit->side, unit, PLAN_COLONIZING);
     } else if (flip_coin() && facilities < u_facility_total_max(u)
               && can_build_facilities(unit->side, unit->type)) {
        /* Build 50% facilities if there is room left. */
@@ -2332,9 +2389,9 @@ auto_pick_new_plan(Unit *unit)
     } else if (can_build_attackers(unit->side, unit->type)) {
        /* Else build offensive units. */       
        set_unit_plan_type(unit->side, unit, PLAN_OFFENSIVE);
-    } else
-      /* Fallback - causes building of any unit that can be built. */
-      set_unit_plan_type(unit->side, unit, PLAN_RANDOM);
-
-    clear_task_agenda(unit->plan);
+    } else {
+       set_unit_plan_type(unit->side, unit, PLAN_PASSIVE);
+       set_unit_reserve(unit->side, unit, TRUE, FALSE);
+    }
 }
+#endif