Complete.Org: Mailing Lists: Archives: freeciv-dev: July 2004:
[Freeciv-Dev] (PR#9493) Technology saved by name
Home

[Freeciv-Dev] (PR#9493) Technology saved by name

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] (PR#9493) Technology saved by name
From: "Mateusz Stefek" <mstefek@xxxxxxxxx>
Date: Sat, 24 Jul 2004 02:32:02 -0700
Reply-to: rt@xxxxxxxxxxx

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

> Everything is implemented in the exactly same way as improvements.
> Patch also changes some comments to use term forward-compatibility
> instead of backward-compatibility.
> 
> --
> mateusz
Ups, wrong patch
--
mateusz

diff -ur -Xdiff_ignore freeorig/common/tech.c freeciv/common/tech.c
--- freeorig/common/tech.c      2004-07-19 09:34:43.000000000 +0200
+++ freeciv/common/tech.c       2004-07-24 09:40:33.000000000 +0200
@@ -289,6 +289,19 @@
 }
 
 /**************************************************************************
+Does a linear search of advances[].name_orig
+Returns A_LAST if none match.
+**************************************************************************/
+Tech_Type_id find_tech_by_name_orig(const char *s)
+{
+  tech_type_iterate(i) {
+    if (mystrcasecmp(advances[i].name_orig, s)==0)
+      return i;
+  } tech_type_iterate_end;
+  return A_LAST;
+}
+
+/**************************************************************************
  Return TRUE if the tech has this flag otherwise FALSE
 **************************************************************************/
 bool tech_flag(Tech_Type_id tech, enum tech_flag_id flag)
diff -ur -Xdiff_ignore freeorig/common/tech.h freeciv/common/tech.h
--- freeorig/common/tech.h      2004-07-23 12:39:00.000000000 +0200
+++ freeciv/common/tech.h       2004-07-24 09:40:33.000000000 +0200
@@ -117,6 +117,7 @@
 bool tech_is_available(struct player *pplayer, Tech_Type_id id);
 bool tech_exists(Tech_Type_id id);
 Tech_Type_id find_tech_by_name(const char *s);
+Tech_Type_id find_tech_by_name_orig(const char *s);
 
 bool tech_flag(Tech_Type_id tech, enum tech_flag_id flag);
 enum tech_flag_id tech_flag_from_str(const char *s);
diff -ur -Xdiff_ignore freeorig/server/savegame.c freeciv/server/savegame.c
--- freeorig/server/savegame.c  2004-07-24 09:37:16.000000000 +0200
+++ freeciv/server/savegame.c   2004-07-24 11:28:56.795932840 +0200
@@ -176,7 +176,7 @@
 #define SAVEFILE_OPTIONS "startoptions spacerace2 rulesets" \
 " diplchance_percent worklists2 map_editor known32fix turn " \
 "attributes watchtower rulesetdir client_worklists orders " \
-"startunits turn_last_built improvement_order"
+"startunits turn_last_built improvement_order technology_order"
 
 static const char hex_chars[] = "0123456789abcdef";
 static const char terrain_chars[] = "adfghjm prstu";
@@ -644,6 +644,47 @@
   "Women's Suffrage",  "Coinage"
 };
 
