Complete.Org: Mailing Lists: Archives: freeciv-dev: February 2003:
[Freeciv-Dev] (PR#3013) gen topol safe goto in server/AI
Home

[Freeciv-Dev] (PR#3013) gen topol safe goto in server/AI

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: per@xxxxxxxxxxx
Subject: [Freeciv-Dev] (PR#3013) gen topol safe goto in server/AI
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Mon, 17 Feb 2003 14:53:41 -0800
Reply-to: rt@xxxxxxxxxxxxxx

Here's an updated version of the patch, including PR#3455, a capstring
update, and removal of cruft in stdinhand.c.

jason

Index: ai/aiair.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiair.c,v
retrieving revision 1.12
diff -u -r1.12 aiair.c
--- ai/aiair.c  2003/02/17 22:49:27     1.12
+++ ai/aiair.c  2003/02/17 22:50:30
@@ -165,7 +165,7 @@
 /**********************************************************************
  * Find something to bomb
  * Air-units specific victim search
- * Returns the want for the best target, records target in goto_dest_x,y
+ * Returns the want for the best target, records target in punit->go
  * TODO: take counterattack dangers into account
  * TODO: make separate handicaps for air units seeing targets
  *       IMO should be more restrictive than general H_MAP, H_FOG
@@ -174,7 +174,8 @@
 {
   struct player *pplayer = unit_owner(punit);
   int max_dist = punit->moves_left / SINGLE_MOVE;
-  int best = 0;
+  int best_x = 0, best_y = 0, best = 0;
+  bool found_something = FALSE;
 
   if ((punit->x == x) && (punit->y == y)) {
     /* Unit is attacking from here */
@@ -208,15 +209,19 @@
        && (air_can_move_between (max_dist, x, y, x1, y1, pplayer) >= 0)){
       int new_best = ai_evaluate_tile_for_air_attack(punit, x1, y1);
       if (new_best > best) {
-       punit->goto_dest_x = x1;
-       punit->goto_dest_y = y1;
+       best_x = x1;
+       best_y = y1;
        best = new_best;
+        found_something = TRUE;
        freelog(LOG_DEBUG, "%s wants to attack tile (%d, %d)", 
                unit_type(punit)->name, x1, y1);
       }
     }
 
   } iterate_outward_end;
+  if (found_something) {
+    ai_unit_new_role(punit, AIUNIT_ATTACK, best_x, best_y);
+  }
 
   return best;
 } 
