Complete.Org: Mailing Lists: Archives: freeciv-dev: December 2004:
[Freeciv-Dev] (PR#7344) Patch: Expanded Orders
Home

[Freeciv-Dev] (PR#7344) Patch: Expanded Orders

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: a-l@xxxxxxx
Subject: [Freeciv-Dev] (PR#7344) Patch: Expanded Orders
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Tue, 7 Dec 2004 01:24:16 -0800
Reply-to: rt@xxxxxxxxxxx

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

Attached is a new up-to-date "expanded orders" patch.  This patch
introduces just one new order: ORDER_BUILD_CITY.  This order is
supported at the server.  Also included are some client changes to
provide a menu option to goto-location-and-build-city (ctrl-shift-b).

This is a preliminary patch.  Please test and comment on the design.

--- Common design

I considered making a new ORDER_ACTION, with a separate enum
unit_action.  The list of unit actions could then grow and grow.  But I
figured this didn't give any advantage over making all ACTIONs into
their own orders.  So instead we just have a new order type
ORDER_BUILD_CITY.  Note that there are many more (potentially dozens) of
possible actions, so this could grow a bit.

--- Server design

I was tempted to change the server design a bit.  But in the end the
only changes I made to unittools was to add support for the new order. 
However this design won't scale well because eventually execute_orders()
will be hundreds or thousands of lines long.  I think a callback
mechanism with a lookup into an array of functions would work ok.  Also
note that calling handle_xxx() really isn't the best thing to do here
since handle_xxx() functions are pretty fuzzy.  This is the same problem
the AI runs into - for instance handle_city_build may build a new city
or add on to an existing city, it gives an error message for some
failures but returns silently for others, and never is there a return
value to indicate what happened.

--- Client design

This is pretty ugly.  We have the hover state (HOVER_PATROL,
HOVER_CONNECT, HOVER_GOTO, HOVER_NUKE, etc.).  We have the connect
activity (an enum unit_activity), which is only valid for HOVER_CONNECT.
 And we have the last order (enum unit_orders), which is only valid for
HOVER_GOTO.  send_path_orders() handles CONNECT, GOTO (except air goto
which is completely separate), and PATROL, and so must take both an
activity and a last order.  Confused yet?  The code is.  Getting rid of
server goto would help.

jason

Index: client/control.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/control.c,v
retrieving revision 1.150
diff -u -r1.150 control.c
--- client/control.c    13 Nov 2004 08:27:46 -0000      1.150
+++ client/control.c    7 Dec 2004 09:12:51 -0000
@@ -55,6 +55,7 @@
 int hover_unit = 0; /* id of unit hover_state applies to */
 enum cursor_hover_state hover_state = HOVER_NONE;
 enum unit_activity connect_activity;
+enum unit_orders goto_last_order; /* Last order for goto */
 /* 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;
@@ -77,13 +78,18 @@
                         enum quickselect_type qtype);
 
 /**************************************************************************
-...
+  Enter the given hover state.
+
+    activity => The connect activity (ACTIVITY_ROAD, etc.)
+    order => The last order (ORDER_BUILD_CITY, ORDER_LAST, etc.)
 **************************************************************************/
 void set_hover_state(struct unit *punit, enum cursor_hover_state state,
-                    enum unit_activity activity)
+                    enum unit_activity activity,
+                    enum unit_orders order)
 {
   assert(punit != NULL || state == HOVER_NONE);
   assert(state == HOVER_CONNECT || activity == ACTIVITY_LAST);
+  assert(state == HOVER_GOTO || order == ORDER_LAST);
   draw_goto_line = TRUE;
   if (punit)
     hover_unit = punit->id;
@@ -91,6 +97,7 @@
     hover_unit = 0;
   hover_state = state;
   connect_activity = activity;
+  goto_last_order = order;
   exit_goto_state();
 }
 
@@ -222,7 +229,7 @@
   struct unit *punit_old_focus = punit_focus;
   struct unit *candidate = find_best_focus_candidate(FALSE);
 
-  set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST);
+  set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, ORDER_LAST);
   if (!can_client_change_view()) {
     return;
   }
