Complete.Org: Mailing Lists: Archives: freeciv-dev: January 2004:
[Freeciv-Dev] (PR#7282) connect as orders
Home

[Freeciv-Dev] (PR#7282) connect as orders

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] (PR#7282) connect as orders
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Tue, 20 Jan 2004 13:47:07 -0800
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=7282 >

Here is a preliminary patch to implement the "connect" functionality 
using orders.

Currently it only works for road, rail, and irrigation.  I'm not sure 
other behaviors are worth it...

It works fairly well in that (1) you get to see the path to be taken and 
(2) a near-optimal path is found.  I say "near-optimal" because the PF 
code is a bit shaky and with all the code I've duplicated from common/ 
there's a good chance for missing cases.

Tilespec needs a bit of work.

The patch includes the basic orders patch.

jason

Index: ai/aiunit.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.c,v
retrieving revision 1.306
diff -u -r1.306 aiunit.c
--- ai/aiunit.c 2004/01/11 17:45:02     1.306
+++ ai/aiunit.c 2004/01/20 21:44:09
@@ -196,7 +196,7 @@
 
   result =
       test_unit_move_to_tile(punit->type, unit_owner(punit),
-                             ACTIVITY_IDLE, FALSE, punit->x, punit->y, 
+                             ACTIVITY_IDLE, punit->x, punit->y, 
                              dest_x, dest_y, unit_flag(punit, F_IGZOC));
   if (result == MR_OK) {
     return 1;
Index: client/control.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/control.c,v
retrieving revision 1.123
diff -u -r1.123 control.c
--- client/control.c    2004/01/09 16:59:50     1.123
+++ client/control.c    2004/01/20 21:44:09
@@ -55,6 +55,7 @@
 /* These should be set via set_hover_state() */
 int hover_unit = 0; /* id of unit hover_state applies to */
 enum cursor_hover_state hover_state = HOVER_NONE;
+enum unit_activity connect_activity;
 /* This may only be here until client goto is fully implemented.
    It is reset each time the hower_state is reset. */
 bool draw_goto_line = TRUE;
@@ -79,15 +80,18 @@
 /**************************************************************************
 ...
 **************************************************************************/
-void set_hover_state(struct unit *punit, enum cursor_hover_state state)
+void set_hover_state(struct unit *punit, enum cursor_hover_state state,
+                    enum unit_activity activity)
 {
   assert(punit != NULL || state == HOVER_NONE);
+  assert(state == HOVER_CONNECT || activity == ACTIVITY_LAST);
   draw_goto_line = TRUE;
   if (punit)
     hover_unit = punit->id;
   else
     hover_unit = 0;
   hover_state = state;
+  connect_activity = activity;
   exit_goto_state();
 }
 
@@ -129,6 +133,10 @@
     punit->focus_status=FOCUS_AVAIL;
     refresh_tile_mapcanvas(punit->x, punit->y, FALSE);
 
+    if (unit_has_orders(punit)) {
+      /* Clear the focus unit's orders. */
+      request_orders_cleared(punit);
+    }
     if (punit->activity != ACTIVITY_IDLE || punit->ai.control)  {
       punit->activity = ACTIVITY_IDLE;
       punit->ai.control = FALSE;
@@ -180,6 +188,7 @@
 {
   if (!punit_focus
       || (punit_focus->activity != ACTIVITY_IDLE
+         && !unit_has_orders(punit_focus)
          && punit_focus->activity != ACTIVITY_GOTO)
       || punit_focus->done_moving
       || punit_focus->moves_left == 0 
@@ -208,7 +217,7 @@
   struct unit *punit_old_focus = punit_focus;
   struct unit *candidate = find_best_focus_candidate(FALSE);
 
-  set_hover_state(NULL, HOVER_NONE);
+  set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST);
 
   if(!candidate) {
     /* First try for "waiting" units. */
@@ -269,6 +278,7 @@
     if ((punit != punit_focus || accept_current)
       && punit->focus_status == FOCUS_AVAIL
       && punit->activity == ACTIVITY_IDLE
+       && !unit_has_orders(punit)
       && punit->moves_left > 0
       && !punit->done_moving
       && !punit->ai.control) {
@@ -392,18 +402,23 @@
 void update_unit_pix_label(struct unit *punit)
 {
   static enum unit_activity prev_activity = ACTIVITY_UNKNOWN;
+  static bool prev_has_orders = FALSE;
   static Unit_Type_id prev_unit_type = U_LAST;
   static int prev_hp = -1;              /* or could store ihp cf tilespec.c */
   
   int i;
-  
+
+  /* Check for any change in the unit's state.  This assumes that a unit's
+   * orders cannot be changed directly but must be removed and then reset. */
   if (punit && get_client_state() != CLIENT_GAME_OVER_STATE) {
     if (punit->type != prev_unit_type
        || punit->activity != prev_activity
+       || punit->has_orders != prev_has_orders
        || punit->hp != prev_hp) {
       set_unit_icon(-1, punit);
       prev_unit_type = punit->type;
       prev_activity = punit->activity;
+      prev_has_orders = punit->has_orders;
       prev_hp = punit->hp;
     }
 
@@ -430,6 +445,7 @@
   else {
     prev_unit_type = U_LAST;
     prev_activity = ACTIVITY_UNKNOWN;
+    prev_has_orders = FALSE;
     prev_hp = -1;
     for(i=-1; i<num_units_below; i++) {
       set_unit_icon(i, NULL);
@@ -580,7 +596,7 @@
     return;
 
   if (hover_state != HOVER_GOTO) {
-    set_hover_state(punit, HOVER_GOTO);
+    set_hover_state(punit, HOVER_GOTO, ACTIVITY_LAST);
     update_unit_info_label(punit);
     /* Not yet implemented for air units, including helicopters. */
     if (is_air_unit(punit) || is_heli_unit(punit)) {
@@ -599,11 +615,21 @@
 prompt player for entering destination point for unit connect
 (e.g. connecting with roads)
 **************************************************************************/
-void request_unit_connect(void)
+void request_unit_connect(enum unit_activity activity)
 {
-  if (punit_focus && can_unit_do_connect (punit_focus, ACTIVITY_IDLE)) {
-    set_hover_state(punit_focus, HOVER_CONNECT);
+  if (!punit_focus || !can_unit_do_connect (punit_focus, activity)) {
+    return;
+  }
+
+  if (hover_state != HOVER_GOTO && connect_activity != activity) {
+    set_hover_state(punit_focus, HOVER_CONNECT, activity);
     update_unit_info_label(punit_focus);
+
+    enter_goto_state(punit_focus);
+    create_line_at_mouse_pos();
+  } else {
+    assert(goto_is_active());
+    goto_add_waypoint();
   }
 }
 
@@ -821,7 +847,7 @@
   if(punit->moves_left == 0)
     do_unit_nuke(punit);
   else {
-    set_hover_state(punit, HOVER_NUKE);
+    set_hover_state(punit, HOVER_NUKE, ACTIVITY_LAST);
     update_unit_info_label(punit);
   }
 }
@@ -838,7 +864,7 @@
   if(!can_unit_paradrop(punit))
     return;
 
-  set_hover_state(punit, HOVER_PARADROP);
+  set_hover_state(punit, HOVER_PARADROP, ACTIVITY_LAST);
   update_unit_info_label(punit);
 }
 
@@ -853,7 +879,7 @@
     return;
 
   if (hover_state != HOVER_PATROL) {
-    set_hover_state(punit, HOVER_PATROL);
+    set_hover_state(punit, HOVER_PATROL, ACTIVITY_LAST);
     update_unit_info_label(punit);
     /* Not yet implemented for air units, including helicopters. */
     if (is_air_unit(punit) || is_heli_unit(punit)) {
@@ -1194,6 +1220,7 @@
   
   if (game.player_idx == punit->owner
       && auto_center_on_unit
+      && !unit_has_orders(punit)
       && punit->activity != ACTIVITY_GOTO
       && punit->activity != ACTIVITY_SENTRY
       && !tile_visible_and_not_on_border_mapcanvas(target_unit->x,
@@ -1270,13 +1297,13 @@
       do_unit_paradrop_to(punit, xtile, ytile);
       break;
     case HOVER_CONNECT:
-      popup_unit_connect_dialog(punit, xtile, ytile);
+      do_unit_connect(punit, xtile, ytile, connect_activity);
       break;
     case HOVER_PATROL:
       do_unit_patrol_to(punit, xtile, ytile);
       break;   
     }
-    set_hover_state(NULL, HOVER_NONE);
+    set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST);
     update_unit_info_label(punit);
   }
 
@@ -1470,7 +1497,7 @@
     }
   }
 
-  set_hover_state(NULL, HOVER_NONE);
+  set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST);
 }
 
 /**************************************************************************
@@ -1507,8 +1534,30 @@
       append_output_window(_("Game: Didn't find a route to the destination!"));
     }
   }
+
+  set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST);
+}
+ 
+/**************************************************************************
+Paradrop to a location
+**************************************************************************/
+void do_unit_connect(struct unit *punit, int x, int y,
+                    enum unit_activity activity)
+{
+  if (is_air_unit(punit)) {
+    append_output_window(_("Game: Sorry, airunit connect not yet 
implemented."));
+  } else {
+    int dest_x, dest_y;
+    draw_line(x, y);
+    get_line_dest(&dest_x, &dest_y);
+    if (same_pos(dest_x, dest_y, x, y)) {
+      send_connect_route(punit, activity);
+    } else {
+      append_output_window(_("Game: Didn't find a route to the destination!"));
+    }
+  }
 
-  set_hover_state(NULL, HOVER_NONE);
+  set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST);
 }
  
 /**************************************************************************
@@ -1527,7 +1576,7 @@
   if (hover_state != HOVER_NONE && !popped) {
     struct unit *punit = player_find_unit_by_id(game.player_ptr, hover_unit);
 
-    set_hover_state(NULL, HOVER_NONE);
+    set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST);
     update_unit_info_label(punit);
 
     keyboardless_goto_button_down = FALSE;
@@ -1608,10 +1657,10 @@
 /**************************************************************************
 handle user pressing key for 'Connect' command
 **************************************************************************/
-void key_unit_connect(void)
+void key_unit_connect(enum unit_activity activity)
 {
   if (punit_focus) {
-    request_unit_connect();
+    request_unit_connect(activity);
   }
 }
 
Index: client/control.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/control.h,v
retrieving revision 1.40
diff -u -r1.40 control.h
--- client/control.h    2003/12/16 15:07:52     1.40
+++ client/control.h    2004/01/20 21:44:09
@@ -31,6 +31,7 @@
 
 extern int hover_unit; /* unit hover_state applies to */
 extern enum cursor_hover_state hover_state;
+extern enum unit_activity connect_activity;
 extern bool draw_goto_line;
 extern bool non_ai_unit_focus;
 
@@ -39,9 +40,12 @@
 void do_unit_nuke(struct unit *punit);
 void do_unit_paradrop_to(struct unit *punit, int x, int y);
 void do_unit_patrol_to(struct unit *punit, int x, int y);
+void do_unit_connect(struct unit *punit, int x, int y,
+                    enum unit_activity activity);
 void do_map_click(int xtile, int ytile, enum quickselect_type qtype);
 
-void set_hover_state(struct unit *punit, enum cursor_hover_state state);
+void set_hover_state(struct unit *punit, enum cursor_hover_state state,
+                    enum unit_activity activity);
 void request_center_focus_unit(void);
 void request_move_unit_direction(struct unit *punit, int dir);
 void request_new_unit_activity(struct unit *punit, enum unit_activity act);
@@ -52,7 +56,7 @@
 void request_unit_build_city(struct unit *punit);
 void request_unit_caravan_action(struct unit *punit, enum packet_type action);
 void request_unit_change_homecity(struct unit *punit);
-void request_unit_connect(void);
+void request_unit_connect(enum unit_activity activity);
 void request_unit_disband(struct unit *punit);
 void request_unit_fortify(struct unit *punit);
 void request_unit_goto(void);
@@ -133,7 +137,7 @@
 void key_unit_auto_settle(void);
 void key_unit_build_city(void);
 void key_unit_build_wonder(void);
-void key_unit_connect(void);
+void key_unit_connect(enum unit_activity activity);
 void key_unit_diplomat_actions(void);
 void key_unit_disband(void);
 void key_unit_done(void);
Index: client/goto.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/goto.c,v
retrieving revision 1.65
diff -u -r1.65 goto.c
--- client/goto.c       2004/01/10 13:05:59     1.65
+++ client/goto.c       2004/01/20 21:44:10
@@ -365,6 +365,80 @@
   return TB_NORMAL;
 }
 
+static int (*original_MC) (int from_x, int from_y, enum direction8 dir,
+                     int to_x, int to_y, struct pf_parameter *param);
+
+/********************************************************************** 
+  PF callback for move cost. Caravans doesn't go into the unknown and
+  don't attack enemy units but enter enemy cities.
+***********************************************************************/
+static int get_MC(int from_x, int from_y, enum direction8 dir,
+                 int to_x, int to_y, struct pf_parameter *param)
+{
+  int base_mc = original_MC(from_x, from_y, dir, to_x, to_y, param);
+  struct tile *ptile = map_get_tile(to_x, to_y);
+  int activity_mc = 0;
+  struct tile_type *ttype = get_tile_type(map_get_terrain(to_x, to_y));
+
+  if (base_mc == PF_IMPOSSIBLE_MC) {
+    return base_mc;
+  }
+
+  if (hover_state == HOVER_CONNECT) {
+    switch (connect_activity) {
+    case ACTIVITY_IRRIGATE:
+      if (!DIR_IS_CARDINAL(dir)) {
+       return PF_IMPOSSIBLE_MC;
+      }
+      if (tile_has_special(ptile, S_IRRIGATION)) {
+       break;
+      }
+
+      activity_mc = ttype->irrigation_time;
+      if (activity_mc == 0) {
+       return PF_IMPOSSIBLE_MC;
+      }
+      break;
+    case ACTIVITY_ROAD:
+      if (tile_has_special(ptile, S_ROAD)) {
+       break;
+      }
+      activity_mc = ttype->road_time;
+      if (activity_mc == 0
+         || !terrain_control.may_road
+         || ((map_has_special(to_x, to_y, S_RIVER)
+              || map_get_terrain(to_x, to_y) == T_RIVER)
+             && !player_knows_techs_with_flag(param->owner, TF_BRIDGE))) {
+       return PF_IMPOSSIBLE_MC;
+      }
+      break;
+    case ACTIVITY_RAILROAD:
+      if (!terrain_control.may_road || ttype->road_time == 0) {
+       return PF_IMPOSSIBLE_MC;
+      }
+      if (tile_has_special(ptile, S_RAILROAD)) {
+       break;
+      } else {
+       if ((map_has_special(to_x, to_y, S_RIVER)
+            || map_get_terrain(to_x, to_y) == T_RIVER)
+           && !player_knows_techs_with_flag(param->owner, TF_BRIDGE)) {
+         return PF_IMPOSSIBLE_MC;
+       }
+       if (!tile_has_special(ptile, S_ROAD)) {
+         activity_mc += ttype->road_time;
+       }
+       activity_mc += ttype->road_time;
+      }
+      break;
+    default:
+      die("Invalid connect activity.");
+    }
+  }
+
+  base_mc += activity_mc * param->move_rate;
+  return base_mc;
+}
+
 /********************************************************************** 
   Fill the PF parameter with the correct client-goto values.
 ***********************************************************************/
@@ -376,6 +450,9 @@
   assert(parameter->get_EC == NULL);
   parameter->get_EC = get_EC;
   assert(parameter->get_TB == NULL);
+  assert(parameter->get_MC != NULL);
+  original_MC = parameter->get_MC;
+  parameter->get_MC = get_MC;
   if (is_attack_unit(punit) || is_diplomat_unit(punit)) {
     parameter->get_TB = get_TB_aggr;
   } else if (unit_flag(punit, F_TRADE_ROUTE)
@@ -464,30 +541,73 @@
   update_last_part(dest_x, dest_y);
 }
 
+/****************************************************************************
+  Send a packet to the server to request that the current orders be
+  cleared.
+****************************************************************************/
+void request_orders_cleared(struct unit *punit)
+{
+  struct packet_unit_orders p;
+
+  /* Clear the orders by sending an empty orders path. */
+  freelog(PACKET_LOG_LEVEL, "Clearing orders for unit %d.", punit->id);
+  p.unit_id = punit->id;
+  p.repeat = p.vigilant = FALSE;
+  p.length = 0;
+  p.dest_x = punit->x;
+  p.dest_y = punit->y;
+  send_packet_unit_orders(&aconnection, &p);
+}
+
 /**************************************************************************
   Send a path as a goto or patrol route to the server.
 **************************************************************************/
-static void send_path_route(struct unit *punit, struct pf_path *path,
-                           enum unit_activity activity)
+static void send_path_orders(struct unit *punit, struct pf_path *path,
+                            bool repeat, bool vigilant)
 {
-  struct packet_unit_route p;
-  int i;
+  struct packet_unit_orders p;
+  int i, old_x, old_y;
 
   p.unit_id = punit->id;
-  p.activity = activity;
+  p.repeat = repeat;
+  p.vigilant = vigilant;
+
+  freelog(PACKET_LOG_LEVEL, "Orders for unit %d:", punit->id);
 
-  /* we skip the start position */
+  /* We skip the start position. */
   p.length = path->length - 1;
   assert(p.length < MAX_LEN_ROUTE);
+  old_x = path->positions[0].x;
+  old_y = path->positions[0].y;
+
+  freelog(PACKET_LOG_LEVEL, "  Repeat: %d.  Vigilant: %d.  Length: %d",
+         p.repeat, p.vigilant, p.length);
 
+  /* If the path has n positions it takes n-1 steps. */
   for (i = 0; i < path->length - 1; i++) {
-    p.x[i] = path->positions[i + 1].x;
-    p.y[i] = path->positions[i + 1].y;
-    freelog(PACKET_LOG_LEVEL, "  packet[%d] = (%d,%d)",
-           i, p.x[i], p.y[i]);
+    int new_x = path->positions[i + 1].x;
+    int new_y = path->positions[i + 1].y;
+
+    if (same_pos(new_x, new_y, old_x, old_y)) {
+      p.orders[i] = ORDER_FINISH_TURN;
+      p.dir[i] = -1;
+      freelog(PACKET_LOG_LEVEL, "  packet[%d] = wait: %d,%d",
+             i, old_x, old_y);
+    } else {
+      p.orders[i] = ORDER_MOVE;
+      p.dir[i] = get_direction_for_step(old_x, old_y, new_x, new_y);
+      freelog(PACKET_LOG_LEVEL, "  packet[%d] = move %s: %d,%d => %d,%d",
+             i, dir_get_name(p.dir[i]), old_x, old_y, new_x, new_y);
+      p.activity[i] = ACTIVITY_LAST;
+    }
+    old_x = new_x;
+    old_y = new_y;
   }
+
+  p.dest_x = old_x;
+  p.dest_y = old_y;
 
-  send_packet_unit_route(&aconnection, &p);
+  send_packet_unit_orders(&aconnection, &p);
 }
 
 /**************************************************************************
@@ -495,7 +615,7 @@
 **************************************************************************/
 void send_goto_path(struct unit *punit, struct pf_path *path)
 {
-  send_path_route(punit, path, ACTIVITY_GOTO);
+  send_path_orders(punit, path, FALSE, FALSE);
 }
 
 /**************************************************************************
@@ -531,9 +651,88 @@
   pf_destroy_map(map);
   pf_destroy_path(return_path);
 
-  send_path_route(punit, path, ACTIVITY_PATROL);
+  send_path_orders(punit, path, TRUE, TRUE);
 
   pf_destroy_path(path);
+}
+
+/**************************************************************************
+  Send the current connect route (i.e., the one generated via HOVER_STATE)
+  to the server.
+**************************************************************************/
+void send_connect_route(struct unit *punit, enum unit_activity activity)
+{
+  struct pf_path *path = NULL;
+  int i;
+  struct packet_unit_orders p;
+  int old_x, old_y;
+
+  assert(is_active);
+  assert(punit->id == goto_map.unit_id);
+
+  for (i = 0; i < goto_map.num_parts; i++) {
+    path = pft_concat(path, goto_map.parts[i].path);
+  }
+
+  p.unit_id = punit->id;
+  p.repeat = FALSE;
+  p.vigilant = FALSE; /* Should be TRUE? */
+
+  p.length = 0;
+  old_x = path->positions[0].x;
+  old_y = path->positions[0].y;
+
+  for (i = 0; i < path->length; i++) {
+    switch (activity) {
+    case ACTIVITY_IRRIGATE:
+      if (!map_has_special(old_x, old_y, S_IRRIGATION)
+         /* and unit can irrigate here */) {
+       p.orders[p.length] = ORDER_ACTIVITY;
+       p.activity[p.length] = ACTIVITY_IRRIGATE;
+       p.length++;
+      }
+      break;
+    case ACTIVITY_ROAD:
+    case ACTIVITY_RAILROAD:
+      if (!map_has_special(old_x, old_y, S_ROAD)
+         /* and unit can build road here */) {
+       p.orders[p.length] = ORDER_ACTIVITY;
+       p.activity[p.length] = ACTIVITY_ROAD;
+       p.length++;
+      }
+      if (activity == ACTIVITY_RAILROAD) {
+       if (!map_has_special(old_x, old_y, S_RAILROAD)
+           /* and unit can build rail here */) {
+         p.orders[p.length] = ORDER_ACTIVITY;
+         p.activity[p.length] = ACTIVITY_RAILROAD;
+         p.length++;
+       }
+      }
+      break;
+    default:
+      die("Invalid connect activity.");
+      break;
+    }
+
+    if (i != path->length - 1) {
+      int new_x = path->positions[i + 1].x;
+      int new_y = path->positions[i + 1].y;
+
+      assert(!same_pos(new_x, new_y, old_x, old_y));
+
+      p.orders[p.length] = ORDER_MOVE;
+      p.dir[p.length] = get_direction_for_step(old_x, old_y, new_x, new_y);
+      p.length++;
+
+      old_x = new_x;
+      old_y = new_y;
+    }
+  }
+
+  p.dest_x = old_x;
+  p.dest_y = old_y;
+
+  send_packet_unit_orders(&aconnection, &p);
 }
 
 /**************************************************************************
Index: client/goto.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/goto.h,v
retrieving revision 1.10
diff -u -r1.10 goto.h
--- client/goto.h       2003/08/11 02:31:38     1.10
+++ client/goto.h       2004/01/20 21:44:10
@@ -29,9 +29,11 @@
 void draw_line(int dest_x, int dest_y);
 int get_drawn(int x, int y, int dir);
 
+void request_orders_cleared(struct unit *punit);
 void send_goto_path(struct unit *punit, struct pf_path *path);
 void send_patrol_route(struct unit *punit);
 void send_goto_route(struct unit *punit);
+void send_connect_route(struct unit *punit, enum unit_activity activity);
 
 struct pf_path *path_to_nearest_allied_city(struct unit *punit);
 
Index: client/mapctrl_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapctrl_common.c,v
retrieving revision 1.25
diff -u -r1.25 mapctrl_common.c
--- client/mapctrl_common.c     2004/01/09 16:59:50     1.25
+++ client/mapctrl_common.c     2004/01/20 21:44:10
@@ -407,7 +407,7 @@
     struct unit *punit =
         player_find_unit_by_id(game.player_ptr, hover_unit);
     do_unit_goto(tile_x, tile_y);
-    set_hover_state(NULL, HOVER_NONE);
+    set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST);
     update_unit_info_label(punit);
   }
   keyboardless_goto_active = FALSE;
@@ -599,7 +599,9 @@
 **************************************************************************/
 void update_line(int canvas_x, int canvas_y)
 {
-  if ((hover_state == HOVER_GOTO || hover_state == HOVER_PATROL)
+  if ((hover_state == HOVER_GOTO
+       || hover_state == HOVER_PATROL
+       || hover_state == HOVER_CONNECT)
       && draw_goto_line) {
     int x, y, old_x, old_y;
 
@@ -619,7 +621,9 @@
 ****************************************************************************/
 void overview_update_line(int overview_x, int overview_y)
 {
-  if ((hover_state == HOVER_GOTO || hover_state == HOVER_PATROL)
+  if ((hover_state == HOVER_GOTO
+       || hover_state == HOVER_PATROL
+       || hover_state == HOVER_CONNECT)
       && draw_goto_line) {
     int x, y, old_x, old_y;
 
Index: client/mapview_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.c,v
retrieving revision 1.72
diff -u -r1.72 mapview_common.c
--- client/mapview_common.c     2004/01/16 02:08:50     1.72
+++ client/mapview_common.c     2004/01/20 21:44:10
@@ -1248,7 +1248,7 @@
   }
 
   if (punit == get_unit_in_focus() && hover_state != HOVER_NONE) {
-    set_hover_state(NULL, HOVER_NONE);
+    set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST);
     update_unit_info_label(punit);
   }
 
Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.344
diff -u -r1.344 packhand.c
--- client/packhand.c   2004/01/18 17:55:26     1.344
+++ client/packhand.c   2004/01/20 21:44:11
@@ -108,7 +108,6 @@
   }
   punit->activity_target = packet->activity_target;
   punit->paradropped = packet->paradropped;
-  punit->connecting = packet->connecting;
   punit->done_moving = packet->done_moving;
   punit->occupy = packet->occupy;
   if (packet->carried) {
@@ -116,6 +115,9 @@
   } else {
     punit->transported_by = 0;
   }
+  punit->has_orders = packet->has_orders;
+  punit->orders.repeat = packet->repeat;
+  punit->orders.vigilant = packet->vigilant;
   return punit;
 }
 
@@ -936,14 +938,18 @@
     }
 
     if (punit->activity != packet_unit->activity
-        || punit->activity_target != packet_unit->activity_target) {
+        || punit->activity_target != packet_unit->activity_target
+       || punit->has_orders != packet_unit->has_orders
+       || punit->orders.repeat != packet_unit->orders.repeat
+       || punit->orders.vigilant != packet_unit->orders.vigilant) {
       /*** Change in activity or activity's target. ***/
 
       /* May change focus if focus unit gets a new activity.
        * But if new activity is Idle, it means user specifically selected
        * the unit */
       if (punit == get_unit_in_focus()
-         && packet_unit->activity != ACTIVITY_IDLE) {
+         && (packet_unit->activity != ACTIVITY_IDLE
+             || packet_unit->has_orders)) {
         check_focus = TRUE;
       }
 
@@ -972,6 +978,9 @@
 
       punit->activity = packet_unit->activity;
       punit->activity_target = packet_unit->activity_target;
+      punit->has_orders = packet_unit->has_orders;
+      punit->orders.repeat = packet_unit->orders.repeat;
+      punit->orders.vigilant = packet_unit->orders.vigilant;
 
       if (punit->owner == game.player_idx) {
         refresh_unit_city_dialogs(punit);
@@ -1072,9 +1081,7 @@
         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(goto_dest_x(punit), goto_dest_y(punit),
-                          pcity->x, pcity->y))
+          && !unit_has_orders(punit)
           && (unit_can_help_build_wonder_here(punit)
               || unit_can_est_traderoute_here(punit))) {
          process_caravan_arrival(punit);
@@ -1117,7 +1124,6 @@
       clear_goto_dest(punit);
     }
     punit->paradropped = packet_unit->paradropped;
-    punit->connecting = packet_unit->connecting;
     if (punit->done_moving != packet_unit->done_moving) {
       punit->done_moving = packet_unit->done_moving;
       check_focus = TRUE;
Index: client/tilespec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v
retrieving revision 1.136
diff -u -r1.136 tilespec.c
--- client/tilespec.c   2004/01/16 16:01:25     1.136
+++ client/tilespec.c   2004/01/20 21:44:11
@@ -1505,12 +1505,13 @@
     }
   }
 
-  if (punit->connecting) {
-    ADD_SPRITE_SIMPLE(sprites.unit.connect);
-  }
-
-  if (punit->activity == ACTIVITY_PATROL) {
-    ADD_SPRITE_SIMPLE(sprites.unit.patrol);
+  if (unit_has_orders(punit)) {
+    if (punit->orders.repeat) {
+      ADD_SPRITE_SIMPLE(sprites.unit.patrol);
+    } else {
+      ADD_SPRITE_SIMPLE(sprites.unit.go_to);
+    }
+    /* FIXME: connect sprite. */
   }
 
   if (stack) {
Index: client/gui-gtk/menu.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/menu.c,v
retrieving revision 1.80
diff -u -r1.80 menu.c
--- client/gui-gtk/menu.c       2003/11/06 11:54:34     1.80
+++ client/gui-gtk/menu.c       2004/01/20 21:44:11
@@ -1146,8 +1146,6 @@
                           can_unit_do_activity(punit, ACTIVITY_EXPLORE));
       menus_set_sensitive("<main>/_Orders/_Connect",
                           can_unit_do_connect(punit, ACTIVITY_IDLE));
-      menus_set_sensitive("<main>/_Orders/Patrol (_Q)",
-                          can_unit_do_activity(punit, ACTIVITY_PATROL));
       menus_set_sensitive("<main>/_Orders/Return to nearest city",
                          !(is_air_unit(punit) || is_heli_unit(punit)));
       menus_set_sensitive("<main>/_Orders/_Disband Unit",
Index: client/gui-gtk-2.0/dialogs.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/dialogs.c,v
retrieving revision 1.57
diff -u -r1.57 dialogs.c
--- client/gui-gtk-2.0/dialogs.c        2004/01/12 16:59:16     1.57
+++ client/gui-gtk-2.0/dialogs.c        2004/01/20 21:44:12
@@ -125,11 +125,6 @@
 
 static GtkWidget *caravan_dialog;
 
-static int is_showing_unit_connect_dialog = FALSE;
-static int unit_to_use_to_connect;
-static int connect_unit_x;
-static int connect_unit_y;
-
 /****************************************************************
 ...
 *****************************************************************/
@@ -1225,77 +1220,6 @@
     g_signal_connect(shl, "destroy", G_CALLBACK(pillage_destroy_callback),
                     NULL);   
   }
-}
-
-/****************************************************************
-handle buttons in unit connect dialog
-*****************************************************************/
-static void unit_connect_callback(GtkWidget *w, gpointer data)
-{
-  struct unit *punit;
-  int activity = GPOINTER_TO_INT(data);
-
-  punit = find_unit_by_id(unit_to_use_to_connect);
-
-  if (punit) {
-    if (activity != ACTIVITY_IDLE) {
-      struct packet_unit_connect req;
-      req.activity_type = activity;
-      req.unit_id = punit->id;
-      req.dest_x = connect_unit_x;
-      req.dest_y = connect_unit_y;
-      send_packet_unit_connect(&aconnection, &req);
-    }
-    else {
-      update_unit_info_label(punit);
-    }
-  }
-}
-
-/****************************************************************
-...
-*****************************************************************/
-static void unit_connect_destroy_callback(GtkWidget *w, gpointer data)
-{
-  is_showing_unit_connect_dialog = FALSE;
-}
-
-/****************************************************************
-popup dialog which prompts for activity type (unit connect)
-*****************************************************************/
-void popup_unit_connect_dialog(struct unit *punit, int dest_x, int dest_y)
-{
-  GtkWidget *shl;
-  int activity;
-
-  if (is_showing_unit_connect_dialog) 
-    return;
-
-  is_showing_unit_connect_dialog = TRUE;
-  unit_to_use_to_connect = punit->id;
-  connect_unit_x = dest_x;
-  connect_unit_y = dest_y;
-
-  shl = message_dialog_start(GTK_WINDOW(toplevel),
-                            _("Connect"),
-                            _("Choose unit activity:"));
-
-  for (activity = ACTIVITY_IDLE + 1; activity < ACTIVITY_LAST; activity++) {
-    if (! can_unit_do_connect (punit, activity)) continue;
-
-    message_dialog_add(shl, get_activity_text(activity),
-                      G_CALLBACK(unit_connect_callback),
-                      GINT_TO_POINTER(activity));
-  }
-
-  message_dialog_add(shl, GTK_STOCK_CANCEL, 
-                    G_CALLBACK(unit_connect_callback),
-                    GINT_TO_POINTER(ACTIVITY_IDLE));
-
-  message_dialog_end(shl);
-
-  g_signal_connect(shl, "destroy",
-                  G_CALLBACK(unit_connect_destroy_callback), NULL);
 }
 
 /****************************************************************
Index: client/gui-gtk-2.0/mapview.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/mapview.c,v
retrieving revision 1.85
diff -u -r1.85 mapview.c
--- client/gui-gtk-2.0/mapview.c        2004/01/11 17:45:03     1.85
+++ client/gui-gtk-2.0/mapview.c        2004/01/20 21:44:12
@@ -327,7 +327,7 @@
     gtk_set_label( unit_info_label, buffer);
 
     if (hover_unit != punit->id)
-      set_hover_state(NULL, HOVER_NONE);
+      set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST);
 
     switch (hover_state) {
     case HOVER_NONE:
Index: client/gui-gtk-2.0/menu.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/menu.c,v
retrieving revision 1.25
diff -u -r1.25 menu.c
--- client/gui-gtk-2.0/menu.c   2003/11/09 04:06:50     1.25
+++ client/gui-gtk-2.0/menu.c   2004/01/20 21:44:12
@@ -117,7 +117,9 @@
   MENU_ORDER_WAKEUP_OTHERS,
   MENU_ORDER_AUTO_SETTLER,   /* shared with AUTO_ATTACK */
   MENU_ORDER_AUTO_EXPLORE,
-  MENU_ORDER_CONNECT,
+  MENU_ORDER_CONNECT_ROAD,
+  MENU_ORDER_CONNECT_RAIL,
+  MENU_ORDER_CONNECT_IRRIGATE,
   MENU_ORDER_PATROL,
   MENU_ORDER_GOTO,
   MENU_ORDER_GOTO_CITY,
@@ -391,9 +393,15 @@
    case MENU_ORDER_AUTO_EXPLORE:
     key_unit_auto_explore();
     break;
-   case MENU_ORDER_CONNECT:
-    key_unit_connect();
+   case MENU_ORDER_CONNECT_ROAD:
+    key_unit_connect(ACTIVITY_ROAD);
     break;
+   case MENU_ORDER_CONNECT_RAIL:
+    key_unit_connect(ACTIVITY_RAILROAD);
+    break;
+   case MENU_ORDER_CONNECT_IRRIGATE:
+    key_unit_connect(ACTIVITY_IRRIGATE);
+    break;
    case MENU_ORDER_PATROL:
     key_unit_patrol();
     break;
@@ -709,8 +717,12 @@
        orders_menu_callback,   MENU_ORDER_AUTO_SETTLER                         
        },
   { "/" N_("Orders") "/" N_("Auto E_xplore"),          "x",
        orders_menu_callback,   MENU_ORDER_AUTO_EXPLORE                         
        },
-  { "/" N_("Orders") "/" N_("_Connect"),               "<shift>c",
-       orders_menu_callback,   MENU_ORDER_CONNECT                              
        },
+  {"/" N_("Orders") "/" N_("_Connect") "/" N_("_Road"), "<ctrl>r",
+   orders_menu_callback, MENU_ORDER_CONNECT_ROAD},
+  {"/" N_("Orders") "/" N_("_Connect") "/" N_("Rai_l"), "<ctrl>l",
+   orders_menu_callback, MENU_ORDER_CONNECT_RAIL},
+  {"/" N_("Orders") "/" N_("_Connect") "/" N_("_Irrigate"), "<ctrl>i",
+   orders_menu_callback, MENU_ORDER_CONNECT_IRRIGATE},
   { "/" N_("Orders") "/" N_("Patrol (_Q)"),            "q",
        orders_menu_callback,   MENU_ORDER_PATROL                               
        },
   { "/" N_("Orders") "/" N_("_Go to"),                 "g",
@@ -1173,10 +1185,12 @@
                           can_unit_do_auto(punit));
       menus_set_sensitive("<main>/_Orders/Auto E_xplore",
                           can_unit_do_activity(punit, ACTIVITY_EXPLORE));
-      menus_set_sensitive("<main>/_Orders/_Connect",
-                          can_unit_do_connect(punit, ACTIVITY_IDLE));
-      menus_set_sensitive("<main>/_Orders/Patrol (_Q)",
-                          can_unit_do_activity(punit, ACTIVITY_PATROL));
+      menus_set_sensitive("<main>/_Orders/_Connect/_Road",
+                          can_unit_do_connect(punit, ACTIVITY_ROAD));
+      menus_set_sensitive("<main>/_Orders/_Connect/_Rail",
+                          can_unit_do_connect(punit, ACTIVITY_RAILROAD));
+      menus_set_sensitive("<main>/_Orders/_Connect/_Irrigate",
+                          can_unit_do_connect(punit, ACTIVITY_IRRIGATE));
       menus_set_sensitive("<main>/_Orders/Return to nearest city",
                          !(is_air_unit(punit) || is_heli_unit(punit)));
       menus_set_sensitive("<main>/_Orders/Diplomat\\/Spy Actions",
Index: client/gui-mui/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-mui/gui_main.c,v
retrieving revision 1.79
diff -u -r1.79 gui_main.c
--- client/gui-mui/gui_main.c   2003/11/19 17:30:51     1.79
+++ client/gui-mui/gui_main.c   2004/01/20 21:44:13
@@ -1259,7 +1259,6 @@
       menu_entry_sensitive(MENU_ORDER_AUTO_ATTACK, (can_unit_do_auto(punit) && 
!unit_flag(punit, F_SETTLERS)));
       menu_entry_sensitive(MENU_ORDER_AUTO_EXPLORE, 
can_unit_do_activity(punit, ACTIVITY_EXPLORE));
       menu_entry_sensitive(MENU_ORDER_CONNECT, can_unit_do_connect(punit, 
ACTIVITY_IDLE));
-      menu_entry_sensitive(MENU_ORDER_PATROL, can_unit_do_activity(punit, 
ACTIVITY_PATROL));
       menu_entry_sensitive(MENU_ORDER_GOTO_CITY, any_cities);
       menu_entry_sensitive(MENU_ORDER_BUILD_WONDER, 
unit_can_help_build_wonder_here(punit));
       menu_entry_sensitive(MENU_ORDER_TRADEROUTE, 
unit_can_est_traderoute_here(punit));
Index: client/gui-sdl/menu.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-sdl/menu.c,v
retrieving revision 1.23
diff -u -r1.23 menu.c
--- client/gui-sdl/menu.c       2003/10/02 21:37:44     1.23
+++ client/gui-sdl/menu.c       2004/01/20 21:44:13
@@ -1198,12 +1198,6 @@
        local_hide(ID_UNIT_ORDER_CONNECT);
       }
 
-      if (can_unit_do_activity(pUnit, ACTIVITY_PATROL)) {
-       local_show(ID_UNIT_ORDER_PATROL);
-      } else {
-       local_hide(ID_UNIT_ORDER_PATROL);
-      }
-
       if (is_diplomat_unit(pUnit) &&
          diplomat_can_do_action(pUnit, DIPLOMAT_ANY_ACTION, pUnit->x,
                                 pUnit->y)) {
Index: client/gui-xaw/menu.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/menu.c,v
retrieving revision 1.58
diff -u -r1.58 menu.c
--- client/gui-xaw/menu.c       2003/12/01 19:32:04     1.58
+++ client/gui-xaw/menu.c       2004/01/20 21:44:13
@@ -369,8 +369,6 @@
                           can_unit_do_activity(punit, ACTIVITY_EXPLORE));
       menu_entry_sensitive(MENU_ORDER, MENU_ORDER_CONNECT, 
                           can_unit_do_connect(punit, ACTIVITY_IDLE));
-      menu_entry_sensitive(MENU_ORDER, MENU_ORDER_PATROL, 
-                          can_unit_do_activity(punit, ACTIVITY_PATROL));
       menu_entry_sensitive(MENU_ORDER, MENU_ORDER_GOTO_CITY,
                           any_cities);
       menu_entry_sensitive(MENU_ORDER, MENU_ORDER_BUILD_WONDER,
Index: client/include/dialogs_g.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/include/dialogs_g.h,v
retrieving revision 1.13
diff -u -r1.13 dialogs_g.h
--- client/include/dialogs_g.h  2003/11/28 17:37:20     1.13
+++ client/include/dialogs_g.h  2004/01/20 21:44:13
@@ -44,7 +44,6 @@
 void popup_sabotage_dialog(struct city *pcity);
 void popup_pillage_dialog(struct unit *punit,
                          enum tile_special_type may_pillage);
-void popup_unit_connect_dialog (struct unit *punit, int dest_x, int dest_y);
 
 void popdown_all_game_dialogs(void);
 
Index: common/capstr.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/capstr.c,v
retrieving revision 1.151
diff -u -r1.151 capstr.c
--- common/capstr.c     2004/01/11 17:45:03     1.151
+++ common/capstr.c     2004/01/20 21:44:13
@@ -74,13 +74,15 @@
  * are not directly related to the capability strings discussed here.)
  */
 
-#define CAPABILITY "+1.14.delta +last_turns_shield_surplus veteran"
+#define CAPABILITY "+1.14.delta +last_turns_shield_surplus veteran +orders"
 
 /* "+1.14.delta" is the new delta protocol for 1.14.0-dev.
  *
  * "last_turns_shield_surplus" means the surplus from the previous turn is
  * tracked by the server and sent to the client.  This information is used
  * in determining penalties when switching production.
+ *
+ * "orders" means client orders is used for client-side goto and patrol.
  */
 
 void init_our_capability(void)
Index: common/map.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/map.h,v
retrieving revision 1.168
diff -u -r1.168 map.h
--- common/map.h        2004/01/18 16:49:17     1.168
+++ common/map.h        2004/01/20 21:44:13
@@ -36,17 +36,6 @@
   int x,y;
 };
 
-struct goto_route {
-  int first_index; /* first valid tile pos */
-  int last_index; /* point to the first non_legal pos. Note that the pos
-                  is always alloced in the pos array (for coding reasons) */
-  int length; /* length of pos array (use this as modulus when iterating)
-                Note that this is always at least 1 greater than the number
-                of valid positions, to make comparing first_index with
-                last_index during wrapped iteration easier. */
-  struct map_position *pos;
-};
-
 /* For client Area Selection */
 enum tile_hilite {
   HILITE_NONE = 0, HILITE_CITY
@@ -558,6 +547,12 @@
 };
 
 BV_DEFINE(dir_vector, 8);
+
+struct unit_order {
+  enum unit_orders order;
+  enum direction8 dir;         /* Only valid for ORDER_MOVE. */
+  enum unit_activity activity; /* Only valid for ORDER_ACTIVITY. */
+};
 
 /* return the reverse of the direction */
 #define DIR_REVERSE(dir) (7 - (dir))
Index: common/packets.def
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.def,v
retrieving revision 1.6
diff -u -r1.6 packets.def
--- common/packets.def  2004/01/14 11:58:12     1.6
+++ common/packets.def  2004/01/20 21:44:13
@@ -174,6 +174,8 @@
 type REPORT_TYPE       = uint8(enum report_type)
 type AUTH_TYPE         = uint8(enum authentication_type)
 type IMPR_RANGE                = uint8(enum impr_range)
+type DIRECTION         = uint8(enum direction8)
+type ORDERS            = uint8(enum unit_orders)
 
 # typedefs for IDs
 type PLAYER            = UINT8
@@ -595,7 +597,8 @@
 
   UINT8 veteran; add-cap(veteran)
   BOOL veteran_old; remove-cap(veteran)
-  BOOL ai, paradropped, connecting, carried, done_moving;
+  BOOL ai, paradropped, carried, done_moving;
+  BOOL has_orders, repeat, vigilant;
 
   UNIT_TYPE type;
   UINT8 movesleft, hp, fuel, activity_count;
@@ -661,18 +664,21 @@
   UNIT unit_id;
 end
 
+# used for server-side goto (air units only)
 PACKET_UNIT_GOTO=58;cs
   UNIT unit_id;
   COORD x, y;
 end
 
-# used for ACTIVITY_GOTO and ACTIVITY_PATROL
-PACKET_UNIT_ROUTE=59;cs
+# used for client orders: currently client-side goto and patrol
+PACKET_UNIT_ORDERS=59;cs
   UNIT unit_id;
-  ACTIVITY activity;
   UINT16 length;
-  COORD x[MAX_LEN_ROUTE:length];
-  COORD y[MAX_LEN_ROUTE:length];
+  BOOL repeat, vigilant;
+  ORDERS orders[MAX_LEN_ROUTE:length];
+  DIRECTION dir[MAX_LEN_ROUTE:length];
+  ACTIVITY activity[MAX_LEN_ROUTE:length];
+  COORD dest_x, dest_y;
 end
 
 PACKET_UNIT_AUTO=60;cs
@@ -699,13 +705,6 @@
 PACKET_UNIT_AIRLIFT=65;cs
   UNIT unit_id;
   CITY city_id;
-end
-
-PACKET_UNIT_CONNECT=66;cs
-  UNIT unit_id;
-  ACTIVITY activity_type;
-  COORD dest_x;
-  COORD dest_y;
 end
 
 PACKET_UNIT_BRIBE_INQ=67;cs,handle-per-conn
Index: common/unit.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unit.c,v
retrieving revision 1.195
diff -u -r1.195 unit.c
--- common/unit.c       2004/01/19 06:01:21     1.195
+++ common/unit.c       2004/01/20 21:44:14
@@ -214,6 +214,14 @@
   return TRUE;
 }
 
+/****************************************************************************
+  Return TRUE iff the unit is following client-side orders.
+****************************************************************************/
+bool unit_has_orders(struct unit *punit)
+{
+  return punit->has_orders;
+}
+
 /**************************************************************************
 ...
 **************************************************************************/
@@ -534,7 +542,7 @@
 Return whether the unit can connect with given activity (or with
 any activity if activity arg is set to ACTIVITY_IDLE)
 **************************************************************************/
-bool can_unit_do_connect (struct unit *punit, enum unit_activity activity) 
+bool can_unit_do_connect (struct unit *punit, enum unit_activity activity)
 {
   struct player *pplayer = unit_owner(punit);
 
@@ -544,12 +552,12 @@
   if (activity == ACTIVITY_IDLE)   /* IDLE here means "any activity" */
     return TRUE;
 
-  if (activity == ACTIVITY_ROAD 
-      || activity == ACTIVITY_IRRIGATE 
+  if (activity == ACTIVITY_ROAD
+      || activity == ACTIVITY_IRRIGATE
       || (activity == ACTIVITY_RAILROAD
-         && player_knows_techs_with_flag(pplayer, TF_RAILROAD))
-      || (activity == ACTIVITY_FORTRESS 
-         && player_knows_techs_with_flag(pplayer, TF_FORTRESS)))
+         && player_knows_techs_with_flag(pplayer, TF_RAILROAD))
+      || (activity == ACTIVITY_FORTRESS
+         && player_knows_techs_with_flag(pplayer, TF_FORTRESS)))
   return TRUE;
 
   return FALSE;
@@ -579,7 +587,6 @@
   case ACTIVITY_TRANSFORM:     text = _("Transform"); break;
   case ACTIVITY_AIRBASE:       text = _("Airbase"); break;
   case ACTIVITY_FALLOUT:       text = _("Fallout"); break;
-  case ACTIVITY_PATROL:        text = _("Patrol"); break;
   default:                     text = _("Unknown"); break;
   }
 
@@ -629,9 +636,6 @@
               (current == ACTIVITY_FORTIFIED) ? ACTIVITY_FORTIFYING : current;
   bool result;
 
-  if (punit->connecting)
-    return can_unit_do_connect(punit, current);
-
   punit->activity = ACTIVITY_IDLE;
   punit->activity_target = S_NO_SPECIAL;
 
@@ -652,26 +656,36 @@
 }
 
 /**************************************************************************
-Note that if you make changes here you should also change the code for
-autosettlers in server/settler.c. The code there does not use this function
-as it would be a ajor CPU hog.
+  Return whether the unit can do the targeted activity at its current
+  location.
 **************************************************************************/
 bool can_unit_do_activity_targeted(struct unit *punit,
                                   enum unit_activity activity,
                                   enum tile_special_type target)
 {
-  struct player *pplayer;
-  struct tile *ptile;
-  struct tile_type *type;
+  return can_unit_do_activity_targeted_at(punit, activity, target,
+                                         punit->x, punit->y);
+}
 
-  pplayer = unit_owner(punit);
-  ptile = map_get_tile(punit->x, punit->y);
-  type = get_tile_type(ptile->terrain);
+/****************************************************************************
+  Return TRUE if the unit can do the targeted activity at the given location.
 
+  Note that if you make changes here you should also change the code for
+  autosettlers in server/settler.c. The code there does not use this function
+  as it would be a ajor CPU hog.
+****************************************************************************/
+bool can_unit_do_activity_targeted_at(struct unit *punit,
+                                     enum unit_activity activity,
+                                     enum tile_special_type target,
+                                     int x, int y)
+{
+  struct player *pplayer = unit_owner(punit);
+  struct tile *ptile = map_get_tile(x, y);
+  struct tile_type *type = get_tile_type(ptile->terrain);
+
   switch(activity) {
   case ACTIVITY_IDLE:
   case ACTIVITY_GOTO:
-  case ACTIVITY_PATROL:
     return TRUE;
 
   case ACTIVITY_POLLUTION:
@@ -697,11 +711,11 @@
          (ptile->terrain!=type->mining_result &&
           type->mining_result!=T_LAST &&
           (!is_ocean(ptile->terrain) || is_ocean(type->mining_result) ||
-           can_reclaim_ocean(punit->x, punit->y)) &&
+           can_reclaim_ocean(x, y)) &&
           (is_ocean(ptile->terrain) || !is_ocean(type->mining_result) ||
-           can_channel_land(punit->x, punit->y)) &&
+           can_channel_land(x, y)) &&
           (!is_ocean(type->mining_result) ||
-           !(map_get_city(punit->x, punit->y)))) )) {
+           !(map_get_city(x, y)))) )) {
       unit_list_iterate(ptile->units, tunit) {
        if(tunit->activity==ACTIVITY_IRRIGATE) return FALSE;
       }
@@ -718,15 +732,15 @@
         (!tile_has_special(ptile, S_FARMLAND) &&
          player_knows_techs_with_flag(pplayer, TF_FARMLAND))) &&
        ( (ptile->terrain==type->irrigation_result && 
-          is_water_adjacent_to_tile(punit->x, punit->y)) ||
+          is_water_adjacent_to_tile(x, y)) ||
          (ptile->terrain!=type->irrigation_result &&
           type->irrigation_result!=T_LAST &&
           (!is_ocean(ptile->terrain) || is_ocean(type->irrigation_result) ||
-           can_reclaim_ocean(punit->x, punit->y)) &&
+           can_reclaim_ocean(x, y)) &&
           (is_ocean(ptile->terrain) || !is_ocean(type->irrigation_result) ||
-           can_channel_land(punit->x, punit->y)) &&
+           can_channel_land(x, y)) &&
           (!is_ocean(type->irrigation_result) ||
-           !(map_get_city(punit->x, punit->y)))) )) {
+           !(map_get_city(x, y)))) )) {
       unit_list_iterate(ptile->units, tunit) {
        if(tunit->activity==ACTIVITY_MINE) return FALSE;
       }
@@ -745,7 +759,7 @@
 
   case ACTIVITY_FORTRESS:
     return (unit_flag(punit, F_SETTLERS) &&
-           !map_get_city(punit->x, punit->y) &&
+           !map_get_city(x, y) &&
            player_knows_techs_with_flag(pplayer, TF_FORTRESS) &&
            !tile_has_special(ptile, S_FORTRESS) && !is_ocean(ptile->terrain));
 
@@ -761,11 +775,7 @@
     /* if the tile has road, the terrain must be ok.. */
     return (terrain_control.may_road &&
            unit_flag(punit, F_SETTLERS) &&
-           (tile_has_special(ptile, S_ROAD) ||
-            (punit->connecting &&
-             (type->road_time != 0 &&
-              ((ptile->terrain!=T_RIVER && !tile_has_special(ptile, S_RIVER))
-               || player_knows_techs_with_flag(pplayer, TF_BRIDGE))))) &&
+           tile_has_special(ptile, S_ROAD) &&
            !tile_has_special(ptile, S_RAILROAD) &&
            player_knows_techs_with_flag(pplayer, TF_RAILROAD));
 
@@ -775,7 +785,7 @@
       int psworking;
       pspresent = get_tile_infrastructure_set(ptile);
       if (pspresent != S_NO_SPECIAL && is_ground_unit(punit)) {
-       psworking = get_unit_tile_pillage_set(punit->x, punit->y);
+       psworking = get_unit_tile_pillage_set(x, y);
        if (ptile->city && (contains_special(target, S_ROAD) ||
                            contains_special(target, S_RAILROAD)))
            return FALSE;
@@ -803,18 +813,22 @@
            (type->transform_result!=T_LAST) &&
            (ptile->terrain!=type->transform_result) &&
            (!is_ocean(ptile->terrain) || is_ocean(type->transform_result) ||
-            can_reclaim_ocean(punit->x, punit->y)) &&
+            can_reclaim_ocean(x, y)) &&
            (is_ocean(ptile->terrain) || !is_ocean(type->transform_result) ||
-            can_channel_land(punit->x, punit->y)) &&
+            can_channel_land(x, y)) &&
            (!is_ocean(type->transform_result) ||
-            !(map_get_city(punit->x, punit->y))) &&
+            !(map_get_city(x, y))) &&
            unit_flag(punit, F_TRANSFORM));
 