@@ -294,8 +299,6 @@
  ***********************************************************************/
 void ai_manage_airunit(struct player *pplayer, struct unit *punit)
 {
-  enum goto_result result = GR_FAILED;
-
   CHECK_UNIT(punit);
 
   if (!is_airunit_refuel_point(punit->x, punit->y, 
@@ -303,24 +306,27 @@
     /* We are out in the open, what shall we do? */
     int refuel_x, refuel_y;
 
-    if (punit->activity == ACTIVITY_GOTO
+    if (punit->activity == ACTIVITY_GOTO && punit->go
       /* We are on a GOTO.  Check if it will get us anywhere */
-       && is_airunit_refuel_point(punit->goto_dest_x, punit->goto_dest_y, 
+       && is_airunit_refuel_point(punit->go->x, punit->go->y, 
                                   pplayer, punit->type, FALSE)
        && air_can_move_between (punit->moves_left/SINGLE_MOVE, 
                                  punit->x, punit->y, 
-                                punit->goto_dest_x, punit->goto_dest_y,
+                                punit->go->x, punit->go->y,
                                 pplayer) >= 0) {
       /* It's an ok GOTO, just go there */
-      result = do_unit_goto(punit, GOTO_MOVE_ANY, FALSE);
+      (void) ai_unit_gothere(punit);
     } else if (find_nearest_airbase(punit->x, punit->y, punit, 
                             &refuel_x, &refuel_y)) {
       /* Go refuelling */
-      punit->goto_dest_x = refuel_x;
-      punit->goto_dest_y = refuel_y;
+      ai_unit_new_role(punit, AIUNIT_RECOVER, refuel_x, refuel_y);
       freelog(LOG_DEBUG, "Sent %s to refuel", unit_type(punit)->name);
-      set_unit_activity(punit, ACTIVITY_GOTO);
-      result = do_unit_goto(punit, GOTO_MOVE_ANY, FALSE);
+      if (!ai_unit_gothere(punit)) {
+        return;
+      }
+      if (!same_pos(refuel_x, refuel_y, punit->x, punit->y)) {
+        freelog(LOG_DEBUG, "Something happened to our unit along the way");
+      }
     } else {
       if (punit->fuel == 1) {
        freelog(LOG_DEBUG, "Oops, %s is fallin outta sky", 
@@ -328,19 +334,13 @@
       }
       return;
     }
-
-    /* Check if we got there okay */
-    if (result != GR_ARRIVED) {
-      freelog(LOG_DEBUG, "Something happened to our unit along the way");
-      /* TODO: some rescuing, but not running into dead-loop */
-    }
-
   } else if (punit->fuel == unit_type(punit)->fuel
             && find_something_to_bomb(punit, punit->x, punit->y) > 0) {
 
-    /* Found target, coordinates are in punit->goto_dest_[xy]
+    /* Found target, coordinates are in punit->go->[xy]
      * TODO: separate attacking into a function, check for the best 
      * tile to attack from */
+    assert(punit->go != NULL);
     set_unit_activity(punit, ACTIVITY_GOTO);
     if (!ai_unit_gothere(punit)) {
       return; /* died */
@@ -349,13 +349,12 @@
      * now actually need to attack */
 
     /* We could use ai_military_findvictim here, but I don't trust it... */
-    set_unit_activity(punit, ACTIVITY_IDLE);
     if (is_tiles_adjacent(punit->x, punit->y, 
-                         punit->goto_dest_x, punit->goto_dest_y)) {
-      int id = punit->id;
-      (void) handle_unit_move_request(punit, punit->goto_dest_x,
-                                     punit->goto_dest_y, TRUE, FALSE);
-      if ((punit = find_unit_by_id(id)) != NULL && punit->moves_left > 0) {
+                         punit->go->x, punit->go->y)) {
+      if (!ai_unit_move(punit, punit->go->x, punit->go->y)) {
+        return;
+      }
+      if (punit->moves_left > 0) {
        /* Fly home now */
        ai_manage_airunit(pplayer, punit);
       }
@@ -372,14 +371,11 @@
               unit_type(punit)->name, dest_x, dest_y, 
               (map_get_city(dest_x, dest_y) ? 
                map_get_city(dest_x, dest_y)->name : ""));
-      punit->goto_dest_x = dest_x;
-      punit->goto_dest_y = dest_y;
-      set_unit_activity(punit, ACTIVITY_GOTO);
-      result = do_unit_goto(punit, GOTO_MOVE_ANY, FALSE);
+      (void) ai_unit_goto(punit, dest_x, dest_y);
     } else {
       freelog(LOG_DEBUG, "%s cannot find anything to kill and is staying put", 
               unit_type(punit)->name);
-      set_unit_activity(punit, ACTIVITY_IDLE);
+      ai_unit_new_role(punit, AIUNIT_NONE, -1, -1);
     }
   }
 
Index: ai/aidiplomat.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidiplomat.c,v
retrieving revision 1.13
diff -u -r1.13 aidiplomat.c
--- ai/aidiplomat.c     2003/02/17 22:49:27     1.13
+++ ai/aidiplomat.c     2003/02/17 22:50:31
@@ -576,7 +576,8 @@
   /* If we have a role, we have a valid goto. Check if we have a valid city. */
   if (punit->ai.ai_role == AIUNIT_ATTACK
       || punit->ai.ai_role == AIUNIT_DEFEND_HOME) {
-    ctarget = map_get_city(punit->goto_dest_x, punit->goto_dest_y);
+    assert(punit->go != NULL);
+    ctarget = map_get_city(punit->go->x, punit->go->y);
   }
 
   /* Check if existing target still makes sense */
@@ -629,10 +630,6 @@
       UNIT_LOG(LOG_DIPLOMAT, punit, "could not find a job");
       return;
     }
-
-    /* TODO: following lines to be absorbed in a goto wrapper */
-    punit->goto_dest_x = ctarget->x;
-    punit->goto_dest_y = ctarget->y;
     ai_unit_new_role(punit, task, ctarget->x, ctarget->y);
   }
 
@@ -654,12 +651,12 @@
   /* Check if we can do something with our destination now. */
   if (punit->ai.ai_role == AIUNIT_ATTACK) {
     int dist = real_map_distance(punit->x, punit->y,
-                                 punit->goto_dest_x,
-                                 punit->goto_dest_y);
+                                 punit->go->x,
+                                 punit->go->y);
     UNIT_LOG(LOG_DIPLOMAT, punit, "attack, dist %d to %s (%s goto)"
              "[%d mc]", dist, ctarget ? ctarget->name : "(none)", 
              punit->activity == ACTIVITY_GOTO ? "has" : "no",
-             WARMAP_COST(punit->goto_dest_x, punit->goto_dest_y));
+             WARMAP_COST(punit->go->x, punit->go->y));
     if (dist == 1) {
       /* Do our stuff */
       ai_unit_new_role(punit, AIUNIT_NONE, -1, -1);
Index: ai/ailog.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/ailog.c,v
retrieving revision 1.6
diff -u -r1.6 ailog.c
--- ai/ailog.c  2003/02/17 22:49:27     1.6
+++ ai/ailog.c  2003/02/17 22:50:31
@@ -73,11 +73,18 @@
     return;
   }
 
-  my_snprintf(buffer, sizeof(buffer), "%s's %s[%d] (%d,%d)->(%d,%d){%d} ",
-              unit_owner(punit)->name, unit_type(punit)->name,
-              punit->id, punit->x, punit->y,
-              punit->goto_dest_x, punit->goto_dest_y, 
-              punit->ai.bodyguard);
+  if (punit->go) {
+    my_snprintf(buffer, sizeof(buffer), "%s's %s[%d] (%d,%d)->(%d,%d)->"
+                "(%d,%d){%d} ", unit_owner(punit)->name, 
+                unit_type(punit)->name, punit->id, punit->go->origin_x,
+                punit->go->origin_y, punit->x, punit->y, punit->go->x, 
+                punit->go->y, punit->ai.bodyguard);
+  } else {
+    my_snprintf(buffer, sizeof(buffer), "%s's %s[%d] (%d,%d){%d} ",
+                unit_owner(punit)->name, unit_type(punit)->name,
+                punit->id, punit->x, punit->y,
+                punit->ai.bodyguard);
+  }
 
   va_start(ap, msg);
   my_vsnprintf(buffer2, sizeof(buffer2), msg, ap);
@@ -85,36 +92,6 @@
 
   cat_snprintf(buffer, sizeof(buffer), buffer2);
   freelog(minlevel, buffer);
-}
-
-/**************************************************************************
-  Log goto message if the goto fails. They will appear like this
-    2: a's Explorer[105] on GOTO (3,25)->(5,23) failed : exploring territory
-**************************************************************************/
-void GOTO_LOG(int level, struct unit *punit, enum goto_result result, 
-              const char *msg, ...)
-{
-  int minlevel = MIN(LOGLEVEL_GOTO, level);
-
-  if (minlevel <= fc_log_level && (result == GR_FAILED || result == 
GR_FOUGHT)) {
-    char buffer[500];
-    char buffer2[500];
-    va_list ap;
-
-    my_snprintf(buffer, sizeof(buffer),
-                "%s's %s[%d] on GOTO (%d,%d)->(%d,%d) %s : ",
-                unit_owner(punit)->name, unit_type(punit)->name,
-                punit->id, punit->x, punit->y,
-                punit->goto_dest_x, punit->goto_dest_y,
-               (result == GR_FAILED) ? "failed" : "fought");
-
-    va_start(ap, msg);
-    my_vsnprintf(buffer2, sizeof(buffer2), msg, ap);
-    va_end(ap);
-
-    cat_snprintf(buffer, sizeof(buffer), buffer2);
-    freelog(minlevel, buffer);
-  }
 }
 
 /**************************************************************************
Index: ai/aitools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aitools.c,v
retrieving revision 1.80
diff -u -r1.80 aitools.c
--- ai/aitools.c        2003/02/17 22:49:27     1.80
+++ ai/aitools.c        2003/02/17 22:50:31
@@ -87,8 +87,7 @@
   CHECK_MAP_POS(pcity->x, pcity->y);
   punit->x = pcity->x;
   punit->y = pcity->y;
-  punit->goto_dest_x = 0;
-  punit->goto_dest_y = 0;
+  punit->go = NULL;
   punit->veteran = make_veteran;
   punit->homecity = pcity->id;
   punit->upkeep = 0;
@@ -139,13 +138,15 @@
 
 /**************************************************************************
   This will eventually become the ferry-enabled goto. For now, it just
-  wraps ai_unit_goto()
+  wraps ai_unit_goto().
+
+  You must set a valid punit->go first.
 **************************************************************************/
 bool ai_unit_gothere(struct unit *punit)
 {
   CHECK_UNIT(punit);
-  assert(punit->goto_dest_x != -1 && punit->goto_dest_y != -1);
-  if (ai_unit_goto(punit, punit->goto_dest_x, punit->goto_dest_y)) {
+  punit->go->counter++;
+  if (ai_unit_goto(punit, punit->go->x, punit->go->y)) {
     return TRUE; /* ... and survived */
   } else {
     return FALSE; /* we died */
@@ -156,24 +157,19 @@
   Go to specified destination but do not disturb existing role or activity
   and do not clear the role's destination. Return FALSE iff we died.
 
-  FIXME: add some logging functionality to replace GOTO_LOG()
+  FIXME: add some logging functionality
 **************************************************************************/
 bool ai_unit_goto(struct unit *punit, int x, int y)
 {
   enum goto_result result;
-  int oldx = punit->goto_dest_x, oldy = punit->goto_dest_y;
   enum unit_activity activity = punit->activity;
 
   CHECK_UNIT(punit);
   /* TODO: log error on same_pos with punit->x|y */
-  punit->goto_dest_x = x;
-  punit->goto_dest_y = y;
   handle_unit_activity_request(punit, ACTIVITY_GOTO);
-  result = do_unit_goto(punit, GOTO_MOVE_ANY, FALSE);
+  result = do_unit_goto(punit, GOTO_MOVE_ANY, FALSE, x, y);
   if (result != GR_DIED) {
     handle_unit_activity_request(punit, activity);
-    punit->goto_dest_x = oldx;
-    punit->goto_dest_y = oldy;
     return TRUE;
   }
   return FALSE;
@@ -183,20 +179,27 @@
   Ensure unit sanity by telling charge that we won't bodyguard it anymore,
   tell bodyguard it can roam free if our job is done, add and remove city 
   spot reservation, and set destination.
+
+  For AIUNIT_NONE, AIUNIT_EXPLORE and AINUNIT_AUTO_EXPLORE, set x and y 
+  to (-1, -1). This is just a convention, the numbers mean nothing. For 
+  all other roles, give valid (x, y) coordinates.
 **************************************************************************/
 void ai_unit_new_role(struct unit *punit, enum ai_unit_task task, int x, int y)
 {
   struct unit *charge = find_unit_by_id(punit->ai.charge);
   struct unit *bodyguard = find_unit_by_id(punit->ai.bodyguard);
 
+  assert(task != AIUNIT_PILLAGE);
+
   if (punit->activity == ACTIVITY_GOTO) {
     /* It would indicate we're going somewhere otherwise */
     handle_unit_activity_request(punit, ACTIVITY_IDLE);
   }
 
   if (punit->ai.ai_role == AIUNIT_BUILD_CITY) {
-    assert(is_normal_map_pos(punit->goto_dest_x, punit->goto_dest_y));
-    remove_city_from_minimap(punit->goto_dest_x, punit->goto_dest_y);
+    assert(punit->go != NULL);
+    assert(is_normal_map_pos(punit->go->x, punit->go->y));
+    remove_city_from_minimap(punit->go->x, punit->go->y);
   }
 
   if (charge && (charge->ai.bodyguard == punit->id)) {
@@ -206,9 +209,32 @@
   punit->ai.charge = BODYGUARD_NONE;
 
   punit->ai.ai_role = task;
-/* TODO:
-  punit->goto_dest_x = x;
-  punit->goto_dest_y = y; */
+
+  switch (task) {
+    case AIUNIT_NONE:
+    case AIUNIT_EXPLORE:
+    case AIUNIT_AUTO_SETTLER:
+      /* No valid coordinates expected */
+      assert(x == -1 && y == -1);
+      punit->go = NULL;
+      break;
+    case AIUNIT_DEFEND_HOME:
+    case AIUNIT_BUILD_CITY:
+    case AIUNIT_ATTACK:
+    case AIUNIT_ESCORT:
+    case AIUNIT_RECOVER:
+    case AIUNIT_TRANSPORT:
+      assert(is_normal_map_pos(x, y));
+      punit->go = &punit->goto_struct;
+      punit->go->x = x;
+      punit->go->y = y;
+      punit->go->origin_x = punit->x;
+      punit->go->origin_y = punit->y;
+      break;
+    default:
+      assert(FALSE);
+      break;
+  }
 
   if (punit->ai.ai_role == AIUNIT_NONE && bodyguard) {
     ai_unit_new_role(bodyguard, AIUNIT_NONE, -1, -1);
Index: ai/aiunit.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.c,v
retrieving revision 1.264
diff -u -r1.264 aiunit.c
--- ai/aiunit.c 2003/02/17 22:49:27     1.264
+++ ai/aiunit.c 2003/02/17 22:50:33
@@ -61,6 +61,7 @@
 static void ai_manage_caravan(struct player *pplayer, struct unit *punit);
 static void ai_manage_barbarian_leader(struct player *pplayer,
                                       struct unit *leader);
+static void ai_manage_hitpoint_recovery(struct unit *punit);
 
 static void ai_military_findjob(struct player *pplayer,struct unit *punit);
 static void ai_military_gohome(struct player *pplayer,struct unit *punit);
@@ -708,7 +709,8 @@
           ai_military_gohome(pplayer, punit);
         } else {
           /* Also try take care of deliberately homeless units */
-          (void) ai_unit_goto(punit, pcity->x, pcity->y);
+          ai_unit_new_role(punit, AIUNIT_DEFEND_HOME, pcity->x, pcity->y);
+          (void) ai_unit_gothere(punit);
         }
       } else {
         /* Sea travel */
@@ -718,7 +720,8 @@
           ai_military_gohome(pplayer, punit); /* until then go home */
         } else {
           UNIT_LOG(LOG_DEBUG, punit, "sending explorer home by boat");
-          (void) ai_unit_goto(punit, x, y);
+          ai_unit_new_role(punit, AIUNIT_DEFEND_HOME, x, y);
+          (void) ai_unit_gothere(punit);
         }
       }
     }
@@ -789,8 +792,6 @@
   if (!has_defense && pcity->ai.danger > 0) {
     /* change homecity to this city */
     if (ai_unit_make_homecity(punit, pcity)) {
-      /* Very important, or will not stay -- Syela */
-      ai_unit_new_role(punit, AIUNIT_DEFEND_HOME, pcity->x, pcity->y);
       return TRUE;
     }
   }
@@ -1188,6 +1189,7 @@
   int x, y;
 
   CHECK_UNIT(punit);
+  assert(punit->id == 0 || punit->ai.ai_role == AIUNIT_ESCORT);
 
   if (aunit && aunit->owner == punit->owner) {
     /* protect a unit */
@@ -1373,10 +1375,9 @@
         handle_unit_activity_request(punit, ACTIVITY_SENTRY);
         ferryboat->ai.passenger = punit->id;
 /* the code that worked for settlers wasn't good for piles of cannons */
-        if (find_beachhead(punit, dest_x, dest_y, &ferryboat->goto_dest_x,
-               &ferryboat->goto_dest_y) != 0) {
-          punit->goto_dest_x = dest_x;
-          punit->goto_dest_y = dest_y;
+        if (ferryboat->go
+            && find_beachhead(punit, dest_x, dest_y, &ferryboat->go->x,
+                              &ferryboat->go->y) != 0) {
           handle_unit_activity_request(punit, ACTIVITY_SENTRY);
          if (ground_unit_transporter_capacity(punit->x, punit->y, pplayer)
              <= 0) {
@@ -1411,9 +1412,6 @@
 bodyguard, or 3) we are going to an empty city.  Previously, cannons
 would disembark before the cruisers arrived and die. -- Syela */
 
-      punit->goto_dest_x = dest_x;
-      punit->goto_dest_y = dest_y;
-
 /* The following code block is supposed to stop units from running away from 
their
 bodyguards, and not interfere with those that don't have bodyguards nearby -- 
Syela */
 /* The case where the bodyguard has moves left and could meet us en route is 
not
@@ -1548,6 +1546,8 @@
 ***********************************************************************/
 static void ai_military_findjob(struct player *pplayer,struct unit *punit)
 {
+  struct ai_data *ai = ai_data_get(pplayer);
+  struct tile *ptile = map_get_tile(punit->x, punit->y);
   struct city *pcity = NULL, *acity = NULL;
   struct unit *aunit;
   int val, def;
@@ -1587,19 +1587,10 @@
     } /* end if home is in danger */
   } /* end if we have a home */
 
-  /* keep barbarians aggresive and primitive */
-  if (is_barbarian(pplayer)) {
-    if (can_unit_do_activity(punit, ACTIVITY_PILLAGE)
-       && is_land_barbarian(pplayer)) {
-      /* land barbarians pillage */
-      ai_unit_new_role(punit, AIUNIT_PILLAGE, -1, -1);
-    } else {
-      ai_unit_new_role(punit, AIUNIT_ATTACK, -1, -1);
-    }
-    return;
-  }
+  /*** Part 1: Check existing assignments, and keep them if possible ***/
 
-  if (punit->ai.charge != BODYGUARD_NONE) { /* I am a bodyguard */
+  if (punit->ai.ai_role == AIUNIT_ESCORT) {
+    /* I am a bodyguard, check validity of assignment */
     aunit = player_find_unit_by_id(pplayer, punit->ai.charge);
     acity = find_city_by_id(punit->ai.charge);
 
@@ -1610,7 +1601,7 @@
          unit_vulnerability_virtual(aunit)) ||
          (acity && acity->owner == punit->owner && acity->ai.urgency != 0 &&
           acity->ai.danger > assess_defense_quadratic(acity))) {
-      assert(punit->ai.ai_role == AIUNIT_ESCORT);
+      ai_military_bodyguard(pplayer, punit);
       return;
     } else {
       ai_unit_new_role(punit, AIUNIT_NONE, -1, -1);
@@ -1624,8 +1615,26 @@
     return;
   }
 
+  /*** Part 2: Give new assignments ***/
+
+  ai_unit_new_role(punit, AIUNIT_NONE, -1, -1);
+
+  /* keep barbarians aggresive and primitive */
+  if (is_barbarian(pplayer)) {
+    if (can_unit_do_activity(punit, ACTIVITY_PILLAGE)
+       && is_land_barbarian(pplayer)) {
+      /* land barbarians pillage */
+      handle_unit_activity_request(punit, ACTIVITY_PILLAGE);
+    }
+    if (punit->moves_left > 0) {
+      ai_military_attack(pplayer, punit);
+    }
+    return;
+  }
+
+  /* Home city in danger, defend it! */
   if (q > 0 && pcity->ai.urgency > 0) {
-    ai_unit_new_role(punit, AIUNIT_DEFEND_HOME, pcity->x, pcity->y);
+    ai_military_gohome(pplayer, punit);
     return;
   }
 
@@ -1633,8 +1642,8 @@
   if ((punit->ai.ai_role == AIUNIT_RECOVER
        && punit->hp < punittype->hp)
       || punit->hp < punittype->hp * 0.25) { /* WAG */
-    UNIT_LOG(LOGLEVEL_RECOVERY, punit, "set to hp recovery");
-    ai_unit_new_role(punit, AIUNIT_RECOVER, -1, -1);
+    UNIT_LOG(LOGLEVEL_RECOVERY, punit, "suggesting hp recovery");
+    ai_manage_hitpoint_recovery(punit);
     return;
   }
 
@@ -1658,7 +1667,7 @@
     val = look_for_charge(pplayer, punit, &aunit, &acity);
   }
   if (q > val) {
-    ai_unit_new_role(punit, AIUNIT_DEFEND_HOME, pcity->x, pcity->y);
+    ai_military_gohome(pplayer, punit);
     return;
   }
   /* this is bad; riflemen might rather attack if val is low -- Syela */
@@ -1666,15 +1675,19 @@
     ai_unit_new_role(punit, AIUNIT_ESCORT, acity->x, acity->y);
     punit->ai.charge = acity->id;
     BODYGUARD_LOG(LOG_DEBUG, punit, "going to defend city");
+    ai_military_bodyguard(pplayer, punit);
   } else if (aunit) {
     ai_unit_new_role(punit, AIUNIT_ESCORT, aunit->x, aunit->y);
     punit->ai.charge = aunit->id;
     BODYGUARD_LOG(LOG_DEBUG, punit, "going to defend unit");
+    ai_military_bodyguard(pplayer, punit);
   } else if (ai_unit_attack_desirability(punit->type) != 0 ||
       (pcity && !same_pos(pcity->x, pcity->y, punit->x, punit->y))) {
-     ai_unit_new_role(punit, AIUNIT_ATTACK, -1, -1);
+    ai_military_attack(pplayer, punit);
+  } else if (ai->explore.continent[ptile->continent]) {
+    ai_manage_explorer(punit);
   } else {
-    ai_unit_new_role(punit, AIUNIT_DEFEND_HOME, -1, -1); /* for default */
+    ai_military_gohome(pplayer, punit); /* for default */
   }
 }
 
@@ -1697,8 +1710,9 @@
       /* aggro defense goes here -- Syela */
       (void) ai_military_rampage(punit, 2); /* 2 is better than pillage */
     } else {
+      ai_unit_new_role(punit, AIUNIT_DEFEND_HOME, pcity->x, pcity->y);
       UNIT_LOG(LOG_DEBUG, punit, "GOHOME");
-      (void) ai_unit_goto(punit, pcity->x, pcity->y);
+      (void) ai_unit_gothere(punit);
     }
   }
 }