@@ -593,9 +600,9 @@
 }
 
 /**************************************************************************
-...
+  Do a goto with an order at the end (or ORDER_LAST).
 **************************************************************************/
-void request_unit_goto(void)
+void request_unit_goto(enum unit_orders last_order)
 {
   struct unit *punit = punit_focus;
 
@@ -603,7 +610,7 @@
     return;
 
   if (hover_state != HOVER_GOTO) {
-    set_hover_state(punit, HOVER_GOTO, ACTIVITY_LAST);
+    set_hover_state(punit, HOVER_GOTO, ACTIVITY_LAST, last_order);
     update_unit_info_label(punit);
     /* Not yet implemented for air units, including helicopters. */
     if (is_air_unit(punit) || is_heli_unit(punit)) {
@@ -695,7 +702,7 @@
 
   if (hover_state != HOVER_CONNECT || connect_activity != activity) {
     /* Enter or change the hover connect state. */
-    set_hover_state(punit_focus, HOVER_CONNECT, activity);
+    set_hover_state(punit_focus, HOVER_CONNECT, activity, ORDER_LAST);
     update_unit_info_label(punit_focus);
 
     enter_goto_state(punit_focus);
@@ -762,15 +769,19 @@
   }
 
   if ((path = path_to_nearest_allied_city(punit))) {
-    enum unit_activity activity = ACTIVITY_LAST;
     int turns = pf_last_position(path)->turn;
 
     if (punit->hp + turns * get_player_bonus(game.player_ptr,
                                             EFT_UNIT_RECOVER)
        < unit_type(punit)->hp) {
-      activity = ACTIVITY_SENTRY;
+      struct unit_order order;
+
+      order.order = ORDER_ACTIVITY;
+      order.activity = ACTIVITY_SENTRY;
+      send_goto_path(punit, path, &order);
+    } else {
+      send_goto_path(punit, path, NULL);
     }
-    send_goto_path(punit, path, activity);
     pf_destroy_path(path);
   }
 }
@@ -995,7 +1006,7 @@
   if(punit->moves_left == 0)
     do_unit_nuke(punit);
   else {
-    set_hover_state(punit, HOVER_NUKE, ACTIVITY_LAST);
+    set_hover_state(punit, HOVER_NUKE, ACTIVITY_LAST, ORDER_LAST);
     update_unit_info_label(punit);
   }
 }
@@ -1012,7 +1023,7 @@
   if(!can_unit_paradrop(punit))
     return;
 
-  set_hover_state(punit, HOVER_PARADROP, ACTIVITY_LAST);
+  set_hover_state(punit, HOVER_PARADROP, ACTIVITY_LAST, ORDER_LAST);
   update_unit_info_label(punit);
 }
 
@@ -1027,7 +1038,7 @@
     return;
 
   if (hover_state != HOVER_PATROL) {
-    set_hover_state(punit, HOVER_PATROL, ACTIVITY_LAST);
+    set_hover_state(punit, HOVER_PATROL, ACTIVITY_LAST, ORDER_LAST);
     update_unit_info_label(punit);
     /* Not yet implemented for air units, including helicopters. */
     if (is_air_unit(punit) || is_heli_unit(punit)) {
@@ -1447,7 +1458,7 @@
       do_unit_patrol_to(punit, ptile);
       break;   
     }
-    set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST);
+    set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, ORDER_LAST);
     update_unit_info_label(punit);
   }
 
@@ -1641,7 +1652,7 @@
     }
   }
 