-  default:
-    freelog(LOG_ERROR, "Unknown activity %d in 
can_unit_do_activity_targeted()",
-           activity);
-    return FALSE;
-  }
+  case ACTIVITY_PATROL_UNUSED:
+  case ACTIVITY_LAST:
+  case ACTIVITY_UNKNOWN:
+    break;
+  }
+  freelog(LOG_ERROR,
+         "Unknown activity %d in can_unit_do_activity_targeted()",
+         activity);
+  return FALSE;
 }
 
 /**************************************************************************
@@ -825,7 +839,6 @@
   punit->activity=new_activity;
   punit->activity_count=0;
   punit->activity_target = S_NO_SPECIAL;
-  punit->connecting = FALSE;
   if (new_activity == ACTIVITY_IDLE && punit->moves_left > 0) {
     /* No longer done. */
     punit->done_moving = FALSE;
@@ -931,7 +944,6 @@
    case ACTIVITY_SENTRY:
    case ACTIVITY_GOTO:
    case ACTIVITY_EXPLORE:
-   case ACTIVITY_PATROL:
      return get_activity_text (punit->activity);
    case ACTIVITY_PILLAGE:
      if(punit->activity_target == S_NO_SPECIAL) {
@@ -1270,14 +1282,14 @@
                           bool igzoc)
 {
   return MR_OK == test_unit_move_to_tile(punit->type, unit_owner(punit),
-                                        punit->activity, punit->connecting,
+                                        punit->activity,
                                         punit->x, punit->y, dest_x, dest_y,
                                         igzoc);
 }
 
 /**************************************************************************
   unit can be moved if:
-  1) the unit is idle or on goto or connecting.
+  1) the unit is idle or on server goto.
   2) the target location is on the map
   3) the target location is next to the unit
   4) there are no non-allied units on the target tile
@@ -1292,9 +1304,9 @@
 enum unit_move_result test_unit_move_to_tile(Unit_Type_id type,
                                             struct player *unit_owner,
                                             enum unit_activity activity,
-                                            bool connecting, int src_x,
-                                            int src_y, int dest_x,
-                                            int dest_y, bool igzoc)
+                                            int src_x, int src_y,
+                                            int dest_x, int dest_y,
+                                            bool igzoc)
 {
   struct tile *pfromtile, *ptotile;
   bool zoc;
@@ -1302,8 +1314,7 @@
 
   /* 1) */
   if (activity != ACTIVITY_IDLE
-      && activity != ACTIVITY_GOTO
-      && activity != ACTIVITY_PATROL && !connecting) {
+      && activity != ACTIVITY_GOTO) {
     return MR_BAD_ACTIVITY;
   }
 