@@ -1809,8 +1823,9 @@
   CHECK_UNIT(punit);
 
   if (dest) {
-    x = punit->goto_dest_x;
-    y = punit->goto_dest_y;
+    assert(punit->go != NULL);
+    x = punit->go->x;
+    y = punit->go->y;
   } else {
     x = punit->x;
     y = punit->y;
@@ -1915,8 +1930,9 @@
     /* dealing with invasion stuff */
     if (IS_ATTACKER(aunit)) {
       if (aunit->activity == ACTIVITY_GOTO) {
+        assert(punit->go != NULL);
         invasion_funct(aunit, TRUE, 0, (COULD_OCCUPY(aunit) ? 1 : 2));
-        if ((pcity = map_get_city(aunit->goto_dest_x, aunit->goto_dest_y))) {
+        if ((pcity = map_get_city(aunit->go->x, aunit->go->y))) {
           pcity->ai.attack += unit_belligerence_basic(aunit);
           pcity->ai.bcost += unit_type(aunit)->build_cost;
         } 
@@ -2300,6 +2316,7 @@
           || (could_unit_move_to_tile(punit, dest_x, dest_y) == 0)) {
         /* Can't attack or move usually means we are adjacent but
          * on a ferry. This fixes the problem (usually). */
+        ai_unit_new_role(punit, AIUNIT_ATTACK, dest_x, dest_y);
         UNIT_LOG(LOG_DEBUG, punit, "mil att gothere -> %d, %d", 
                  dest_x, dest_y);
         if (ai_military_gothere(pplayer, punit, dest_x, dest_y) <= 0) {
@@ -2334,7 +2351,8 @@
   pcity = find_nearest_safe_city(punit);
   if (is_sailing_unit(punit) && pcity) {
     /* Sail somewhere */
-    (void) ai_unit_goto(punit, pcity->x, pcity->y);
+    ai_unit_new_role(punit, AIUNIT_DEFEND_HOME, pcity->x, pcity->y);
+    (void) ai_unit_gothere(punit);
   } else if (!is_barbarian(pplayer)) {
     /* Nothing else to do. Worst case, this function
        will send us back home */
@@ -2347,12 +2365,14 @@
     if ((pc = dist_nearest_city(pplayer, punit->x, punit->y, FALSE, TRUE))) {
       if (!is_ocean(map_get_terrain(punit->x, punit->y))) {
         UNIT_LOG(LOG_DEBUG, punit, "Barbarian marching to conquer %s", 
pc->name);
+        ai_unit_new_role(punit, AIUNIT_ATTACK, pc->x, pc->y);
         ai_military_gothere(pplayer, punit, pc->x, pc->y);
       } else {
         /* sometimes find_beachhead is not enough */
         if (find_beachhead(punit, pc->x, pc->y, &fx, &fy) == 0) {
           find_city_beach(pc, punit, &fx, &fy);
           freelog(LOG_DEBUG, "Barbarian sailing to city");
+          ai_unit_new_role(punit, AIUNIT_ATTACK, fx, fy);
           ai_military_gothere(pplayer, punit, fx, fy);
        }
       }
@@ -2472,7 +2492,7 @@
       }
       p++;
       bodyguard = unit_list_find(&map_get_tile(punit->x, punit->y)->units, 
aunit->ai.bodyguard);
-      pcity = map_get_city(aunit->goto_dest_x, aunit->goto_dest_y);
+      pcity = aunit->go ? map_get_city(aunit->go->x, aunit->go->y) : NULL;
       if (aunit->ai.bodyguard == BODYGUARD_NONE || bodyguard ||
          (pcity && pcity->ai.invasion >= 2)) {
        if (pcity) {
@@ -2501,21 +2521,21 @@
   if (p != 0) {
     freelog(LOG_DEBUG, "%s#%d@(%d,%d), p=%d, n=%d",
                  unit_name(punit->type), punit->id, punit->x, punit->y, p, n);
-    if (punit->moves_left > 0 && n != 0) {
+    if (punit->go && punit->moves_left > 0 && n != 0) {
       (void) ai_unit_gothere(punit);
     } else if (n == 0 && !map_get_city(punit->x, punit->y)) { /* rest in a 
city, for unhap */
-      x = punit->goto_dest_x; y = punit->goto_dest_y;
       port = find_nearest_safe_city(punit);
       if (port && !ai_unit_goto(punit, port->x, port->y)) {
         return; /* oops! */
       }
-      punit->goto_dest_x = x; punit->goto_dest_y = y;
       send_unit_info(pplayer, punit); /* to get the crosshairs right -- Syela 
*/
     } else {
       UNIT_LOG(LOG_DEBUG, punit, "Ferryboat %d@(%d,%d) stalling.",
                    punit->id, punit->x, punit->y);
-      if(is_barbarian(pplayer)) /* just in case */
+      if (is_barbarian(pplayer)) {
+        /* just in case */
         (void) ai_manage_explorer(punit);
+      }
     }
     return;
   }
@@ -2530,8 +2550,6 @@
   punit->ai.passenger = 0;
   UNIT_LOG(LOG_DEBUG, punit, "Ferryboat is lonely.");
   handle_unit_activity_request(punit, ACTIVITY_IDLE);
-  punit->goto_dest_x = 0; /* FIXME: -1 */
-  punit->goto_dest_y = 0; /* FIXME: -1 */
 
   /* Release bodyguard and let it roam */
   ai_unit_new_role(punit, AIUNIT_NONE, -1, -1);
@@ -2569,8 +2587,7 @@
   } unit_list_iterate_end;
   if (best < 4 * unit_type(punit)->move_rate) {
     /* Pickup is within 4 turns to grab, so move it! */
-    punit->goto_dest_x = x;
-    punit->goto_dest_y = y;
+    ai_unit_new_role(punit, AIUNIT_TRANSPORT, x, y);
     UNIT_LOG(LOG_DEBUG, punit, "Found a friend and going to him @(%d, %d)",
              x, y);
     (void) ai_unit_gothere(punit);
@@ -2585,8 +2602,7 @@
   if (pcity) {
     if (!ai_handicap(pplayer, H_TARGETS) ||
         unit_move_turns(punit, pcity->x, pcity->y) < p) {
-      punit->goto_dest_x = pcity->x;
-      punit->goto_dest_y = pcity->y;
+      ai_unit_new_role(punit, AIUNIT_RECOVER, pcity->x, pcity->y);
       UNIT_LOG(LOG_DEBUG, punit, "No friends.  Going home.");
       (void) ai_unit_gothere(punit);
       return;
@@ -2664,42 +2680,8 @@
 
   CHECK_UNIT(punit);
 
-  /* was getting a bad bug where a settlers caused a defender to leave home */
-  /* and then all other supported units went on DEFEND_HOME/goto */
   ai_military_findjob(pplayer, punit);
 
-  switch (punit->ai.ai_role) {
-  case AIUNIT_AUTO_SETTLER:
-  case AIUNIT_BUILD_CITY:
-    ai_unit_new_role(punit, AIUNIT_NONE, -1, -1);
-    break;
-  case AIUNIT_DEFEND_HOME:
-    ai_military_gohome(pplayer, punit);
-    break;
-  case AIUNIT_ATTACK:
-    ai_military_attack(pplayer, punit);
-    break;
-  case AIUNIT_FORTIFY:
-    ai_military_gohome(pplayer, punit);
-    break;
-  case AIUNIT_RUNAWAY: 
-    break;
-  case AIUNIT_ESCORT: 
-    ai_military_bodyguard(pplayer, punit);
-    break;
-  case AIUNIT_PILLAGE:
-    handle_unit_activity_request(punit, ACTIVITY_PILLAGE);
-    return; /* when you pillage, you have moves left, avoid later fortify */
-  case AIUNIT_EXPLORE:
-    (void) ai_manage_explorer(punit);
-    break;
-  case AIUNIT_RECOVER:
-    ai_manage_hitpoint_recovery(punit);
-    break;
-  default:
-    assert(FALSE);
-  }
-
   /* If we are still alive, either sentry or fortify. */
   if ((punit = find_unit_by_id(id))) {
     if (unit_list_find(&(map_get_tile(punit->x, punit->y)->units),
@@ -2771,7 +2753,7 @@
   if (!bodyguard && punit->ai.bodyguard > BODYGUARD_NONE) {
     UNIT_LOG(LOGLEVEL_BODYGUARD, punit, "lost bodyguard, asking for new");
     punit->ai.bodyguard = BODYGUARD_WANTED;
-  }  
+  }
 
   if ((unit_flag(punit, F_DIPLOMAT))
       || (unit_flag(punit, F_SPY))) {
Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.291
diff -u -r1.291 packhand.c
--- client/packhand.c   2003/02/17 22:49:27     1.291
+++ client/packhand.c   2003/02/17 22:50:34
@@ -97,8 +97,6 @@
   punit->upkeep_gold = packet->upkeep_gold;
   punit->ai.control = packet->ai;
   punit->fuel = packet->fuel;
-  punit->goto_dest_x = packet->goto_dest_x;
-  punit->goto_dest_y = packet->goto_dest_y;
   punit->activity_target = packet->activity_target;
   punit->paradropped = packet->paradropped;
   punit->connecting = packet->connecting;
@@ -1005,9 +1003,6 @@
         if((unit_flag(punit, F_TRADE_ROUTE) || unit_flag(punit, F_HELP_WONDER))
           && (!game.player_ptr->ai.control || ai_popup_windows)
           && punit->owner==game.player_idx
-          && (punit->activity!=ACTIVITY_GOTO ||
-              same_pos(punit->goto_dest_x, punit->goto_dest_y,
-                       pcity->x, pcity->y))
           && (unit_can_help_build_wonder_here(punit)
               || unit_can_est_traderoute_here(punit))) {
          process_caravan_arrival(punit);
@@ -1042,8 +1037,6 @@
     punit->moves_left=packet->movesleft;
     punit->bribe_cost=0;
     punit->fuel=packet->fuel;
-    punit->goto_dest_x=packet->goto_dest_x;
-    punit->goto_dest_y=packet->goto_dest_y;
     punit->paradropped=packet->paradropped;
     punit->connecting=packet->connecting;
   
Index: client/gui-gtk/mapctrl.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/mapctrl.c,v
retrieving revision 1.76
diff -u -r1.76 mapctrl.c
--- client/gui-gtk/mapctrl.c    2003/02/17 22:49:27     1.76
+++ client/gui-gtk/mapctrl.c    2003/02/17 22:50:34
@@ -156,12 +156,6 @@
                    ptype->attack_strength, 
                    ptype->defense_strength, ptype->firepower, punit->hp, 
                    ptype->hp, punit->veteran ? _(" V") : "", uc);
-
-        if(punit->activity == ACTIVITY_GOTO || punit->connecting)  {
-         cross_head->x = punit->goto_dest_x;
-         cross_head->y = punit->goto_dest_y;
-         cross_head++;
-        }
       } else {
         struct unit *apunit;
         
Index: client/gui-gtk-2.0/mapctrl.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/mapctrl.c,v
retrieving revision 1.17
diff -u -r1.17 mapctrl.c
--- client/gui-gtk-2.0/mapctrl.c        2003/02/17 22:49:27     1.17
+++ client/gui-gtk-2.0/mapctrl.c        2003/02/17 22:50:34
@@ -165,12 +165,6 @@
                    ptype->attack_strength, 
                    ptype->defense_strength, ptype->firepower, punit->hp, 
                    ptype->hp, punit->veteran ? _(" V") : "", uc);
-
-        if(punit->activity == ACTIVITY_GOTO || punit->connecting)  {
-         cross_head->x = punit->goto_dest_x;
-         cross_head->y = punit->goto_dest_y;
-         cross_head++;
-        }
       } else {
         struct unit *apunit;
         
Index: client/gui-win32/mapctrl.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-win32/mapctrl.c,v
retrieving revision 1.20
diff -u -r1.20 mapctrl.c
--- client/gui-win32/mapctrl.c  2003/02/17 22:49:27     1.20
+++ client/gui-win32/mapctrl.c  2003/02/17 22:50:35
@@ -191,12 +191,6 @@
                  ptype->attack_strength, 
                  ptype->defense_strength, ptype->firepower, punit->hp, 
                  ptype->hp, punit->veteran?_(" V"):"", uc);
-      
-      if(punit->activity==ACTIVITY_GOTO || punit->connecting)  {
-       cross_head->x = punit->goto_dest_x;
-       cross_head->y = punit->goto_dest_y;
-       cross_head++;
-      }
     } else {
       my_snprintf(s, sizeof(s), _("A:%d D:%d FP:%d HP:%d0%%"),
                  ptype->attack_strength, 
Index: client/gui-xaw/mapctrl.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/mapctrl.c,v
retrieving revision 1.64
diff -u -r1.64 mapctrl.c
--- client/gui-xaw/mapctrl.c    2003/02/17 22:49:27     1.64
+++ client/gui-xaw/mapctrl.c    2003/02/17 22:50:35
@@ -165,12 +165,6 @@
                _("A:%d D:%d FP:%d HP:%d/%d%s%s"), ptype->attack_strength, 
                ptype->defense_strength, ptype->firepower, punit->hp, 
                ptype->hp, punit->veteran?_(" V"):"", uc);
-
-        if(punit->activity==ACTIVITY_GOTO)  {
-         cross_head->x = punit->goto_dest_x;
-         cross_head->y = punit->goto_dest_y;
-         cross_head++;
-        }
       } else {
         my_snprintf(s, sizeof(s),
                    _("A:%d D:%d FP:%d HP:%d0%%"), ptype->attack_strength, 
Index: common/capstr.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/capstr.c,v
retrieving revision 1.126
diff -u -r1.126 capstr.c
--- common/capstr.c     2003/02/17 22:49:27     1.126
+++ common/capstr.c     2003/02/17 22:50:35
@@ -76,8 +76,8 @@
 
 #define CAPABILITY "+1.14.0 conn_info +occupied team tech_impr_gfx " \
                    "city_struct_minor_cleanup obsolete_last class_legend " \
-                   "+impr_req +waste +fastfocus +continent"
-  
+                   "+impr_req +waste +fastfocus +continent +goto"
+
 /* "+1.14.0" is protocol for 1.14.0 release.
  *
  * "conn_info" is sending the conn_id field. To preserve compatability
@@ -109,6 +109,9 @@
  * "fastfocus" removes the server from client unit focus.
  *
  * +continent": the server gives the client continent information
+ *
+ * "goto" makes server goto gen topol safe, and also better. But removes
+ * goto information from the client in regards to connecting and air units.
  */
 
 void init_our_capability(void)
Index: common/packets.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.c,v
retrieving revision 1.240
diff -u -r1.240 packets.c
--- common/packets.c    2003/02/17 22:49:27     1.240
+++ common/packets.c    2003/02/17 22:50:36
@@ -1268,8 +1268,6 @@
   dio_put_uint8(&dout, req->unhappiness);
   dio_put_uint8(&dout, req->activity);
   dio_put_uint8(&dout, req->activity_count);
-  dio_put_uint8(&dout, req->goto_dest_x);
-  dio_put_uint8(&dout, req->goto_dest_y);
   dio_put_uint16(&dout, req->activity_target);
   dio_put_uint8(&dout, req->packet_use);
   dio_put_uint16(&dout, req->info_city_id);
@@ -1546,8 +1544,6 @@
   dio_get_uint8(&din, &packet->unhappiness);
   dio_get_uint8(&din, &packet->activity);
   dio_get_uint8(&din, &packet->activity_count);
-  dio_get_uint8(&din, &packet->goto_dest_x);
-  dio_get_uint8(&din, &packet->goto_dest_y);
   dio_get_uint16(&din, (int *) &packet->activity_target);
   dio_get_uint8(&din, &packet->packet_use);
   dio_get_uint16(&din, &packet->info_city_id);
Index: common/packets.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.h,v
retrieving revision 1.141
diff -u -r1.141 packets.h
--- common/packets.h    2003/02/17 22:49:28     1.141
+++ common/packets.h    2003/02/17 22:50:37
@@ -310,7 +310,6 @@
   int upkeep_gold;
   bool ai;
   int fuel;
-  int goto_dest_x, goto_dest_y;
   enum tile_special_type activity_target;
   bool paradropped;
   bool connecting;
Index: common/unit.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unit.h,v
retrieving revision 1.95
diff -u -r1.95 unit.h
--- common/unit.h       2003/02/17 22:49:28     1.95
+++ common/unit.h       2003/02/17 22:50:37
@@ -47,10 +47,18 @@
   DIPLOMAT_CLIENT_POPUP_DIALOG
 };
 
-enum ai_unit_task { AIUNIT_NONE, AIUNIT_AUTO_SETTLER, AIUNIT_BUILD_CITY,
-                    AIUNIT_DEFEND_HOME, AIUNIT_ATTACK, AIUNIT_FORTIFY,
-                    AIUNIT_RUNAWAY, AIUNIT_ESCORT, AIUNIT_EXPLORE,
-                    AIUNIT_PILLAGE, AIUNIT_RECOVER };
+enum ai_unit_task {
+  AIUNIT_NONE,          /* default */
+  AIUNIT_AUTO_SETTLER,  /* make terrain improvements */
+  AIUNIT_BUILD_CITY,    /* build a city */
+  AIUNIT_DEFEND_HOME,   /* go to a city to _defend_ it */
+  AIUNIT_ATTACK,        /* attack designated target */
+  AIUNIT_ESCORT,        /* protect unit or city */
+  AIUNIT_EXPLORE,       /* explore */
+  AIUNIT_PILLAGE,       /* pseudo-role indicating pillage */
+  AIUNIT_RECOVER,       /* go to a place to recover or rest */
+  AIUNIT_TRANSPORT     /* transport other units */
+};
 
 enum goto_move_restriction {
   GOTO_MOVE_ANY,
@@ -103,6 +111,12 @@
   int charge; /* the unit this unit is bodyguarding */
 };
 
+struct unit_goto {
+  int x, y;               /* where are we going? */
+  int origin_x, origin_y; /* from where did we start? */
+  int counter;            /* how long has this taken? */
+};
+
 struct unit {
   Unit_Type_id type;
   int id;
@@ -121,7 +135,8 @@
   int bribe_cost;
   struct unit_ai ai;
   enum unit_activity activity;
-  int goto_dest_x, goto_dest_y;
+  struct unit_goto goto_struct; /* never refer to this directly */
+  struct unit_goto *go;
   int activity_count;
   enum tile_special_type activity_target;
   enum unit_focus_status focus_status;
@@ -132,7 +147,7 @@
   bool paradropped;
   bool connecting;
   int transported_by;
-  struct goto_route *pgr;
+  struct goto_route *pgr; /* client-side goto */
 };
 
 
Index: doc/README.AI
===================================================================
RCS file: /home/freeciv/CVS/freeciv/doc/README.AI,v
retrieving revision 1.8
diff -u -r1.8 README.AI
--- doc/README.AI       2003/02/17 22:49:28     1.8
+++ doc/README.AI       2003/02/17 22:50:38
@@ -14,6 +14,7 @@
 Selecting military units
 Diplomacy
 Difficulty levels
+Goto
 Things that needs to be fixed
 Idea space
 
@@ -262,6 +263,22 @@
 is an initial PEACE mode for AIs under 'easy' difficulty.  This can be
 turned to WAR by a simple countdown timer started after first contact.
 This way 'easy' will be more easy --- a frequently requested feature.
+
+
+GOTO
+====
+
+There are two different ways to use goto. The first is temporary
+goto which lasts one turn or less. This you use ai_unit_goto()
+for, as it will preserve any multi-turn goto and roles it may 
+have. This is ideal for striking out at nearby units while not
+abandoning your overral mission. The second is goto which is
+part of a larger mission. You set your destination for this 
+through ai_unit_new_role(), which you give the coordinates for
+your target, and the you call ai_unit_gothere() to get there.
+
+See common/unit.h for a description of the various unit roles
+that you can use.
 
 
 DIFFICULTY LEVELS
Index: server/autoattack.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/autoattack.c,v
retrieving revision 1.42
diff -u -r1.42 autoattack.c
--- server/autoattack.c 2003/02/17 22:49:28     1.42
+++ server/autoattack.c 2003/02/17 22:50:39
@@ -166,21 +166,17 @@
                   unit_owner(enemy)->name, unit_name(enemy->type));
   
   set_unit_activity(punit, ACTIVITY_GOTO);
-  punit->goto_dest_x=enemy->x;
-  punit->goto_dest_y=enemy->y;
   
   send_unit_info(NULL, punit);
-  (void) do_unit_goto(punit, GOTO_MOVE_ANY, FALSE);
+  (void) do_unit_goto(punit, GOTO_MOVE_ANY, FALSE, enemy->x, enemy->y);
   
   punit = find_unit_by_id(id);
   
   if (punit) {
     set_unit_activity(punit, ACTIVITY_GOTO);
-    punit->goto_dest_x=pcity->x;
-    punit->goto_dest_y=pcity->y;
     send_unit_info(NULL, punit);
     
-    (void) do_unit_goto(punit, GOTO_MOVE_ANY, FALSE);
+    (void) do_unit_goto(punit, GOTO_MOVE_ANY, FALSE, pcity->x, pcity->y);
     
     if (unit_list_find(&map_get_tile(pcity->x, pcity->y)->units, id)) {
       handle_unit_activity_request(punit, ACTIVITY_IDLE);
@@ -231,8 +227,10 @@
     if(punit->ai.control
        && is_military_unit(punit)
        && punit->activity == ACTIVITY_GOTO
-       && punit->moves_left == unit_type(punit)->move_rate) {
-      (void) do_unit_goto(punit, GOTO_MOVE_ANY, FALSE);
+       && punit->moves_left == unit_type(punit)->move_rate
+       && punit->go) {
+      (void) do_unit_goto(punit, GOTO_MOVE_ANY, FALSE,
+                          punit->go->x, punit->go->y);
     }
   }
   unit_list_iterate_end;
Index: server/gotohand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/gotohand.c,v
retrieving revision 1.167
diff -u -r1.167 gotohand.c
--- server/gotohand.c   2003/02/17 22:49:28     1.167
+++ server/gotohand.c   2003/02/17 22:50:39
@@ -746,7 +746,7 @@
          freelog(LOG_DEBUG, "%s#%d@(%d,%d) dissuaded from (%d,%d) -> (%d,%d)",
                  unit_type(punit)->name, punit->id,
                  punit->x, punit->y, x1, y1,
-                 punit->goto_dest_x, punit->goto_dest_y);
+                 dest_x, dest_y);
        }
        break;
 
@@ -1265,7 +1265,7 @@
 **************************************************************************/
 enum goto_result do_unit_goto(struct unit *punit,
                              enum goto_move_restriction restriction,
-                             bool trigger_special_ability)
+                             bool trigger_special_ability, int gx, int gy)
 {
   struct player *pplayer = unit_owner(punit);
   int unit_id, dest_x, dest_y, waypoint_x, waypoint_y;
@@ -1278,8 +1278,8 @@
   }
 
   unit_id = punit->id;
-  dest_x = waypoint_x = punit->goto_dest_x;
-  dest_y = waypoint_y = punit->goto_dest_y;
+  dest_x = waypoint_x = gx;
+  dest_y = waypoint_y = gy;
 
   if (same_pos(punit->x, punit->y, dest_x, dest_y) ||
       !goto_is_sane(punit, dest_x, dest_y, FALSE)) {
@@ -1342,7 +1342,7 @@
       penemy = is_enemy_unit_tile(map_get_tile(x, y), unit_owner(punit));
       assert(punit->moves_left > 0);
 
-      last_tile = same_pos(x, y, punit->goto_dest_x, punit->goto_dest_y);
+      last_tile = same_pos(x, y, gx, gy);
 
       /* Call handle_unit_move_request for humans and ai_unit_move for AI */
       success = (!pplayer->ai.control 
Index: server/gotohand.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/gotohand.h,v
retrieving revision 1.26
diff -u -r1.26 gotohand.h
--- server/gotohand.h   2003/02/17 22:49:28     1.26
+++ server/gotohand.h   2003/02/17 22:50:40
@@ -31,7 +31,7 @@
 bool is_dist_finite(int dist);
 enum goto_result do_unit_goto(struct unit *punit,
                              enum goto_move_restriction restriction,
-                             bool trigger_special_ability);
+                             bool trigger_special_ability, int gx, int gy);
 void generate_warmap(struct city *pcity, struct unit *punit);
 void really_generate_warmap(struct city *pcity, struct unit *punit,
                            enum unit_move_type move_type);
Index: server/savegame.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/savegame.c,v
retrieving revision 1.114
diff -u -r1.114 savegame.c
--- server/savegame.c   2003/02/17 22:49:28     1.114
+++ server/savegame.c   2003/02/17 22:50:41
@@ -981,10 +981,19 @@
                                                "player%d.u%d.connecting",
                                                plrno, i);
 
-    punit->goto_dest_x=secfile_lookup_int(file, 
-                                         "player%d.u%d.goto_x", plrno,i);
-    punit->goto_dest_y=secfile_lookup_int(file, 
-                                         "player%d.u%d.goto_y", plrno,i);
+    /* Load the goto information.  Older savegames will not have the
+     * "go" field, so we just load the goto destination by default. */
+    if (secfile_lookup_bool_default(file, TRUE,
+                                   "player%d.u%d.go", plrno, i)) {
+      punit->go = &punit->goto_struct;
+      punit->go->x = secfile_lookup_int(file,
+                                       "player%d.u%d.goto_x", plrno, i);
+      punit->go->y = secfile_lookup_int(file, 
+                                       "player%d.u%d.goto_y", plrno, i);
+    } else {
+      punit->go = NULL;
+    }
+
     punit->ai.control=secfile_lookup_bool(file, "player%d.u%d.ai", plrno,i);
     punit->ai.ai_role = AIUNIT_NONE;
     punit->ai.ferryboat = 0;
@@ -1410,8 +1419,16 @@
     secfile_insert_int(file, punit->fuel, "player%d.u%d.fuel",
                                plrno, i);
 
-    secfile_insert_int(file, punit->goto_dest_x, "player%d.u%d.goto_x", plrno, 
i);
-    secfile_insert_int(file, punit->goto_dest_y, "player%d.u%d.goto_y", plrno, 
i);
+    if (punit->go) {
+      secfile_insert_bool(file, TRUE, "player%d.u%d.go", plrno, i);
+      secfile_insert_int(file, punit->go->x, "player%d.u%d.goto_x", plrno, i);
+      secfile_insert_int(file, punit->go->y, "player%d.u%d.goto_y", plrno, i);
+    } else {
+      secfile_insert_bool(file, FALSE, "player%d.u%d.go", plrno, i);
+      /* for compatility with older servers */
+      secfile_insert_int(file, 0, "player%d.u%d.goto_x", plrno, i);
+      secfile_insert_int(file, 0, "player%d.u%d.goto_y", plrno, i);
+    }
     secfile_insert_bool(file, punit->ai.control, "player%d.u%d.ai", plrno, i);
     secfile_insert_int(file, punit->ord_map, "player%d.u%d.ord_map", plrno, i);
     secfile_insert_int(file, punit->ord_city, "player%d.u%d.ord_city", plrno, 
i);
Index: server/settlers.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/settlers.c,v
retrieving revision 1.165
diff -u -r1.165 settlers.c
--- server/settlers.c   2003/02/17 22:49:28     1.165
+++ server/settlers.c   2003/02/17 22:50:42
@@ -458,8 +458,8 @@
 static bool is_already_assigned(struct unit *myunit, struct player *pplayer, 
     int x, int y)
 {
-  if (same_pos(myunit->x, myunit->y, x, y) ||
-      same_pos(myunit->goto_dest_x, myunit->goto_dest_y, x, y)) {
+  if (same_pos(myunit->x, myunit->y, x, y)
+      || (myunit->go && same_pos(myunit->go->x, myunit->go->y, x, y))) {
 /* I'm still not sure this is exactly right -- Syela */
     unit_list_iterate(map_get_tile(x, y)->units, punit)
       if (myunit==punit) continue;
@@ -1222,18 +1222,20 @@
     }
     ferryboat = unit_list_find(&(map_get_tile(punit->x, punit->y)->units),
                                punit->ai.ferryboat);
-    punit->goto_dest_x = gx;
-    punit->goto_dest_y = gy;
 
+    /* FIXME: _gross_ hack */
+    punit->go = &punit->goto_struct;
+    punit->go->x = gx;
+    punit->go->y = gy;
+
     if (ferryboat && (ferryboat->ai.passenger == 0
                       || ferryboat->ai.passenger == punit->id)) {
       UNIT_LOG(LOG_DEBUG, punit, "We have FOUND BOAT %d, ABOARD",
                ferryboat->id);
       handle_unit_activity_request(punit, ACTIVITY_SENTRY);
+      ai_unit_new_role(ferryboat, AIUNIT_TRANSPORT, gx, gy);
       ferryboat->ai.passenger = punit->id;
-      ferryboat->goto_dest_x = gx;
-      ferryboat->goto_dest_y = gy;
-      if (!ai_unit_goto(ferryboat, gx, gy)) {
+      if (!ai_unit_gothere(ferryboat)) {
         return FALSE; /* died */
       }
       handle_unit_activity_request(punit, ACTIVITY_IDLE);
@@ -1249,8 +1251,10 @@
       && (!ferryboat
           || (is_tiles_adjacent(punit->x, punit->y, gx, gy)
               && could_unit_move_to_tile(punit, gx, gy) != 0))) {
-    punit->goto_dest_x = gx;
-    punit->goto_dest_y = gy;
+    /* FIXME: _gross_ hack */
+    punit->go = &punit->goto_struct;
+    punit->go->x = gx;
+    punit->go->y = gy;
     if (!ai_unit_goto(punit, gx, gy)) {
       return FALSE; /* died */
     }
@@ -1311,7 +1315,7 @@
       best_act == ACTIVITY_UNKNOWN /* flag */) {
     ai_unit_new_role(punit, AIUNIT_BUILD_CITY, gx, gy);
   } else {
-    ai_unit_new_role(punit, AIUNIT_AUTO_SETTLER, gx, gy);
+    ai_unit_new_role(punit, AIUNIT_AUTO_SETTLER, -1, -1);
   }
 
   /* We've now worked out what to do; go to it! */
@@ -1426,7 +1430,7 @@
     if (unit_flag(punit, F_SETTLERS)
        || unit_flag(punit, F_CITIES)) {
       if (punit->activity == ACTIVITY_GOTO) {
-        ptile = map_get_tile(punit->goto_dest_x, punit->goto_dest_y);
+        ptile = map_get_tile(punit->go->x, punit->go->y);
         ptile->assigned = ptile->assigned | i; /* assigned for us only */
       } else {
         ptile = map_get_tile(punit->x, punit->y);
Index: server/unithand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unithand.c,v
retrieving revision 1.255
diff -u -r1.255 unithand.c
--- server/unithand.c   2003/02/17 22:49:28     1.255
+++ server/unithand.c   2003/02/17 22:50:43
@@ -76,8 +76,9 @@
     return;
   }
 
-  punit->goto_dest_x = req->x;
-  punit->goto_dest_y = req->y;
+  punit->go = &punit->goto_struct;
+  punit->go->x = req->x;
+  punit->go->y = req->y;
 
   set_unit_activity(punit, ACTIVITY_GOTO);
 
@@ -92,7 +93,7 @@
     assign_units_to_transporter(punit, TRUE);
   }
 
-  (void) do_unit_goto(punit, GOTO_MOVE_ANY, TRUE);
+  (void) do_unit_goto(punit, GOTO_MOVE_ANY, TRUE, req->x, req->y);
 }
 
 /**************************************************************************
@@ -133,8 +134,9 @@
     return;
   }
 
-  punit->goto_dest_x = req->dest_x;
-  punit->goto_dest_y = req->dest_y;
+  punit->go = &punit->goto_struct;
+  punit->go->x = req->dest_x;
+  punit->go->y = req->dest_y;
 
   set_unit_activity(punit, req->activity_type);
   punit->connecting = TRUE;
@@ -148,7 +150,7 @@
   if (!can_unit_do_activity(punit, req->activity_type)) {
     (void) do_unit_goto(punit,
                        get_activity_move_restriction(req->activity_type),
-                       FALSE);
+                       FALSE, req->dest_x, req->dest_y);
   }
 }
 
@@ -1034,7 +1036,7 @@
      * human players the server-side goto implementation should be
      * obsoleted for client usage. So in time, remove the code below. */
     if (punit->activity == ACTIVITY_GOTO && 
-        !same_pos(punit->goto_dest_x, punit->goto_dest_y, dest_x, dest_y)) {
+        !same_pos(punit->go->x, punit->go->y, dest_x, dest_y)) {
       notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT,
                       _("Game: %s aborted GOTO as there are units in the 
way."),
                       unit_type(punit)->name);
@@ -1445,8 +1447,8 @@
 #endif
 
   if (punit->activity == ACTIVITY_GOTO) {
-    punit->goto_dest_x = pgr->pos[pgr->last_index-1].x;
-    punit->goto_dest_y = pgr->pos[pgr->last_index-1].y;
+    punit->go->x = pgr->pos[pgr->last_index-1].x;
+    punit->go->y = pgr->pos[pgr->last_index-1].y;
     send_unit_info(pplayer, punit);
   }
 
Index: server/unittools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v
retrieving revision 1.213
diff -u -r1.213 unittools.c
--- server/unittools.c  2003/02/17 22:49:28     1.213
+++ server/unittools.c  2003/02/17 22:50:44
@@ -520,10 +520,8 @@
              (air_can_move_between
               (punit->moves_left / 3, punit->x, punit->y, x_itr, y_itr,
                unit_owner(punit)) >= 0)) {
-           punit->goto_dest_x = x_itr;
-           punit->goto_dest_y = y_itr;
            set_unit_activity(punit, ACTIVITY_GOTO);
-           (void) do_unit_goto(punit, GOTO_MOVE_ANY, FALSE);
+           (void) do_unit_goto(punit, GOTO_MOVE_ANY, FALSE, x_itr, y_itr);
            notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, 
                             _("Game: Your %s has returned to refuel."),
                             unit_name(punit->type));
@@ -721,10 +719,11 @@
 
   unit_restore_movepoints(pplayer, punit);
 
-  if (punit->connecting && !can_unit_do_activity(punit, activity)) {
+  if (punit->connecting && !can_unit_do_activity(punit, activity)
+      && punit->go) {
     punit->activity_count = 0;
-    if (do_unit_goto(punit, get_activity_move_restriction(activity), FALSE)
-       == GR_DIED) {
+    if (do_unit_goto(punit, get_activity_move_restriction(activity), 
+                     FALSE, punit->go->x, punit->go->y) == GR_DIED) {
       return;
     }
   }
@@ -907,11 +906,12 @@
     unit_list_iterate (map_get_tile(punit->x, punit->y)->units, punit2) {
       if (punit2->activity == activity) {
        bool alive = TRUE;
-       if (punit2->connecting) {
+       if (punit2->connecting && punit->go) {
          punit2->activity_count = 0;
          alive = (do_unit_goto(punit2,
                                get_activity_move_restriction(activity),
-                               FALSE) != GR_DIED);
+                               FALSE, punit->go->x, punit->go->y)
+                  != GR_DIED);
        } else {
          set_unit_activity(punit2, ACTIVITY_IDLE);
        }
@@ -929,11 +929,13 @@
   }
 
   if (activity==ACTIVITY_GOTO) {
-    if (!punit->ai.control && (!is_military_unit(punit) ||
-       punit->ai.passenger != 0 || !pplayer->ai.control)) {
+    assert(punit->go != NULL);
+    if (punit->go && !punit->ai.control && (!is_military_unit(punit)
+        || punit->ai.passenger != 0 || !pplayer->ai.control)) {
 /* autosettlers otherwise waste time; idling them breaks assignment */
 /* Stalling infantry on GOTO so I can see where they're GOing TO. -- Syela */
-      (void) do_unit_goto(punit, GOTO_MOVE_ANY, TRUE);
+      (void) do_unit_goto(punit, GOTO_MOVE_ANY, TRUE, punit->go->x, 
+                          punit->go->y);
     }
     return;
   }
@@ -1569,8 +1571,7 @@
   punit->x = x;
   punit->y = y;
 
-  punit->goto_dest_x=0;
-  punit->goto_dest_y=0;
+  punit->go = NULL;
   
   pcity=find_city_by_id(homecity_id);
   punit->veteran=make_veteran;
@@ -1924,8 +1925,6 @@
   packet->upkeep_gold = punit->upkeep_gold;
   packet->ai = punit->ai.control;
   packet->fuel = punit->fuel;
-  packet->goto_dest_x = punit->goto_dest_x;
-  packet->goto_dest_y = punit->goto_dest_y;
   packet->activity_target = punit->activity_target;
   packet->paradropped = punit->paradropped;
   packet->connecting = punit->connecting;
@@ -2910,9 +2909,9 @@
     }
   }
   /* A transporter should not take units with it when on an attack goto -- 
fisch */
-  if ((punit->activity == ACTIVITY_GOTO) &&
-      get_defender(punit, punit->goto_dest_x, punit->goto_dest_y) &&
-      !is_ocean(psrctile->terrain)) {
+  if ((punit->activity == ACTIVITY_GOTO || punit->go)
+      && get_defender(punit, punit->go->x, punit->go->y)
+      && !is_ocean(psrctile->terrain)) {
     transport_units = FALSE;
   }
 
@@ -2987,8 +2986,8 @@
       && is_ocean(pdesttile->terrain)
       && !(pplayer->ai.control)
       && !(punit->activity == ACTIVITY_GOTO      /* if unit is GOTOing and the 
ship */ 
-          && (dest_x != punit->goto_dest_x      /* isn't the final destination 
*/
-              || dest_y != punit->goto_dest_y)) /* then don't go to sleep */
+          && (dest_x != punit->go->x      /* isn't the final destination */
+              || dest_y != punit->go->y)) /* then don't go to sleep */
       ) {
     set_unit_activity(punit, ACTIVITY_SENTRY);
   }

[Prev in Thread] Current Thread [Next in Thread]