-  set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST);
+  set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, ORDER_LAST);
 }
 
 /**************************************************************************
@@ -1680,7 +1691,7 @@
     }
   }
 
-  set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST);
+  set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, ORDER_LAST);
 }
  
 /**************************************************************************
@@ -1705,7 +1716,7 @@
     }
   }
 
-  set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST);
+  set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, ORDER_LAST);
 }
  
 /**************************************************************************
@@ -1724,7 +1735,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, ACTIVITY_LAST);
+    set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, ORDER_LAST);
     update_unit_info_label(punit);
 
     keyboardless_goto_button_down = FALSE;
@@ -1842,7 +1853,7 @@
 void key_unit_goto(void)
 {
   if (punit_focus) {
-    request_unit_goto();
+    request_unit_goto(ORDER_LAST);
   }
 }
 
Index: client/control.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/control.h,v
retrieving revision 1.45
diff -u -r1.45 control.h
--- client/control.h    29 Sep 2004 02:24:19 -0000      1.45
+++ client/control.h    7 Dec 2004 09:12:51 -0000
@@ -32,6 +32,7 @@
 extern int hover_unit; /* unit hover_state applies to */
 extern enum cursor_hover_state hover_state;
 extern enum unit_activity connect_activity;
+extern enum unit_orders goto_last_order;
 extern bool draw_goto_line;
 extern bool non_ai_unit_focus;
 
@@ -47,7 +48,8 @@
 void do_map_click(struct tile *ptile, enum quickselect_type qtype);
 
 void set_hover_state(struct unit *punit, enum cursor_hover_state state,
-                    enum unit_activity activity);
+                    enum unit_activity connect_activity,
+                    enum unit_orders goto_last_order);
 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);
@@ -63,7 +65,7 @@
 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);
+void request_unit_goto(enum unit_orders last_order);
 void request_unit_move_done(void);
 void request_unit_nuke(struct unit *punit);
 void request_unit_paradrop(struct unit *punit);
Index: client/goto.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/goto.c,v
retrieving revision 1.79
diff -u -r1.79 goto.c
--- client/goto.c       22 Nov 2004 19:14:41 -0000      1.79
+++ client/goto.c       7 Dec 2004 09:12:51 -0000
@@ -793,7 +793,7 @@
 **************************************************************************/
 static void send_path_orders(struct unit *punit, struct pf_path *path,
                             bool repeat, bool vigilant,
-                            enum unit_activity final_activity)
+                            struct unit_order *final_order)
 {
   struct packet_unit_orders p;
   int i;
@@ -834,10 +834,11 @@
     old_tile = new_tile;
   }
 