@@ -1484,7 +1495,6 @@
   punit->moves_left = unit_move_rate(punit);
   punit->moved = FALSE;
   punit->paradropped = FALSE;
-  punit->connecting = FALSE;
   punit->done_moving = FALSE;
   if (is_barbarian(pplayer)) {
     punit->fuel = BARBARIAN_LIFE;
@@ -1497,12 +1507,12 @@
   punit->ai.charge = 0;
   punit->bribe_cost = -1; /* flag value */
   punit->transported_by = -1;
-  punit->pgr = NULL;
   punit->focus_status = FOCUS_AVAIL;
   punit->ord_map = 0;
   punit->ord_city = 0;
   set_unit_activity(punit, ACTIVITY_IDLE);
   punit->occupy = 0;
+  punit->has_orders = FALSE;
 
   return punit;
 }
@@ -1513,7 +1523,7 @@
 **************************************************************************/
 void destroy_unit_virtual(struct unit *punit)
 {
-  free_unit_goto_route(punit);
+  free_unit_orders(punit);
   free(punit);
 }
 
@@ -1521,13 +1531,16 @@
   Free and reset the unit's goto route (punit->pgr).  Only used by the
   server.
 **************************************************************************/
-void free_unit_goto_route(struct unit *punit)
+void free_unit_orders(struct unit *punit)
 {
-  if (punit->pgr) {
-    free(punit->pgr->pos);
-    free(punit->pgr);
-    punit->pgr = NULL;
+  if (punit->has_orders) {
+    if (is_goto_dest_set(punit)) {
+      clear_goto_dest(punit);
+    }
+    free(punit->orders.list);
+    punit->orders.list = NULL;
   }
+  punit->has_orders = FALSE;
 }
 
 /****************************************************************************
Index: common/unit.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unit.h,v
retrieving revision 1.108
diff -u -r1.108 unit.h
--- common/unit.h       2004/01/11 17:45:04     1.108
+++ common/unit.h       2004/01/20 21:44:14
@@ -19,20 +19,28 @@
 
 struct player;
 struct city;
-struct goto_route;
 struct tile;
+struct unit_order;
 
 #define BARBARIAN_LIFE    5
 
+/* Changing this enum will break savegame and network compatability. */
 enum unit_activity {
   ACTIVITY_IDLE, ACTIVITY_POLLUTION, ACTIVITY_ROAD, ACTIVITY_MINE,
   ACTIVITY_IRRIGATE, ACTIVITY_FORTIFIED, ACTIVITY_FORTRESS, ACTIVITY_SENTRY,
   ACTIVITY_RAILROAD, ACTIVITY_PILLAGE, ACTIVITY_GOTO, ACTIVITY_EXPLORE,
   ACTIVITY_TRANSFORM, ACTIVITY_UNKNOWN, ACTIVITY_AIRBASE, ACTIVITY_FORTIFYING,
-  ACTIVITY_FALLOUT, ACTIVITY_PATROL,
+  ACTIVITY_FALLOUT,
+  ACTIVITY_PATROL_UNUSED, /* Needed for savegame compatability. */
   ACTIVITY_LAST   /* leave this one last */
 };
 
+/* Changing this enum will break savegame and network compatability. */
+enum unit_orders {
+  ORDER_MOVE, ORDER_FINISH_TURN, ORDER_ACTIVITY,
+  ORDER_LAST
+};
+
 enum unit_focus_status {
   FOCUS_AVAIL, FOCUS_WAIT, FOCUS_DONE  
 };
@@ -142,7 +150,6 @@
   bool debug;
   bool moved;
   bool paradropped;
-  bool connecting;
 
   /* This value is set if the unit is done moving for this turn. This
    * information is used by the client.  The invariant is:
@@ -153,7 +160,14 @@
 
   int transported_by;
   int occupy; /* number of units that occupy transporter */
-  struct goto_route *pgr;
+
+  bool has_orders;
+  struct {
+    int length, index; /* server only */
+    bool repeat;       /* The path is to be repeated on completion. */
+    bool vigilant;     /* Orders should be cleared if an enemy is met. */
+    struct unit_order *list; /* server only */
+  } orders;
 };
 
 /* Wrappers for accessing the goto destination of a unit.  This goto_dest
@@ -222,6 +236,7 @@
 bool unit_can_est_traderoute_here(struct unit *punit);
 bool unit_can_defend_here(struct unit *punit);
 bool unit_can_airlift_to(struct unit *punit, struct city *pcity);
+bool unit_has_orders(struct unit *punit);
 
 bool can_unit_paradrop(struct unit *punit);
 bool can_unit_change_homecity(struct unit *punit);
@@ -232,6 +247,10 @@
 bool can_unit_do_activity_targeted(struct unit *punit,
                                   enum unit_activity activity,
                                   enum tile_special_type target);
+bool can_unit_do_activity_targeted_at(struct unit *punit,
+                                     enum unit_activity activity,
+                                     enum tile_special_type target,
+                                     int map_x, int map_y);
 void set_unit_activity(struct unit *punit, enum unit_activity new_activity);
 void set_unit_activity_targeted(struct unit *punit,
                                enum unit_activity new_activity,
@@ -292,9 +311,9 @@
 enum unit_move_result test_unit_move_to_tile(Unit_Type_id type,
                                             struct player *unit_owner,
                                             enum unit_activity activity,
-                                            bool connecting, int src_x,
-                                            int src_y, int dest_x,
-                                            int dest_y, bool igzoc);
+                                            int src_x, int src_y,
+                                            int dest_x, int dest_y,
+                                            bool igzoc);
 bool unit_type_really_ignores_zoc(Unit_Type_id type);
 bool zoc_ok_move(struct unit *punit, int x, int y);
 
@@ -303,7 +322,7 @@
 struct unit *create_unit_virtual(struct player *pplayer, struct city *pcity,
                                  Unit_Type_id type, int veteran_level);
 void destroy_unit_virtual(struct unit *punit);
-void free_unit_goto_route(struct unit *punit);
+void free_unit_orders(struct unit *punit);
 
 int get_transporter_occupancy(struct unit *ptrans);
 
Index: server/gotohand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/gotohand.c,v
retrieving revision 1.177
diff -u -r1.177 gotohand.c
--- server/gotohand.c   2004/01/11 17:45:05     1.177
+++ server/gotohand.c   2004/01/20 21:44:16
@@ -1279,10 +1279,7 @@
   enum goto_result status;
   int x, y;
 
-  if (punit->pgr) {
-    /* we have a precalculated goto route */
-    return goto_route_execute(punit);
-  }
+  assert(!unit_has_orders(punit));
 
   unit_id = punit->id;
   dest_x = waypoint_x = goto_dest_x(punit);