+/* old (~1.14.1) techs order in civ2/default ruleset.
+ * Note that Theology is called Religion in civ1 ruleset.
+ * Nowadays we save A_FUTURE as "A_FUTURE", A_NONE as "A_NONE".
+ * A_UNSET as "A_UNSET"
+ * This used to be saved as 198 ,0 or -1, 0
+ */
+const char* old_default_techs[] = 
+{
+  "A_NONE",
+  "Advanced Flight",   "Alphabet",             "Amphibious Warfare",
+  "Astronomy",         "Atomic Theory",        "Automobile",
+  "Banking",           "Bridge Building",      "Bronze Working",
+  "Ceremonial Burial", "Chemistry",            "Chivalary",
+  "Code of Laws",      "Combined Arms",        "Combustion",
+  "Communism",         "Computers",            "Conscription",
+  "Construction",      "Currency",             "Democracy",
+  "Economics",         "Electricity",          "Electronics",
+  "Engineering",       "Environmentalism",     "Espionage",
+  "Explosives",                "Feudalism",            "Flight",
+  "Fundamentalism",    "Fusion Power",         "Genetic Engineering",
+  "Guerilla Warfare",  "Gunpowder",            "Horseback Riding",
+  "Industrialization", "Invention",            "Iron Working",
+  "Labor Union",       "Laser",                "Leadership",
+  "Literacy",          "Machine Tools",        "Magnetism",
+  "Map Making",                "Masonry",              "Mass Production",
+  "Mathematics",       "Medicine",             "Metallurgy",
+  "Miniaturization",   "Mobile Warfare",       "Monarchy",
+  "Monotheism",                "Mysticism",            "Navigation",
+  "Nuclear Fission",   "Nuclear Power",        "Philosophy",
+  "Physics",           "Plastics",             "Polytheism",
+  "Pottery",           "Radio",                "Railroad",
+  "Recycling",         "Refining",             "Refrigeration",
+  "Robotics",          "Rocketry",             "Sanitation",
+  "Seafaring",         "Space Flight",         "Stealth",
+  "Steam Engine",      "Steel",                "Superconductors",
+  "Tactics",           "The Corporation",      "The Republic",
+  "The Wheel",         "Theology",             "Theory of Gravity"
+  "Trade",             "University",           "Warrior Code",
+  "Writing"
+};
+
 /****************************************************************************
   Nowadays unit types are saved by name, but old servers need the
   unit_type_id.  This function tries to find the correct _old_ id for the
@@ -668,7 +709,7 @@
     }
   }
 
-  /* It's a new unit. Savegame cannot be backward compatible so we can
+  /* It's a new unit. Savegame cannot be forward compatible so we can
    * return anything */
   return type;
 }
@@ -714,7 +755,7 @@
     }
   }
 
-  /* It's a new improvement. Savegame cannot be backward compatible so we can
+  /* It's a new improvement. Savegame cannot be forward compatible so we can
    * return anything */
   return type;
 }
@@ -767,6 +808,183 @@
   bitvector[old_id] = '1';
 }
 