-  if (final_activity != ACTIVITY_LAST) {
-    p.orders[i] = ORDER_ACTIVITY;
-    p.dir[i] = -1;
-    p.activity[i] = final_activity;
+  if (final_order) {
+    p.orders[i] = final_order->order;
+    p.dir[i] = (final_order->order == ORDER_MOVE) ? final_order->dir : -1;
+    p.activity[i] = (final_order->order == ORDER_ACTIVITY)
+      ? final_order->activity : ACTIVITY_LAST;
     p.length++;
   }
 
@@ -851,9 +852,9 @@
   Send an arbitrary goto path for the unit to the server.
 **************************************************************************/
 void send_goto_path(struct unit *punit, struct pf_path *path,
-                   enum unit_activity final_activity)
+                   struct unit_order *final_order)
 {
-  send_path_orders(punit, path, FALSE, FALSE, final_activity);
+  send_path_orders(punit, path, FALSE, FALSE, final_order);
 }
 
 /**************************************************************************
@@ -887,7 +888,7 @@
   pf_destroy_map(map);
   pf_destroy_path(return_path);
 
-  send_path_orders(punit, path, TRUE, TRUE, ACTIVITY_LAST);
+  send_path_orders(punit, path, TRUE, TRUE, NULL);
 
   pf_destroy_path(path);
 }
@@ -987,7 +988,14 @@
     path = pft_concat(path, goto_map.parts[i].path);
   }
 
-  send_goto_path(punit, path, ACTIVITY_LAST);
+  if (goto_last_order == ORDER_LAST) {
+    send_goto_path(punit, path, NULL);
+  } else {
+    struct unit_order order;
+
+    order.order = goto_last_order;
+    send_goto_path(punit, path, &order);
+  }
   pf_destroy_path(path);
 }
 
Index: client/goto.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/goto.h,v
retrieving revision 1.16
diff -u -r1.16 goto.h
--- client/goto.h       29 Sep 2004 02:24:19 -0000      1.16
+++ client/goto.h       7 Dec 2004 09:12:51 -0000
@@ -34,7 +34,7 @@
 
 void request_orders_cleared(struct unit *punit);
 void send_goto_path(struct unit *punit, struct pf_path *path,
-                   enum unit_activity final_activity);
+                   struct unit_order *last_order);
 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);
Index: client/mapctrl_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapctrl_common.c,v
retrieving revision 1.43
diff -u -r1.43 mapctrl_common.c
--- client/mapctrl_common.c     22 Nov 2004 19:31:30 -0000      1.43
+++ client/mapctrl_common.c     7 Dec 2004 09:12:52 -0000
@@ -427,7 +427,7 @@
         player_find_unit_by_id(game.player_ptr, hover_unit);
 
     do_unit_goto(ptile);
-    set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST);
+    set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, ORDER_LAST);
     update_unit_info_label(punit);
   }
   keyboardless_goto_active = FALSE;
@@ -447,7 +447,7 @@
       && !same_pos(keyboardless_goto_start_tile, ptile)
       && can_client_issue_orders()) {
     keyboardless_goto_active = TRUE;
-    request_unit_goto();
+    request_unit_goto(ORDER_LAST);
   }
 }
 
Index: client/mapview_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.c,v
retrieving revision 1.163
diff -u -r1.163 mapview_common.c
--- client/mapview_common.c     6 Dec 2004 18:01:14 -0000       1.163
+++ client/mapview_common.c     7 Dec 2004 09:12:52 -0000
@@ -1910,7 +1910,7 @@
   anim_timer = renew_timer_start(anim_timer, TIMER_USER, TIMER_ACTIVE);
 
   if (punit == get_unit_in_focus() && hover_state != HOVER_NONE) {
-    set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST);
+    set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, ORDER_LAST);
     update_unit_info_label(punit);
   }
 
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.147
diff -u -r1.147 mapview.c
--- client/gui-gtk-2.0/mapview.c        1 Nov 2004 03:39:45 -0000       1.147
+++ client/gui-gtk-2.0/mapview.c        7 Dec 2004 09:12:53 -0000
@@ -188,7 +188,7 @@
 
   if(punit) {
     if (hover_unit != punit->id)
-      set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST);
+      set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, ORDER_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.57
diff -u -r1.57 menu.c
--- client/gui-gtk-2.0/menu.c   25 Nov 2004 06:57:17 -0000      1.57
+++ client/gui-gtk-2.0/menu.c   7 Dec 2004 09:12:53 -0000
@@ -129,6 +129,7 @@
   MENU_ORDER_CONNECT_ROAD,
   MENU_ORDER_CONNECT_RAIL,
   MENU_ORDER_CONNECT_IRRIGATE,
+  MENU_ORDER_GO_BUILD_CITY,
   MENU_ORDER_PATROL,
   MENU_ORDER_GOTO,
   MENU_ORDER_GOTO_CITY,
@@ -447,6 +448,9 @@
    case MENU_ORDER_CONNECT_ROAD:
     key_unit_connect(ACTIVITY_ROAD);
     break;
+  case MENU_ORDER_GO_BUILD_CITY:
+    request_unit_goto(ORDER_BUILD_CITY);
+    break;
    case MENU_ORDER_CONNECT_RAIL:
     key_unit_connect(ACTIVITY_RAILROAD);
     break;
@@ -787,6 +791,8 @@
    orders_menu_callback, MENU_ORDER_CONNECT_RAIL},
   {"/" N_("Orders") "/" N_("_Connect") "/" N_("_Irrigate"), "<ctrl><shift>i",
    orders_menu_callback, MENU_ORDER_CONNECT_IRRIGATE},
+  {"/" N_("Orders") "/" N_("Go _to") "/" N_("_Build city"), "<ctrl><shift>b",
+   orders_menu_callback, MENU_ORDER_GO_BUILD_CITY},
   { "/" N_("Orders") "/" N_("Patrol (_Q)"),            "q",
        orders_menu_callback,   MENU_ORDER_PATROL                               
        },
   { "/" N_("Orders") "/" N_("_Go to"),                 "g",
Index: common/unit.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unit.h,v
retrieving revision 1.130
diff -u -r1.130 unit.h
--- common/unit.h       6 Dec 2004 18:01:15 -0000       1.130
+++ common/unit.h       7 Dec 2004 09:12:53 -0000
@@ -34,9 +34,10 @@
   ACTIVITY_LAST   /* leave this one last */
 };
 