@@ -1291,7 +1288,6 @@
   if (same_pos(punit->x, punit->y, dest_x, dest_y) ||
       !goto_is_sane(punit, dest_x, dest_y, FALSE)) {
     punit->activity = ACTIVITY_IDLE;
-    punit->connecting = FALSE;
     send_unit_info(NULL, punit);
     if (same_pos(punit->x, punit->y, dest_x, dest_y)) {
       return GR_ARRIVED;
@@ -1319,7 +1315,6 @@
              pplayer->name, unit_type(punit)->name,
              punit->x, punit->y, dest_x, dest_y);
       punit->activity = ACTIVITY_IDLE;
-      punit->connecting = FALSE;
       send_unit_info(NULL, punit);
       return GR_FAILED;
     }
@@ -1383,13 +1378,6 @@
        return GR_OUT_OF_MOVEPOINTS;
       }
 
-      /* single step connecting unit when it can do it's activity */
-      if (punit->connecting
-         && can_unit_do_activity(punit, punit->activity)) {
-       /* for connecting unit every step is a destination */
-       return GR_ARRIVED;
-      }
-
       freelog(LOG_DEBUG, "Moving on.");
     } while(!same_pos(x, y, waypoint_x, waypoint_y));
   } else {
@@ -1398,30 +1386,21 @@
            pplayer->name, unit_type(punit)->name,
            punit->x, punit->y, dest_x, dest_y);
     handle_unit_activity_request(punit, ACTIVITY_IDLE);
