<URL: http://bugs.freeciv.org/Ticket/Display.html?id=40462 >

 This patch implements saving of ongoing base building activity with
variable number of base types.


 - ML

diff -Nurd -X.diff_ignore freeciv/server/savegame.c freeciv/server/savegame.c
--- freeciv/server/savegame.c   2008-08-12 17:07:40.000000000 +0300
+++ freeciv/server/savegame.c   2008-08-12 17:53:39.000000000 +0300
@@ -234,6 +234,8 @@
        ;/* savefile_options_default */
 
 static const char hex_chars[] = "0123456789abcdef";
+static const char num_chars[] =
+  "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-+";
 
 static void set_savegame_special(bv_special *specials,
                    char ch, const enum tile_special_type *index);
@@ -277,6 +279,34 @@
 }
 
 /****************************************************************************
+  Converts number in to single character. This works to values up to ~70.
+****************************************************************************/
+static char num2char(unsigned int num)
+{
+  if (num >= strlen(num_chars)) {
+    return '?';
+  }
+
+  return num_chars[num];
+}
+
+/****************************************************************************
+  Converts single character into numerical value. This is not hex conversion.
+****************************************************************************/
+static int char2num(char ch)
+{
+  char *pch;
+
+  pch = strchr(num_chars, ch);
+
+  if (!pch) {
+    die("Unknown ascii value for num: '%c' %d", ch, ch);
+  }
+
+  return pch - num_chars;
+}
+
+/****************************************************************************
   Dereferences the terrain character.  See terrains[].identifier
     example: char2terrain('a') => T_ARCTIC
 ****************************************************************************/