-/* Changing this enum will break savegame and network compatability. */
+/* Changing this enum will break network compatability. */
 enum unit_orders {
-  ORDER_MOVE, ORDER_FULL_MP, ORDER_ACTIVITY,
+  ORDER_MOVE, ORDER_ACTIVITY,
+  ORDER_FULL_MP, ORDER_BUILD_CITY, /* and plenty more for later... */
   ORDER_LAST
 };
 
Index: server/savegame.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/savegame.c,v
retrieving revision 1.210
diff -u -r1.210 savegame.c
--- server/savegame.c   30 Nov 2004 08:37:03 -0000      1.210
+++ server/savegame.c   7 Dec 2004 09:12:54 -0000
@@ -266,6 +266,9 @@
   case 'w':
   case 'W':
     return ORDER_FULL_MP;
+  case 'b':
+  case 'B':
+    return ORDER_BUILD_CITY;
   case 'a':
   case 'A':
     return ORDER_ACTIVITY;
@@ -287,6 +290,8 @@
     return 'w';
   case ORDER_ACTIVITY:
     return 'a';
+  case ORDER_BUILD_CITY:
+    return 'b';
   case ORDER_LAST:
     break;
   }
@@ -2662,6 +2667,7 @@
          act_buf[j] = activity2char(punit->orders.list[j].activity);
          break;
        case ORDER_FULL_MP:
+       case ORDER_BUILD_CITY:
        case ORDER_LAST:
          break;
        }
Index: server/unithand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unithand.c,v
retrieving revision 1.316
diff -u -r1.316 unithand.c
--- server/unithand.c   4 Dec 2004 04:44:08 -0000       1.316
+++ server/unithand.c   7 Dec 2004 09:12:54 -0000
@@ -1607,6 +1607,9 @@
 
 
   for (i = 0; i < packet->length; i++) {
+    if (packet->orders[i] < 0 || packet->orders[i] > ORDER_LAST) {
+      packet->orders[i] = ORDER_LAST;
+    }
     switch (packet->orders[i]) {
     case ORDER_MOVE:
       if (!is_valid_dir(packet->dir[i])) {
@@ -1636,10 +1639,10 @@
       }
       break;
     case ORDER_FULL_MP:
+    case ORDER_BUILD_CITY:
       break;
-    default:
+    case ORDER_LAST:
       /* An invalid order.  This is handled in execute_orders. */
-      packet->orders[i] = ORDER_LAST;
       break;
     }
   }
Index: server/unittools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v
retrieving revision 1.312
diff -u -r1.312 unittools.c
--- server/unittools.c  6 Dec 2004 18:01:15 -0000       1.312
+++ server/unittools.c  7 Dec 2004 09:12:55 -0000
@@ -3075,6 +3075,21 @@
        send_unit_info(NULL, punit);
       }
       break;
+    case ORDER_BUILD_CITY:
+      handle_unit_build_city(pplayer, unitid,
+                            city_name_suggestion(pplayer, punit->tile));
+      freelog(LOG_DEBUG, "  building city");
+      if (player_find_unit_by_id(pplayer, unitid)) {
+       /* Build failed. */
+       cancel_orders(punit, " orders canceled; failed to build city");
+       notify_player_ex(pplayer, punit->tile, E_UNIT_ORDERS,
+                        _("Game: Orders for %s aborted because building "
+                          "of city failed."), unit_name(punit->type));
+       return TRUE;
+      } else {
+       /* Build succeeded => unit "died" */
+       return FALSE;
+      }
     case ORDER_ACTIVITY:
       activity = order.activity;
       if (!can_unit_do_activity(punit, activity)) {

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#7344) Patch: Expanded Orders, Jason Short <=