-    punit->connecting = FALSE;
     send_unit_info(NULL, punit);
     return GR_FAILED;
   }
   /** Finished moving the unit for this turn **/
 
-  /* ensure that the connecting unit will perform it's activity
-     on the destination file too. */
-  if (punit->connecting && can_unit_do_activity(punit, punit->activity))
-    return GR_ARRIVED;
-
   /* normally we would just do this unconditionally, but if we had an
      airplane goto we might not be finished even if the loop exited */
   if (same_pos(punit->x, punit->y, dest_x, dest_y)) {
-    if (punit->activity != ACTIVITY_PATROL) {
-      punit->activity = ACTIVITY_IDLE;
-    }
+    punit->activity = ACTIVITY_IDLE;
     status = GR_ARRIVED;
   } else {
     /* we have a plane refueling at a waypoint */
     status = GR_OUT_OF_MOVEPOINTS;
   }
 
-  punit->connecting = FALSE;
   send_unit_info(NULL, punit);
   return status;
 }
Index: server/hand_gen.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/hand_gen.c,v
retrieving revision 1.2
diff -u -r1.2 hand_gen.c
--- server/hand_gen.c   2004/01/06 20:19:17     1.2
+++ server/hand_gen.c   2004/01/20 21:44:16
@@ -184,13 +184,8 @@
       ((struct packet_unit_goto *)packet)->y);
     return TRUE;
 