+/****************************************************************************
+  Nowadays techs are saved by name, but old servers need numbers
+  This function tries to find the correct _old_ id for the
+  technology. It is used when the technology is saved.
+****************************************************************************/
+static int old_tech_id(Tech_Type_id tech)
+{
+  const char* technology_name;
+  int i;
+  
+  if (is_future_tech(tech)) {
+    return 198;
+  }
+  
+  if (tech == A_UNSET) {
+    return 199;
+  }
+  
+  technology_name = advances[tech].name_orig;
+  
+  /* this is the only place where civ1 was different from 1.14.1 defaults */
+  if (strcmp(game.rulesetdir, "civ1") == 0 && 
+      mystrcasecmp(technology_name, "Religion") == 0) {
+    return 83;
+  }
+  
+  for (i = 0; i < ARRAY_SIZE(old_default_techs); i++) {
+    if (mystrcasecmp(technology_name, old_default_techs[i]) == 0) {
+      return i;
+    }
+  }
+  
+  /* It's a new technology. Savegame cannot be forward compatible so we can
+   * return anything */
+  return tech;
+}
+
+/****************************************************************************
+  Convert an old-style technology id into a tech name.
+****************************************************************************/
+static const char* old_tech_name(int id)
+{
+  /* This was 1.14.1 value for A_FUTURE */
+  if (id == 198) {
+    return "A_FUTURE";
+  }
+  
+  if (id == -1 || id == 0) {
+    return "A_NONE";
+  }
+  
+  if (id == A_UNSET) {
+    return "A_UNSET";
+  }
+
+  if (id < 0 || id >= ARRAY_SIZE(old_default_techs)) {
+    freelog(LOG_ERROR, _("Wrong improvement type id value (%d)"), id);
+    exit(EXIT_FAILURE);
+  }
+
+  if (strcmp(game.rulesetdir, "civ1") == 0 && id == 83) {
+    return "Religion";
+  }
+  
+  return old_default_techs[id];
+}
+
+/****************************************************************************
+  Initialize the old-style technology bitvector so that all advances
+  are marked as not present.
+****************************************************************************/
+static void init_old_technology_bitvector(char* bitvector)
+{
+  int i;
+
+  for (i = 0; i < ARRAY_SIZE(old_default_techs); i++) {
+    bitvector[i] = '0';
+  }
+  bitvector[ARRAY_SIZE(old_default_techs)] = '\0';
+}
+
+/****************************************************************************
+  Insert technology into old-style bitvector
+
+  New bitvectors do not depend on ruleset order. However, we want to create
+  savegames which can be read by 1.14.x and earlier servers. 
+  This function adds a technology into the bitvector string according
+  to the 1.14.1 technology ordering.
+****************************************************************************/
+static void add_technology_into_old_bitvector(char* bitvector,
+                                              Tech_Type_id id)
+{
+  int old_id;
+
+  old_id = old_tech_id(id);
+  if (old_id < 0 || old_id >= ARRAY_SIZE(old_default_techs)) {
+    return;
+  }
+  bitvector[old_id] = '1';
+}
+
+
+/*****************************************************************************
+  Load technology from path_name and if doesn't exist (because savegame
+  is too old) load from path.
+*****************************************************************************/
+static Tech_Type_id load_technology(struct section_file *file,
+                                    const char* path, int plrno)
+{
+  char path_with_name[128];
+  const char* name;
+  int id;
+  
+  my_snprintf(path_with_name, sizeof(path_with_name), 
+              "%s_name", path);
+             
+  name = secfile_lookup_str_default(file, NULL, path_with_name, plrno);
+  if (!name) {
+    id = secfile_lookup_int_default(file, -1, path, plrno);
+    name = old_tech_name(id);
+  }
+  
+  if (mystrcasecmp(name, "A_FUTURE") == 0) {
+    return A_FUTURE;
+  }
+  if (mystrcasecmp(name, "A_NONE") == 0) {
+    return A_NONE;
+  }
+  if (mystrcasecmp(name, "A_UNSET") == 0) {
+    return A_UNSET;
+  }
+  if (name[0] == '\0') {
+    /* it is used by changed_from */
+    return -1;
+  }
+  
+  id = find_tech_by_name_orig(name);
+  if (id == A_LAST) {
+    freelog(LOG_ERROR, _("Unknown technology (%s)"), name);
+    exit(EXIT_FAILURE);    
+  }
+  return id;
+}
+
+/*****************************************************************************
+  Save technology in secfile entry called path_name and for forward
+  compatibility in path(by number).
+*****************************************************************************/
+static void save_technology(struct section_file *file,
+                            const char* path, int plrno, Tech_Type_id tech)
+{
+  char path_with_name[128];
+  const char* name;
+ 
+  my_snprintf(path_with_name, sizeof(path_with_name), 
+              "%s_name", path);
+  
+  switch (tech) {
+    case -1: /* used in changed_from */
+       name = "";
+       break;
+    case A_NONE:
+       name = "A_NONE";
+       break;
+    case A_UNSET:
+       name = "A_UNSET";
+       break;
+    case A_FUTURE:
+       name = "A_FUTURE";
+       break;
+    default:
+       name = advances[tech].name_orig;
+  }
+  secfile_insert_str(file, name, path_with_name, plrno);
+  secfile_insert_int(file, old_tech_id(tech), path, plrno);
+}
+
 /***************************************************************
 Load the worklist elements specified by path, given the arguments
 plrno and wlinx, into the worklist pointed to by pwl.
@@ -1098,12 +1316,16 @@
 static void player_load(struct player *plr, int plrno,
                        struct section_file *file,
                        char** improvement_order,
-                       int improvement_order_size)
+                       int improvement_order_size,
+                       char** technology_order,
+                       int technology_order_size)
 {
-  int i, j, x, y, ncities, c_s;
+  int i, j, k, x, y, ncities, c_s;
   const char *p;
+  const char *name;
   char *savefile_options = secfile_lookup_str(file, "savefile.options");
   struct ai_data *ai;
+  Tech_Type_id id;
 
   server_player_init(plr, TRUE);
   ai_data_init(plr);
@@ -1211,13 +1433,9 @@
     ai->diplomacy.player_intel[i].asked_about_ceasefire
          = secfile_lookup_int_default(file, 0, "player%d.ai.ask_ceasefire%d", 
plrno, i);
   }
-  plr->ai.tech_goal = secfile_lookup_int(file, "player%d.ai.tech_goal", plrno);
-  if (plr->ai.tech_goal == A_NONE
-      || !tech_exists(plr->ai.tech_goal)) {
-    /* The value of A_UNSET could change in the future, since it
-     * is not ruleset-dependent.  And it used to be A_NONE, so we check for
-     * that as well.  This is a hack since there's no way to distinguish
-     * from A_FUTURE (which shouldn't ever be here anyway). */
+  plr->ai.tech_goal = load_technology(file, "player%d.ai.tech_goal", plrno);
+  if (plr->ai.tech_goal == A_NONE) {
+    /* old servers (1.14.1) had A_UNSET = A_NONE */
     plr->ai.tech_goal = A_UNSET;
   }
   /* Some sane defaults */