@@ -1562,7 +1592,8 @@
 ****************************************************************************/
 static void player_load_units(struct player *plr, int plrno,
                              struct section_file *file,
-                             char *savefile_options)
+                             char *savefile_options,
+                              struct base_type **base_order)
 {
   int nunits, i, j;
   enum unit_activity activity;
@@ -1580,7 +1611,8 @@
     const char* type_name;
     struct unit_type *type;
     struct base_type *pbase = NULL;
-    
+    int base;
+
     type_name = secfile_lookup_str_default(file, NULL,
                                            "player%d.u%d.type_by_name",
                                            plrno, i);
@@ -1641,6 +1673,9 @@
     punit->birth_turn = secfile_lookup_int_default(file, game.info.turn,
                                                    "player%d.u%d.born", plrno, 
i);
     activity = secfile_lookup_int(file, "player%d.u%d.activity", plrno, i);
+    base = secfile_lookup_int_default(file, -1,
+                                      "player%d.u%d.activity_base", 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
@@ -1657,10 +1692,14 @@
     } else if (activity == ACTIVITY_AIRBASE) {
       pbase = get_base_by_gui_type(BASE_GUI_AIRBASE, punit, punit->tile);
     } else if (activity == ACTIVITY_BASE) {
-      /* This should currently not happen as ACTIVITY_BASE is saved as
-       * ACTIVITY_FORTRESS or ACTIVITY_AIRBASE. We don't know base type,
-       * let's use sensible fallback */
-      set_unit_activity_base(punit, BASE_FORTRESS);
+      if (base >= 0
+          && base < sizeof(base_order) / sizeof (struct base_type *)) {
+        pbase = base_order[base];
+      } else {
+        freelog(LOG_ERROR, "Cannot find base %d for %s to build",
+                base, unit_rule_name(punit));
+        set_unit_activity(punit, ACTIVITY_IDLE);
+      }
     } else {
       set_unit_activity(punit, activity);
     }
@@ -1745,7 +1784,7 @@
       int len = secfile_lookup_int_default(file, 0,
                        "player%d.u%d.orders_length", plrno, i);
       if (len > 0) {
-       char *orders_buf, *dir_buf, *act_buf;
+       char *orders_buf, *dir_buf, *act_buf, *base_buf;
 
        punit->orders.list = fc_malloc(len * sizeof(*(punit->orders.list)));
        punit->orders.length = len;
@@ -1762,6 +1801,8 @@
                        "player%d.u%d.dir_list", plrno, i);
        act_buf = secfile_lookup_str_default(file, "",
                        "player%d.u%d.activity_list", plrno, i);
+        base_buf = secfile_lookup_str_default(file, NULL,
+                                             "player%d.u%d.base_list", plrno, 
i);
        punit->has_orders = TRUE;
        for (j = 0; j < len; j++) {
          struct unit_order *order = &punit->orders.list[j];
@@ -1787,6 +1828,7 @@
            break;
          }
 
+          /* Pre 2.2 savegames had activities ACTIVITY_FORTRESS and 
ACTIVITY_AIRBASE */
           if (order->activity == ACTIVITY_FORTRESS) {
             pbase = get_base_by_gui_type(BASE_GUI_FORTRESS, NULL, NULL);
             order->activity = ACTIVITY_IDLE; /* In case no matching gui_type 
found */
@@ -1794,11 +1836,23 @@
             pbase = get_base_by_gui_type(BASE_GUI_AIRBASE, NULL, NULL);
             order->activity = ACTIVITY_IDLE; /* In case no matching gui_type 
found */
           }
-
           if (pbase) {
             /* Either ACTIVITY_FORTRESS or ACTIVITY_AIRBASE */
             order->activity = ACTIVITY_BASE;
             order->base = base_number(pbase);
+          } else if (base_buf) {
+            base = char2num(base_buf[j]);
+
+            if (base >= 0
+                && base < sizeof(base_order) / sizeof (struct base_type *)) {
+              pbase = base_order[base];
+            } else {
+              freelog(LOG_ERROR, "Cannot find base %d for %s to build",
+                      base, unit_rule_name(punit));
+              base = base_number(get_base_by_gui_type(BASE_GUI_FORTRESS, NULL, 
NULL));
+            }
+
+            order->base = base;
           }
        }
       } else {
@@ -3290,6 +3344,7 @@
 
   unit_list_iterate(plr->units, punit) {
     int activity = punit->activity;
+    char basenum = -1;
 
     i++;
 
@@ -3306,17 +3361,7 @@
                       plrno, i);
 
     if (activity == ACTIVITY_BASE) {
-      struct base_type *pbase;
-      pbase = base_by_number(punit->activity_base);
-
-      if (pbase->gui_type == BASE_GUI_FORTRESS) {
-        activity = ACTIVITY_FORTRESS;
-      } else if (pbase->gui_type == BASE_GUI_AIRBASE) {
-        activity = ACTIVITY_AIRBASE;
-      } else {
-        /* Gui type other. Make sensible fallback */
-        activity = ACTIVITY_FORTRESS;
-      }
+      basenum = punit->activity_base;
     }
     secfile_insert_int(file, activity, "player%d.u%d.activity",
                        plrno, i);
@@ -3326,6 +3371,7 @@
     secfile_insert_int(file, punit->activity_target, 
                                "player%d.u%d.activity_target",
                                plrno, i);
+    secfile_insert_int(file, basenum, "player%d.u%d.activity_base", 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",
@@ -3366,7 +3412,7 @@
                       "player%d.u%d.transported_by", plrno, i);
     if (punit->has_orders) {
       int len = punit->orders.length, j;
-      char orders_buf[len + 1], dir_buf[len + 1], act_buf[len + 1];
+      char orders_buf[len + 1], dir_buf[len + 1], act_buf[len + 1], 
base_buf[len + 1];
 
       secfile_insert_int(file, len, "player%d.u%d.orders_length", plrno, i);
       secfile_insert_int(file, punit->orders.index,
@@ -3380,26 +3426,16 @@
        orders_buf[j] = order2char(punit->orders.list[j].order);
        dir_buf[j] = '?';
        act_buf[j] = '?';
+        base_buf[j] = '?';
        switch (punit->orders.list[j].order) {
        case ORDER_MOVE:
          dir_buf[j] = dir2char(punit->orders.list[j].dir);
          break;
        case ORDER_ACTIVITY:
           if (punit->orders.list[j].activity == ACTIVITY_BASE) {
-            struct base_type *pbase;
-            pbase = base_by_number(punit->orders.list[j].base);
-
-            if (pbase->gui_type == BASE_GUI_FORTRESS) {
-              act_buf[j] = activity2char(ACTIVITY_FORTRESS);
-            } else if (pbase->gui_type == BASE_GUI_AIRBASE) {
-              act_buf[j] = activity2char(ACTIVITY_AIRBASE);
-            } else {
-              /* Saving others as fortress */
-              act_buf[j] = activity2char(ACTIVITY_FORTRESS);
-            }
-          } else {
-            act_buf[j] = activity2char(punit->orders.list[j].activity);
+            base_buf[j] = num2char(punit->orders.list[j].base);
           }
+          act_buf[j] = activity2char(punit->orders.list[j].activity);
          break;
        case ORDER_FULL_MP:
        case ORDER_BUILD_CITY:
@@ -3419,6 +3455,8 @@
                         "player%d.u%d.dir_list", plrno, i);
       secfile_insert_str(file, act_buf,
                         "player%d.u%d.activity_list", plrno, i);
+      secfile_insert_str(file, base_buf,
+                         "player%d.u%d.base_list", plrno, i);
     } else {
       /* Put all the same fields into the savegame - otherwise the
        * registry code can't correctly use a tabular format and the
@@ -3435,6 +3473,8 @@
                         "player%d.u%d.dir_list", plrno, i);
       secfile_insert_str(file, "-",
                         "player%d.u%d.activity_list", plrno, i);
+      secfile_insert_str(file, "-",
+                         "player%d.u%d.base_list", plrno, i);
     }
   } unit_list_iterate_end;
 }
@@ -4493,7 +4533,7 @@
 
       player_load_cities(pplayer, n, file, savefile_options,
                         improvement_order, improvement_order_size);
-      player_load_units(pplayer, n, file, savefile_options);
+      player_load_units(pplayer, n, file, savefile_options, base_order);
       player_load_attributes(pplayer, n, file);
     } players_iterate_end;
 
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to