-  case PACKET_UNIT_ROUTE:
-    handle_unit_route(pplayer,
-      ((struct packet_unit_route *)packet)->unit_id,
-      ((struct packet_unit_route *)packet)->activity,
-      ((struct packet_unit_route *)packet)->length,
-      ((struct packet_unit_route *)packet)->x,
-      ((struct packet_unit_route *)packet)->y);
+  case PACKET_UNIT_ORDERS:
+    handle_unit_orders(pplayer, packet);
     return TRUE;
 
   case PACKET_UNIT_AUTO:
@@ -224,14 +219,6 @@
     handle_unit_airlift(pplayer,
       ((struct packet_unit_airlift *)packet)->unit_id,
       ((struct packet_unit_airlift *)packet)->city_id);
-    return TRUE;
-
-  case PACKET_UNIT_CONNECT:
-    handle_unit_connect(pplayer,
-      ((struct packet_unit_connect *)packet)->unit_id,
-      ((struct packet_unit_connect *)packet)->activity_type,
-      ((struct packet_unit_connect *)packet)->dest_x,
-      ((struct packet_unit_connect *)packet)->dest_y);
     return TRUE;
 
   case PACKET_UNIT_BRIBE_INQ:
Index: server/hand_gen.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/hand_gen.h,v
retrieving revision 1.2
diff -u -r1.2 hand_gen.h
--- server/hand_gen.h   2003/12/06 19:23:51     1.2
+++ server/hand_gen.h   2004/01/20 21:44:16
@@ -49,14 +49,14 @@
 void handle_unit_establish_trade(struct player *pplayer, int unit_id);
 void handle_unit_help_build_wonder(struct player *pplayer, int unit_id);
 void handle_unit_goto(struct player *pplayer, int unit_id, int x, int y);
-void handle_unit_route(struct player *pplayer, int unit_id, enum unit_activity 
activity, int length, int *x, int *y);
+struct packet_unit_orders;
+void handle_unit_orders(struct player *pplayer, struct packet_unit_orders 
*packet);
 void handle_unit_auto(struct player *pplayer, int unit_id);
 void handle_unit_unload(struct player *pplayer, int unit_id);
 void handle_unit_upgrade(struct player *pplayer, int unit_id);
 void handle_unit_nuke(struct player *pplayer, int unit_id);
 void handle_unit_paradrop_to(struct player *pplayer, int unit_id, int x, int 
y);
 void handle_unit_airlift(struct player *pplayer, int unit_id, int city_id);
-void handle_unit_connect(struct player *pplayer, int unit_id, enum 
unit_activity activity_type, int dest_x, int dest_y);
 void handle_unit_bribe_inq(struct connection *pc, int unit_id);
 void handle_unit_type_upgrade(struct player *pplayer, Unit_Type_id type);
 void handle_unit_diplomat_action(struct player *pplayer, int diplomat_id, enum 
diplomat_actions action_type, int target_id, int value);
Index: server/savegame.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/savegame.c,v
retrieving revision 1.144
diff -u -r1.144 savegame.c
--- server/savegame.c   2004/01/12 16:59:17     1.144
+++ server/savegame.c   2004/01/20 21:44:16
@@ -175,7 +175,7 @@
    and rulesets */
 #define SAVEFILE_OPTIONS "startoptions spacerace2 rulesets" \
 " diplchance_percent worklists2 map_editor known32fix turn " \
-"attributes watchtower rulesetdir client_worklists"
+"attributes watchtower rulesetdir client_worklists orders"
 
 static const char hex_chars[] = "0123456789abcdef";
 static const char terrain_chars[] = "adfghjm prstu";
@@ -597,6 +597,7 @@
   int i, j, x, y, nunits, ncities, c_s;
   char *p;
   char *savefile_options = secfile_lookup_str(file, "savefile.options");
+  enum unit_activity activity;
 
   server_player_init(plr, TRUE);
 
@@ -1043,7 +1044,18 @@
     
     punit->moves_left=secfile_lookup_int(file, "player%d.u%d.moves", plrno, i);
     punit->fuel= secfile_lookup_int(file, "player%d.u%d.fuel", plrno, i);
-    set_unit_activity(punit, secfile_lookup_int(file, 
"player%d.u%d.activity",plrno, i));
+    activity = secfile_lookup_int(file, "player%d.u%d.activity",plrno, i);
+    if (activity == ACTIVITY_PATROL_UNUSED) {
+      /* Previously ACTIVITY_PATROL and ACTIVITY_GOTO were used for
+       * client-side goto.  Now client-side goto is handled by setting
+       * a special flag, and units with orders generally have ACTIVITY_IDLE.
+       * Old orders are lost.  Old client-side goto units will still have
+       * ACTIVITY_GOTO and will goto the correct position via server goto.
+       * Old client-side patrol units lose their patrol routes and are put
+       * into idle mode. */
+      activity = ACTIVITY_IDLE;
+    }
+    set_unit_activity(punit, activity);
 /* need to do this to assign/deassign settlers correctly -- Syela */
 /* was punit->activity=secfile_lookup_int(file, "player%d.u%d.activity",plrno, 
i); */
     punit->activity_count=secfile_lookup_int(file, 
@@ -1053,9 +1065,6 @@
        secfile_lookup_int_default(file, (int) S_NO_SPECIAL,
                                   "player%d.u%d.activity_target", plrno, i);
 
-    punit->connecting=secfile_lookup_bool_default(file, FALSE,
-                                               "player%d.u%d.connecting",
-                                               plrno, i);
     punit->done_moving = secfile_lookup_bool_default(file,
        (punit->moves_left == 0), "player%d.u%d.done_moving", plrno, i);
     /* Load the goto information.  Older savegames will not have the
@@ -1090,58 +1099,42 @@
        etc may use junk values).
     */
 
-    /* load the goto route */
-    {
-      int len = secfile_lookup_int_default(file, 0, 
"player%d.u%d.goto_length", plrno, i);
+    /* load the unit orders */
+    if (has_capability("orders", savefile_options)) {
+      int len = secfile_lookup_int_default(file, 0,
+                       "player%d.u%d.orders_length", plrno, i);
       if (len > 0) {
-       char *goto_buf, *goto_buf_ptr;
-       struct goto_route *pgr = fc_malloc(sizeof(struct goto_route));
-       pgr->pos = fc_malloc((len+1) * sizeof(struct map_position));
-       pgr->first_index = 0;
-       pgr->length = len+1;
-       pgr->last_index = len;
-       punit->pgr = pgr;
-
-       /* get x coords */
-       goto_buf = secfile_lookup_str(file, "player%d.u%d.goto_route_x", plrno, 
i);
-       goto_buf_ptr = goto_buf;
+       char *orders_buf, *dir_buf;
+
+       punit->orders.list = fc_malloc(len * sizeof(*(punit->orders.list)));
+       punit->orders.length = len;
+       punit->orders.index = secfile_lookup_int_default(file, 0,
+                       "player%d.u%d.orders_index", plrno, i);
+       punit->orders.repeat = secfile_lookup_bool_default(file, FALSE,
+                       "player%d.u%d.orders_repeat", plrno, i);
+       punit->orders.vigilant = secfile_lookup_bool_default(file, FALSE,
+                       "player%d.u%d.orders_vigilant", plrno, i);
+
+       orders_buf = secfile_lookup_str_default(file, "",
+                       "player%d.u%d.orders_list", plrno, i);
+       dir_buf = secfile_lookup_str_default(file, "",
+                       "player%d.u%d.dir_list", plrno, i);
        for (j = 0; j < len; j++) {
-         if (sscanf(goto_buf_ptr, "%d", &pgr->pos[j].x) == 0) {
-           die("not an int");
-         }
-         while (*goto_buf_ptr != ',') {
-           goto_buf_ptr++;
-           if (*goto_buf_ptr == '\0') {
-             die("byebye");
-           }
+         if (orders_buf[j] == '\0' || dir_buf == '\0') {
+           freelog(LOG_ERROR, _("Savegame error: invalid unit orders."));
+           free_unit_orders(punit);
+           break;
          }
-         goto_buf_ptr++;
+         punit->orders.list[j].order = orders_buf[j] - 'a';
+         punit->orders.list[j].dir = dir_buf[j] - 'a';
        }
-       /* get y coords */
-       goto_buf = secfile_lookup_str(file, "player%d.u%d.goto_route_y", plrno, 
i);
-       goto_buf_ptr = goto_buf;
-       for (j = 0; j < len; j++) {
-         if (sscanf(goto_buf_ptr, "%d", &pgr->pos[j].y) == 0) {
-           die("not an int");
-         }
-         while (*goto_buf_ptr != ',') {
-           goto_buf_ptr++;
-           if (*goto_buf_ptr == '\0') {
-             die("byebye");
-           }
-         }
-         goto_buf_ptr++;
-       }
+       punit->has_orders = TRUE;
       } else {
-       /* mark unused strings as read to avoid warnings */
-       (void) secfile_lookup_str_default(file, "",
-                                         "player%d.u%d.goto_route_x", plrno,
-                                         i);
-       (void) secfile_lookup_str_default(file, "",
-                                         "player%d.u%d.goto_route_y", plrno,
-                                         i);
-       punit->pgr = NULL;
+       punit->has_orders = FALSE;
+       punit->orders.list = NULL;
       }
+    } else {
+      /* Old-style goto routes get discarded. */
     }
 
     {
@@ -1513,9 +1506,6 @@
     secfile_insert_int(file, punit->activity_target, 
                                "player%d.u%d.activity_target",
                                plrno, i);
-    secfile_insert_bool(file, punit->connecting, 
-                               "player%d.u%d.connecting",
-                               plrno, i);
     secfile_insert_bool(file, punit->done_moving,
                        "player%d.u%d.done_moving", plrno, i);
     secfile_insert_int(file, punit->moves_left, "player%d.u%d.moves",
@@ -1543,42 +1533,30 @@
     secfile_insert_bool(file, punit->paradropped, "player%d.u%d.paradropped", 
plrno, i);
     secfile_insert_int(file, punit->transported_by,
                       "player%d.u%d.transported_by", plrno, i);
-    if (punit->pgr && punit->pgr->first_index != punit->pgr->last_index) {
-      struct goto_route *pgr = punit->pgr;
-      int index = pgr->first_index;
-      int len = 0;
-      while (pgr && index != pgr->last_index) {
-       len++;
-       index = (index + 1) % pgr->length;
+    if (punit->has_orders) {
+      int len = punit->orders.length, j;
+      char orders_buf[len + 1], dir_buf[len + 1];
+
+      secfile_insert_int(file, len, "player%d.u%d.orders_length", plrno, i);
+      secfile_insert_int(file, punit->orders.index,
+                        "player%d.u%d.orders_index", plrno, i);
+      secfile_insert_bool(file, punit->orders.repeat,
+                         "player%d.u%d.orders_repeat", plrno, i);
+      secfile_insert_bool(file, punit->orders.vigilant,
+                         "player%d.u%d.orders_vigilant", plrno, i);
+
+      for (j = 0; j < len; j++) {
+       orders_buf[j] = 'a' + punit->orders.list[j].order;
+       dir_buf[j] = 'a' + punit->orders.list[j].dir;
       }
-      assert(len > 0);
-      secfile_insert_int(file, len, "player%d.u%d.goto_length", plrno, i);
-      /* assumption about the chars per map position */
-      assert(MAP_MAX_HEIGHT < 1000 && MAP_MAX_WIDTH < 1000);
-      {
-       char *goto_buf = fc_malloc(4 * len + 1);
-       char *goto_buf_ptr = goto_buf;
-       index = pgr->first_index;
-       while (index != pgr->last_index) {
-         goto_buf_ptr += sprintf(goto_buf_ptr, "%d,", pgr->pos[index].x);
-         index = (index + 1) % pgr->length;
-       }
-       *goto_buf_ptr = '\0';
-       secfile_insert_str(file, goto_buf, "player%d.u%d.goto_route_x", plrno, 
i);
+      orders_buf[len] = dir_buf[len] = '\0';
 
-       goto_buf_ptr = goto_buf;
-       index = pgr->first_index;
-       while (index != pgr->last_index) {
-         goto_buf_ptr += sprintf(goto_buf_ptr, "%d,", pgr->pos[index].y);
-         index = (index + 1) % pgr->length;
-       }
-       *goto_buf_ptr = '\0';
-       secfile_insert_str(file, goto_buf, "player%d.u%d.goto_route_y", plrno, 
i);
-      }
+      secfile_insert_str(file, orders_buf,
+                        "player%d.u%d.orders_list", plrno, i);
+      secfile_insert_str(file, dir_buf,
+                        "player%d.u%d.dir_list", plrno, i);
     } else {
-      secfile_insert_int(file, 0, "player%d.u%d.goto_length", plrno, i);
-      secfile_insert_str(file, "", "player%d.u%d.goto_route_x", plrno, i);
-      secfile_insert_str(file, "", "player%d.u%d.goto_route_y", plrno, i);
+      secfile_insert_int(file, 0, "player%d.u%d.orders_length", plrno, i);
     }
   }
   unit_list_iterate_end;
Index: server/unithand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unithand.c,v
retrieving revision 1.283
diff -u -r1.283 unithand.c
--- server/unithand.c   2004/01/12 16:34:44     1.283
+++ server/unithand.c   2004/01/20 21:44:16
@@ -108,44 +108,6 @@
 }
 
 /**************************************************************************
-Handler for PACKET_UNIT_CONNECT request. The unit is send on way and will 
-build something (roads only for now) along the way, using server-side
-path-finding. 
-
-FIXME: This should be rewritten to use client-side path finding along so 
-that we can show in the client where the road-to-be-built will be and 
-enable the use of waypoints to alter this route. - Per
-**************************************************************************/
-void handle_unit_connect(struct player *pplayer, int unit_id,
-                        enum unit_activity activity_type, int dest_x,
-                        int dest_y)
-{
-  struct unit *punit = player_find_unit_by_id(pplayer, unit_id);
-
-  if (!is_normal_map_pos(dest_x, dest_y) || !punit
-      || !can_unit_do_connect(punit, activity_type)) {
-    return;
-  }
-
-  set_goto_dest(punit, dest_x, dest_y);
-
-  set_unit_activity(punit, activity_type);
-  punit->connecting = TRUE;
-
-  send_unit_info(NULL, punit);
-
-  /* 
-   * Avoid wasting first turn if unit cannot do the activity on the
-   * starting tile.
-   */
-  if (!can_unit_do_activity(punit, activity_type)) {
-    (void) do_unit_goto(punit,
-                       get_activity_move_restriction(activity_type),
-                       FALSE);
-  }
-}
-
-/**************************************************************************
  Upgrade all units of a given type.
 **************************************************************************/
 void handle_unit_type_upgrade(struct player *pplayer, Unit_Type_id type)
@@ -847,10 +809,6 @@
     }
   }
 
-  if (pwinner == punit && punit->activity != ACTIVITY_IDLE) {
-    /* Ensure we remove ACTIVITY_GOTO here */
-    set_unit_activity(punit, ACTIVITY_IDLE);
-  }
   send_unit_info(NULL, pwinner);
 }
 
@@ -874,7 +832,7 @@
 
   reason =
       test_unit_move_to_tile(punit->type, unit_owner(punit),
-                            punit->activity, punit->connecting,
+                            punit->activity,
                             punit->x, punit->y, dest_x, dest_y, igzoc);
   if (reason == MR_OK)
     return TRUE;
@@ -1402,7 +1360,6 @@
     enum tile_special_type old_target = punit->activity_target;
 
     set_unit_activity(punit, new_activity);
-    free_unit_goto_route(punit);
     send_unit_info(NULL, punit);
     handle_unit_activity_dependencies(punit, old_activity, old_target);
   }
@@ -1422,7 +1379,6 @@
     enum tile_special_type old_target = punit->activity_target;
 
     set_unit_activity_targeted(punit, new_activity, new_target);
-    free_unit_goto_route(punit);
     send_unit_info(NULL, punit);    
     handle_unit_activity_dependencies(punit, old_activity, old_target);
   }