@@ -1241,7 +1459,8 @@
   plr->economic.science=secfile_lookup_int(file, "player%d.science", plrno);
   plr->economic.luxury=secfile_lookup_int(file, "player%d.luxury", plrno);
 
-  plr->future_tech=secfile_lookup_int(file, "player%d.futuretech", plrno);
+  /* how many future techs were researched already by player */
+  plr->future_tech = secfile_lookup_int(file, "player%d.futuretech", plrno);
 
   /* We use default values for bulbs_researched_before, changed_from
    * and got_tech to preserve backwards-compatability with save files
@@ -1251,27 +1470,43 @@
   plr->research.bulbs_researched_before =
          secfile_lookup_int_default(file, 0,
                                     "player%d.researched_before", plrno);
-  plr->research.changed_from =
-         secfile_lookup_int_default(file, -1,
-                                    "player%d.research_changed_from",
-                                    plrno);
+  plr->research.changed_from = 
+          load_technology(file, "player%d.research_changed_from", plrno);
   plr->got_tech = secfile_lookup_bool_default(file, FALSE,
                                              "player%d.research_got_tech",
                                              plrno);
   plr->research.techs_researched=secfile_lookup_int(file, 
                                             "player%d.researchpoints", plrno);
-  plr->research.researching=secfile_lookup_int(file, 
-                                            "player%d.researching", plrno);
-  if (plr->research.researching == A_NONE
-      || !tech_exists(plr->research.researching)) {
-    /* The value of A_FUTURE could change in the future, since it
-     * is not ruleset-dependent.  And it used to be A_NONE, so we check for
-     * that as well.  This is a hack since there's no way to distinguish
-     * from A_UNSET (which shouldn't ever be here anyway). */
+  plr->research.researching = 
+       load_technology(file, "player%d.researching", plrno);
+  if (plr->research.researching == A_NONE) {
+    /* old servers (1.14.1) used to save A_FUTURE by 0 */
     plr->research.researching = A_FUTURE;
   }
-
-  p=secfile_lookup_str(file, "player%d.invs", plrno);
+  
+  p = secfile_lookup_str(file, "player%d.invs_new", plrno);
+  if (!p) {
+    /* old savegames */
+    p = secfile_lookup_str(file, "player%d.invs", plrno);
+    for (k = 0; p[k];  k++) {
+      if (p[k] == '1') {
+        name = old_tech_name(k);
+       id = find_tech_by_name_orig(name);
+       if (id != A_LAST) {
+         set_invention(plr, id, TECH_KNOWN);
+       }
+      }
+    }
+  } else {
+    for (k = 0; k < technology_order_size && p[k]; k++) {
+      if (p[k] == '1') {
+        id = find_tech_by_name_orig(technology_order[k]);
+       if (id != A_LAST) {
+         set_invention(plr, id, TECH_KNOWN);
+       }
+      }
+    }
+  }
     
   plr->capital=secfile_lookup_bool(file, "player%d.capital", plrno);
   plr->revolution=secfile_lookup_int_default(file, 0, "player%d.revolution",
@@ -1858,7 +2093,7 @@
   secfile_insert_int(file, plr->government, "player%d.government", plrno);
   secfile_insert_int(file, plr->embassy, "player%d.embassy", plrno);
 
-  /* This field won't be used, kept only for backward compatibility. 
+  /* This field won't be used, kept only for forward compatibility. 
    * City styles are specified by name since CVS 12/01-04. */
   secfile_insert_int(file, 0, "player%d.city_style", plrno);
 
@@ -1885,7 +2120,7 @@
     secfile_insert_int(file, 
ai->diplomacy.player_intel[i].asked_about_ceasefire, 
                        "player%d.ai.ask_ceasefire%d", plrno, i);
   }
-  secfile_insert_int(file, plr->ai.tech_goal, "player%d.ai.tech_goal", plrno);
+  save_technology(file, "player%d.ai.tech_goal", plrno, plr->ai.tech_goal);
   secfile_insert_int(file, plr->ai.skill_level,
                     "player%d.ai.skill_level", plrno);
   secfile_insert_int(file, plr->ai.barbarian_type, "player%d.ai.is_barbarian", 
plrno);
@@ -1902,21 +2137,33 @@
                     "player%d.researched_before", plrno);
   secfile_insert_bool(file, plr->got_tech,
                      "player%d.research_got_tech", plrno);
-  secfile_insert_int(file, plr->research.changed_from,
-                    "player%d.research_changed_from", plrno);
+  save_technology(file, "player%d.research_changed_from", plrno, 
+                  plr->research.changed_from);
   secfile_insert_int(file, plr->research.techs_researched,
                     "player%d.researchpoints", plrno);
-  secfile_insert_int(file, plr->research.researching,
-                    "player%d.researching", plrno);  
+  save_technology(file, "player%d.researching", plrno,
+                  plr->research.researching);  
 
   secfile_insert_bool(file, plr->capital, "player%d.capital", plrno);
   secfile_insert_int(file, plr->revolution, "player%d.revolution", plrno);
 
+  /* 1.14 servers depend on technology order in ruleset. Here we are trying
+   * to simulate 1.14.1 default order */
+  init_old_technology_bitvector(invs);
+  tech_type_iterate(tech_id) {
+    if (get_invention(plr, tech_id) == TECH_KNOWN) {
+      add_technology_into_old_bitvector(invs, tech_id);
+    }
+  } tech_type_iterate_end;
+  secfile_insert_str(file, invs, "player%d.invs", plrno);
+  
+  /* Save technology lists as bitvector. Note that technology order is 
+   * saved in savefile.technology_order */
   tech_type_iterate(tech_id) {
     invs[tech_id] = (get_invention(plr, tech_id) == TECH_KNOWN) ? '1' : '0';
   } tech_type_iterate_end;
   invs[game.num_tech_types] = '\0';
-  secfile_insert_str(file, invs, "player%d.invs", plrno);
+  secfile_insert_str(file, invs, "player%d.invs_new", plrno);
 
   secfile_insert_int(file, plr->reputation, "player%d.reputation", plrno);
   for (i = 0; i < MAX_NUM_PLAYERS+MAX_NUM_BARBARIANS; i++) {
@@ -1987,7 +2234,7 @@
     secfile_insert_int(file, punit->hp, "player%d.u%d.hp", plrno, i);
     secfile_insert_int(file, punit->homecity, "player%d.u%d.homecity",
                                plrno, i);
-    /* .type is actually kept only for backward compatibility */
+    /* .type is actually kept only for forward compatibility */
     secfile_insert_int(file, old_unit_type_id(punit->type), 
"player%d.u%d.type",
                       plrno, i);
     secfile_insert_str(file, unit_name_orig(punit->type),
@@ -2411,6 +2658,8 @@
   const char *string;
   char** improvement_order = NULL;
   int improvement_order_size = 0;
+  char** technology_order = NULL;
+  int technology_order_size = 0;
   const char* name;
 
   game.version = secfile_lookup_int_default(file, 0, "game.version");
@@ -2422,6 +2671,10 @@
     improvement_order = secfile_lookup_str_vec(file, &improvement_order_size,
                                                "savefile.improvement_order");
   }
+  if (has_capability("technology_order", savefile_options)) {
+    technology_order = secfile_lookup_str_vec(file, &technology_order_size,
+                                              "savefile.technology_order");
+  }
 
   /* we require at least version 1.9.0 */
   if (10900 > game.version) {
@@ -2791,7 +3044,8 @@
 
     for (i = 0; i < game.nplayers; i++) {
       player_load(&game.players[i], i, file, improvement_order,
-                  improvement_order_size); 
+                  improvement_order_size, technology_order,
+                 technology_order_size); 
     }
 
     cities_iterate(pcity) {
@@ -2942,6 +3196,24 @@
     secfile_insert_str_vec(file, buf, game.num_impr_types,
                            "savefile.improvement_order");
   }
+  
+  /* Save technology order in savegame, so we are not dependent on ruleset
+   * order. If the game isn't started advances aren't loaded 
+   * so we can not save the order/
+   */
+  if (game.num_tech_types > 0) {
+    const char* buf[game.num_tech_types];
+    tech_type_iterate(tech) {
+      if (tech == A_NONE) {
+        buf[tech] = "A_NONE";
+      } else {
+        buf[tech] = advances[tech].name_orig;
+      }
+    } tech_type_iterate_end;
+    secfile_insert_str_vec(file, buf, game.num_tech_types,
+                           "savefile.technology_order");
+  }
+  
   secfile_insert_int(file, game.gold, "game.gold");
   secfile_insert_int(file, game.tech, "game.tech");
   secfile_insert_int(file, game.skill_level, "game.skill_level");
Tylko w freeciv/server: x



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