@@ -1495,66 +1451,80 @@
 }
 
 /**************************************************************************
-Receives goto route packages.
+Receives route packages.
 **************************************************************************/
-static void handle_route(struct player *pplayer, struct unit *punit,
-                        int length, int *x, int *y)
+void handle_unit_orders(struct player *pplayer,
+                       struct packet_unit_orders *packet)
 {
-  struct goto_route *pgr = NULL;
+  struct unit *punit = player_find_unit_by_id(pplayer, packet->unit_id);
   int i;
 
-  free_unit_goto_route(punit);
+  if (!punit || packet->length < 0 || punit->activity != ACTIVITY_IDLE) {
+    return;
+  }
 
-  /* 
-   * pgr->pos is implemented as a circular buffer of positions, and
-   * this circular buffer requires an extra "empty" spot.  Hence we
-   * increase the length by one. 
-   */
-  pgr = fc_malloc(sizeof(struct goto_route));
-  pgr->length = length + 1;
-  pgr->first_index = 0;
-  pgr->last_index = length;
-  pgr->pos = fc_malloc(pgr->length * sizeof(*pgr->pos));
-
-  for (i = 0; i < length; i++) {
-    pgr->pos[i].x = x[i];
-    pgr->pos[i].y = y[i];
+  for (i = 0; i < packet->length; i++) {
+    switch (packet->orders[i]) {
+    case ORDER_MOVE:
+      if (!is_valid_dir(packet->dir[i])) {
+       return;
+      }
+      break;
+    case ORDER_ACTIVITY:
+      switch (packet->activity[i]) {
+      case ACTIVITY_ROAD:
+      case ACTIVITY_RAILROAD:
+      case ACTIVITY_IRRIGATE:
+       break;
+      default:
+       return;
+      }
+      break;
+    case ORDER_FINISH_TURN:
+      break;
+    default:
+      /* An invalid order.  This is handled in execute_orders. */
+      packet->orders[i] = ORDER_LAST;
+      break;
+    }
   }
 
-  punit->pgr = pgr;
+  free_unit_orders(punit);
 
-#ifdef DEBUG
-  freelog(LOG_DEBUG, "first:%d, last:%d, length:%d",
-         pgr->first_index, pgr->last_index, pgr->length);
-  for (i = pgr->first_index; i < pgr->last_index; i++) {
-    freelog(LOG_NORMAL, "  %d,%d", pgr->pos[i].x, pgr->pos[i].y);
+  if (packet->length == 0) {
+    assert(!unit_has_orders(punit));
+    send_unit_info(NULL, punit);
+    return;
   }
-#endif
 
-  if (punit->activity == ACTIVITY_GOTO) {
-    set_goto_dest(punit, pgr->pos[pgr->last_index-1].x,
-                 pgr->pos[pgr->last_index-1].y);
-    send_unit_info(pplayer, punit);
+  punit->has_orders = TRUE;
+  punit->orders.length = packet->length;
+  punit->orders.index = 0;
+  punit->orders.repeat = packet->repeat;
+  punit->orders.vigilant = packet->vigilant;
+  punit->orders.list
+    = fc_malloc(packet->length * sizeof(*(punit->orders.list)));
+  for (i = 0; i < packet->length; i++) {
+    punit->orders.list[i].order = packet->orders[i];
+    punit->orders.list[i].dir = packet->dir[i];
+    punit->orders.list[i].activity = packet->activity[i];
   }
-
-  assign_units_to_transporter(punit, TRUE);
-  (void) goto_route_execute(punit);
-}
 
-/**************************************************************************
-Receives route packages.
-**************************************************************************/
-void handle_unit_route(struct player *pplayer, int unit_id,
-                      enum unit_activity activity, int length, int *x,
-                      int *y)
-{
-  struct unit *punit = player_find_unit_by_id(pplayer, unit_id);
+  if (!packet->repeat) {
+    set_goto_dest(punit, packet->dest_x, packet->dest_y);
+  }
 
-  if (!punit || length < 1
-      || !(activity == ACTIVITY_GOTO || activity == ACTIVITY_PATROL)) {
-    return;
+#ifdef DEBUG
+  freelog(LOG_DEBUG, "Orders for unit %d: length:%d",
+         packet->unit_id, packet->length);
+  for (i = 0; i < packet->length; i++) {
+    freelog(LOG_DEBUG, "  %d,%s", packet->orders[i],
+           dir_get_name(packet->dir[i]));
   }
+#endif
 
-  handle_unit_activity_request(punit, activity);
-  handle_route(pplayer, punit, length, x, y);
+  assign_units_to_transporter(punit, TRUE);
+  if (execute_orders(punit) != GR_DIED) {
+    send_unit_info(NULL, punit);
+  }
 }
Index: server/unittools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v
retrieving revision 1.270
diff -u -r1.270 unittools.c
--- server/unittools.c  2004/01/11 17:45:06     1.270
+++ server/unittools.c  2004/01/20 21:44:17
@@ -653,8 +653,7 @@
   struct tile *ptile = map_get_tile(punit->x, punit->y);
   
   if (activity != ACTIVITY_IDLE && activity != ACTIVITY_FORTIFIED
-      && activity != ACTIVITY_GOTO && activity != ACTIVITY_EXPLORE
-      && activity != ACTIVITY_PATROL) {
+      && activity != ACTIVITY_GOTO && activity != ACTIVITY_EXPLORE) {
     /*  We don't need the activity_count for the above */
     if (punit->moves_left > 0) {
       /* 
@@ -682,20 +681,6 @@
 
   unit_restore_movepoints(pplayer, punit);
 
-  if (punit->connecting && !can_unit_do_activity(punit, activity)) {
-    punit->activity_count = 0;
-    if (do_unit_goto(punit, get_activity_move_restriction(activity), FALSE)
-       == GR_DIED) {
-      return;
-    }
-  }
-
-  /* if connecting, automagically build prerequisities first */
-  if (punit->connecting && activity == ACTIVITY_RAILROAD &&
-      !map_has_special(punit->x, punit->y, S_ROAD)) {
-    activity = ACTIVITY_ROAD;
-  }
-
   if (activity == ACTIVITY_EXPLORE) {
     bool more_to_explore = ai_manage_explorer(punit);
 
@@ -868,18 +853,8 @@
     send_tile_info(NULL, punit->x, punit->y);
     unit_list_iterate (map_get_tile(punit->x, punit->y)->units, punit2) {
       if (punit2->activity == activity) {
-       bool alive = TRUE;
-       if (punit2->connecting) {
-         punit2->activity_count = 0;
-         alive = (do_unit_goto(punit2,
-                               get_activity_move_restriction(activity),
-                               FALSE) != GR_DIED);
-       } else {
-         set_unit_activity(punit2, ACTIVITY_IDLE);
-       }
-       if (alive) {
-         send_unit_info(NULL, punit2);
-       }
+       set_unit_activity(punit2, ACTIVITY_IDLE);
+       send_unit_info(NULL, punit2);
       }
     } unit_list_iterate_end;
   }
@@ -900,8 +875,8 @@
     return;
   }
 
-  if (punit->activity == ACTIVITY_PATROL) {
-    if (goto_route_execute(punit) == GR_DIED) {
+  if (unit_has_orders(punit)) {
+    if (execute_orders(punit) == GR_DIED) {
       return;
     }
   }
@@ -1890,10 +1865,16 @@
   }
   packet->activity_target = punit->activity_target;
   packet->paradropped = punit->paradropped;
-  packet->connecting = punit->connecting;
   packet->done_moving = punit->done_moving;
   packet->carried = carried;
   packet->occupy = get_transporter_occupancy(punit);
+  packet->has_orders = punit->has_orders;
+  if (punit->has_orders) {
+    packet->repeat = punit->orders.repeat;
+    packet->vigilant = punit->orders.vigilant;
+  } else {
+    packet->repeat = packet->vigilant = FALSE;
+  }
 }
 
 /**************************************************************************
@@ -1926,9 +1907,8 @@
   packet->type = punit->type;
   packet->hp = punit->hp;
   packet->occupied = (get_transporter_occupancy(punit) > 0);
-  if (punit->activity == ACTIVITY_GOTO
-      || punit->activity == ACTIVITY_EXPLORE
-      || punit->activity == ACTIVITY_PATROL) {
+  if (punit->activity == ACTIVITY_EXPLORE
+      || punit->activity == ACTIVITY_GOTO) {
     packet->activity = ACTIVITY_IDLE;
   } else {
     packet->activity = punit->activity;
@@ -2744,7 +2724,8 @@
   square_iterate(punit->x, punit->y, 3, x, y) {
     unit_list_iterate(map_get_tile(x, y)->units, ppatrol) {
       if (punit != ppatrol
-         && ppatrol->activity == ACTIVITY_PATROL) {
+         && unit_has_orders(ppatrol)
+         && ppatrol->orders.vigilant) {
        (void) maybe_cancel_patrol_due_to_enemy(ppatrol);
       }
     } unit_list_iterate_end;
@@ -2859,11 +2840,9 @@
 static void check_unit_activity(struct unit *punit)
 {
   if (punit->activity != ACTIVITY_IDLE
-      && punit->activity != ACTIVITY_GOTO
       && punit->activity != ACTIVITY_SENTRY
       && punit->activity != ACTIVITY_EXPLORE
-      && punit->activity != ACTIVITY_PATROL
-      && !punit->connecting) {
+      && punit->activity != ACTIVITY_GOTO) {
     set_unit_activity(punit, ACTIVITY_IDLE);
   }
 }
@@ -2905,7 +2884,8 @@
   }
 
   /* A transporter should not take units with it on an attack goto. */
-  if (punit->activity == ACTIVITY_GOTO
+  if ((unit_has_orders(punit)
+       || punit->activity == ACTIVITY_GOTO)
       && (is_non_allied_unit_tile(pdesttile, pplayer)
           || is_non_allied_city_tile(pdesttile, pplayer))
       && !is_ocean(psrctile->terrain)) {
@@ -2948,13 +2928,6 @@
       pcargo->x = dest_x;
       pcargo->y = dest_y;
 
-      if ((pcargo->activity == ACTIVITY_GOTO
-          || pcargo->activity == ACTIVITY_PATROL)
-         && !pcargo->ai.control) {
-       /* Cancel any _client_ gotos for these units. */
-       handle_unit_activity_request(pcargo, ACTIVITY_IDLE);
-      }
-
       unit_list_insert(&pdesttile->units, pcargo);
       check_unit_activity(pcargo);
       send_unit_info_to_onlookers(NULL, pcargo, src_x, src_y, FALSE);
@@ -3031,14 +3004,8 @@
     } unit_list_iterate_end;
     assert(punit->transported_by != -1);
 
-    /* set activity to sentry if boarding a ship unless the unit is just 
-     * passing through the ship on its way somewhere else.  If the unit is
-     * GOTOing and the ship isn't the final destination, then don't go
-     * to sleep. */
-    if (!(pplayer->ai.control)
-       && !(punit->activity == ACTIVITY_GOTO
-            && !same_pos(goto_dest_x(punit), goto_dest_y(punit),
-                         dest_x, dest_y))) {
+    /* Set activity to sentry if boarding a ship. */
+    if (!pplayer->ai.control && !unit_has_orders(punit)) {
       set_unit_activity(punit, ACTIVITY_SENTRY);
     }
 
@@ -3165,115 +3132,150 @@
   return cancel;
 }
 
-/**************************************************************************
-Moves a unit according to its pgr (goto or patrol order). If two consequetive
-positions in the route is not adjacent it is assumed to be a goto. The unit
-is put on idle if a move fails.
-If the activity is ACTIVITY_PATROL the map positions are put back in the
-route (at the end).  To avoid infinite loops on railroad we stop for this
-turn when the unit is back where it started, eben if it have moves left.
-
-If a patrolling unit came across an enemy we could make the patrolling unit
-autoattack or just stop and wait for the owner to attack. It is also
-debateable if units on goto should stop when they encountered an enemy
-unit. Currently the unit continues if it can, or if it is blocked it stops.
-**************************************************************************/
-enum goto_result goto_route_execute(struct unit *punit)
-{
-  struct goto_route *pgr = punit->pgr;
-  int index, x, y;
-  bool res, last_tile, moved;
-  int patrol_stop_index = pgr->last_index;
+/****************************************************************************
+  Executes a unit's orders stored in punit->orders.  The unit is put on idle
+  if an action fails or if "patrol" is set and an enemy unit is encountered.
+
+  If the orders are repeating the loop starts over at the beginning once it
+  completes.  To avoid infinite loops on railroad we stop for this
+  turn when the unit is back where it started, even if it have moves left.
+
+  A unit will attack under orders only on its final action.
+****************************************************************************/
+enum goto_result execute_orders(struct unit *punit)
+{
+  int dest_x, dest_y;
+  bool res, last_order;
   int unitid = punit->id;
   struct player *pplayer = unit_owner(punit);
+  int moves_made = 0;
+  enum unit_activity activity;
 
-  assert(pgr != NULL);
-  while (TRUE) {
-    freelog(LOG_DEBUG, "running a round\n");
+  assert(unit_has_orders(punit));
 
-    index = pgr->first_index;
-    if (index == pgr->last_index) {
-      free_unit_goto_route(punit);
-      if (punit->activity == ACTIVITY_GOTO) 
-       /* the activity could already be SENTRY (if boarded a ship) 
-          -- leave it as it is then */
-       handle_unit_activity_request(punit, ACTIVITY_IDLE);
-      return GR_ARRIVED;
-    }
-    x = pgr->pos[index].x; y = pgr->pos[index].y;
-    freelog(LOG_DEBUG, "%i,%i -> %i,%i\n", punit->x, punit->y, x, y);
+  if (punit->activity != ACTIVITY_IDLE) {
+    return GR_WAITING;
+  }
 
+  freelog(LOG_DEBUG, "Executing orders for %s %d",
+         unit_name(punit->type), punit->id);
+
+  while (TRUE) {
     if (punit->moves_left == 0) {
+      /* FIXME: this check won't work when actions take 0 MP. */
+      freelog(LOG_DEBUG, "  stopping because of no more move points");
       return GR_OUT_OF_MOVEPOINTS;
     }
 
-    if (punit->activity == ACTIVITY_PATROL
-       && maybe_cancel_patrol_due_to_enemy(punit)) {
-      return GR_FAILED;
+    if (punit->done_moving) {
+      freelog(LOG_DEBUG, "  stopping because we're done this turn");
+      return GR_WAITING;
     }
 
-    last_tile = (((index + 1) % pgr->length) == (pgr->last_index));
-
-    if (punit->activity == ACTIVITY_GOTO && !last_tile 
-        && maybe_cancel_goto_due_to_enemy(punit, x, y)) {
+    if (punit->orders.vigilant && maybe_cancel_patrol_due_to_enemy(punit)) {
+      /* "Patrol" orders are stopped if an enemy is near. */
+      freelog(LOG_DEBUG, "  stopping because of nearby enemy");
+      free_unit_orders(punit);
       return GR_FAILED;
     }
-
-    /* Move unit */
-    moved = !same_pos(punit->x, punit->y, x, y);
-    if (moved) {
-      res = handle_unit_move_request(punit, x, y, FALSE, !last_tile);
-    } else {
-      res = TRUE;
-    }
 
-    if (!player_find_unit_by_id(pplayer, unitid)) {
-      return GR_DIED;
+    if (moves_made == punit->orders.length) {
+      /* For repeating orders, don't repeat more than once per turn. */
+      freelog(LOG_DEBUG, "  stopping because we ran a round");
+      return GR_ARRIVED;
     }
 
-    if (same_pos(punit->x, punit->y, x, y)) {
-      /* We succeeded in moving one step forward */
-      pgr->first_index = (pgr->first_index + 1) % pgr->length;
-      if (punit->activity == ACTIVITY_PATROL) {
-       /* When patroling we go in little circles; 
-        * done by reinserting points */
-       pgr->pos[pgr->last_index].x = x;
-       pgr->pos[pgr->last_index].y = y;
-       pgr->last_index = (pgr->last_index + 1) % pgr->length;
-
-       if (patrol_stop_index == pgr->first_index) {
-         freelog(LOG_DEBUG, "stopping because we ran a round\n");
-         return GR_ARRIVED;    /* don't patrol more than one round */
-       }
-       if (maybe_cancel_patrol_due_to_enemy(punit)) {
-         return GR_FAILED;
-       }
-      }
+    last_order = (!punit->orders.repeat
+                 && punit->orders.index + 1 == punit->orders.length);
 
-      if (!moved) {
-       /* Sometimes the goto route will have us sit still for a moment -
-        * for instance a trireme will do this to have enough MP to
-        * cross the ocean in one turn. */
-       punit->done_moving = TRUE;
-       send_unit_info(unit_owner(punit), punit);
-       return GR_WAITING;
-      }
+    switch (punit->orders.list[punit->orders.index].order) {
+    case ORDER_FINISH_TURN:
+      punit->done_moving = TRUE;
+      freelog(LOG_DEBUG, "  waiting this turn");
+      send_unit_info(unit_owner(punit), punit);
+      break;
+    case ORDER_ACTIVITY:
+      activity = punit->orders.list[punit->orders.index].activity;
+      if (!can_unit_do_activity(punit, activity)) {
+       freelog(LOG_DEBUG, "  orders canceled because of failed activity");
+       free_unit_orders(punit);
+       return GR_FAILED;
+      }
+      set_unit_activity(punit, activity);
+      punit->done_moving = TRUE;
+      break;
+    case ORDER_MOVE:
+      /* Move unit */
+      if (!MAPSTEP(dest_x, dest_y, punit->x, punit->y,
+                  punit->orders.list[punit->orders.index].dir)) {
+       freelog(LOG_DEBUG, "  move order %d sent us to invalid location",
+               punit->orders.list[punit->orders.index].dir);
+       free_unit_orders(punit);
+       return GR_FAILED;
+      }
+
+      if (!last_order
+         && maybe_cancel_goto_due_to_enemy(punit, dest_x, dest_y)) {
+       freelog(LOG_DEBUG, "  orders canceled because of enemy");
+       free_unit_orders(punit);
+       return GR_FAILED;
+      }
+
+      freelog(LOG_DEBUG, "  moving %s to %d,%d",
+             dir_get_name(punit->orders.list[punit->orders.index].dir),
+             dest_x, dest_y);
+      res = handle_unit_move_request(punit, dest_x, dest_y,
+                                    FALSE, !last_order);
+      if (!player_find_unit_by_id(pplayer, unitid)) {
+       freelog(LOG_DEBUG, "  unit died while moving.");
+       return GR_DIED;
+      }
+
+      if (res && !same_pos(dest_x, dest_y, punit->x, punit->y)) {
+       /* Movement succeeded but unit didn't move. */
+       freelog(LOG_DEBUG, "  orders resulted in combat.");
+       return GR_FOUGHT;
+      }
+
+      if (!res && punit->moves_left > 0) {
+       /* Movement failed (ZOC, etc.) */
+       freelog(LOG_DEBUG, "  attempt to move failed.");
+       abort();
+       free_unit_orders(punit);
+       return GR_FAILED;
+      }
+
+      if (last_order && punit->transported_by != -1) {
+       /* Set activity to sentry if boarding a ship.  This is done in
+        * move_unit, but that function doesn't handle the orders case. */
+       set_unit_activity(punit, ACTIVITY_SENTRY);
+      }
+      break;
+    case ORDER_LAST:
+      freelog(LOG_DEBUG, "  client sent invalid order!");
+      notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT,
+                      _("Game: Your %s has invalid orders."),
+                      unit_name(punit->type));
+      free_unit_orders(punit);
+      return GR_FAILED;
     }
 
-    if (res && !same_pos(x, y, punit->x, punit->y)) {
-      /*
-       * unit is alive, moved alright, didn't arrive, has moves_left
-       * --- what else can it be 
-       */
-      return GR_FOUGHT;
-    }
+    /* We succeeded in moving one step forward */
+    punit->orders.index++;
 
-    if (!res && punit->moves_left > 0) {
-      freelog(LOG_DEBUG, "move idling\n");
-      handle_unit_activity_request(punit, ACTIVITY_IDLE);
-      return GR_FAILED;
+    if (punit->orders.index == punit->orders.length) {
+      if (!punit->orders.repeat) {
+       free_unit_orders(punit);
+       assert(punit->has_orders == FALSE);
+       freelog(LOG_DEBUG, "  stopping because orders are complete");
+       return GR_ARRIVED;
+      } else {
+       /* Start over. */
+       freelog(LOG_DEBUG, "  repeating orders.");
+       punit->orders.index = 0;
+      }
     }
-  } /* end while*/
+  } /* end while */
 }
 
 /**************************************************************************
Index: server/unittools.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unittools.h,v
retrieving revision 1.60
diff -u -r1.60 unittools.h
--- server/unittools.h  2004/01/11 17:45:06     1.60
+++ server/unittools.h  2004/01/20 21:44:17
@@ -82,6 +82,6 @@
 void assign_units_to_transporter(struct unit *ptrans, bool take_from_land);
 bool move_unit(struct unit *punit, int dest_x, int dest_y,
              bool transport_units, bool take_from_land, int move_cost);
-enum goto_result goto_route_execute(struct unit *punit);
+enum goto_result execute_orders(struct unit *punit);
 
 #endif  /* FC__UNITTOOLS_H */

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#7282) connect as orders, Jason Short <=