Freeciv21
Develop your civilization from humble roots to a global empire
savecompat.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2020 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 
14 // utility
15 #include "capability.h"
16 #include "fcintl.h"
17 #include "log.h"
18 #include "registry_ini.h"
19 
20 // common
21 #include "map.h"
22 #include "specialist.h"
23 
24 // server
25 #include "aiiface.h"
26 #include "unittools.h"
27 
28 #include "savecompat.h"
29 
31 
32 static const char *special_names[] = {"Irrigation", "Mine", "Pollution",
33  "Hut", "Farmland", "Fallout",
34  nullptr};
35 
36 /*
37  For each savefile format after 2.3.0, compatibility functions are defined
38  which translate secfile structures from previous version to that version;
39  all necessary compat functions are called in order to
40  translate between the file and current version. See sg_load_compat().
41 
42  The integer version ID should be increased every time the format is
43  changed. If the change is not backwards compatible, please state the
44  changes in the following list and update the compat functions at the end of
45  this file.
46 
47  - what was added / removed
48  - when was it added / removed (date and version)
49  - when can additional capability checks be set to mandatory (version)
50  - which compatibility checks are needed and till when (version)
51 
52  freeciv | what | date | id
53  --------+------------------------------------------------+------------+----
54  current | (mapped to current savegame format) | ----/--/-- | 0
55  | first version (svn17538) | 2010/07/05 | -
56  2.3.0 | 2.3.0 release | 2010/11/?? | 3
57  2.4.0 | 2.4.0 release | 201./../.. | 10
58  | * player ai type | |
59  | * delegation | |
60  | * citizens | |
61  | * save player color | |
62  | * "known" info format change | |
63  2.5.0 | 2.5.0 release | 201./../.. | 20
64  2.6.0 | 2.6.0 release | 201./../.. | 30
65  3.0.0 | 3.0.0 release | 201./../.. | 40
66  3.1.0 | 3.0.0 release (development) | 201./../.. | 50
67  | | |
68 */
69 
70 static void compat_load_020400(struct loaddata *loading,
71  enum sgf_version format_class);
72 static void compat_load_020500(struct loaddata *loading,
73  enum sgf_version format_class);
74 static void compat_load_020600(struct loaddata *loading,
75  enum sgf_version format_class);
76 static void compat_load_030000(struct loaddata *loading,
77  enum sgf_version format_class);
78 static void compat_load_030100(struct loaddata *loading,
79  enum sgf_version format_class);
80 static void compat_post_load_030100(struct loaddata *loading,
81  enum sgf_version format_class);
82 
83 #ifdef FREECIV_DEV_SAVE_COMPAT
84 static void compat_load_dev(struct loaddata *loading);
85 static void compat_post_load_dev(struct loaddata *loading);
86 #endif // FREECIV_DEV_SAVE_COMPAT
87 
88 typedef void (*load_version_func_t)(struct loaddata *loading,
89  enum sgf_version format_class);
90 
91 struct compatibility {
92  int version;
95 };
96 
97 /* The struct below contains the information about the savegame versions. It
98  * is identified by the version number (first element), which should be
99  * steadily increasing. It is saved as 'savefile.version'. The support
100  * string (first element of 'name') is not saved in the savegame; it is
101  * saved in settings files (so, once assigned, cannot be changed). The
102  * 'pretty' string (second element of 'name') can be changed if necessary
103  * For changes in the development version, edit the definitions above and
104  * add the needed code to load the old version below. Thus, old
105  * savegames can still be loaded while the main definition
106  * represents the current state of the art. */
107 /* While developing freeciv 3.1.0, add the compatibility functions to
108  * - compat_load_030100 to load old savegame. */
109 static struct compatibility compat[] = {
110  // dummy; equal to the current version (last element)
111  {0, nullptr, nullptr},
112  // version 1 and 2 is not used
113  /* version 3: first savegame2 format, so no compat functions for
114  * translation from previous format */
115  {3, nullptr, nullptr},
116  // version 4 to 9 are reserved for possible changes in 2.3.x
117  {10, compat_load_020400, nullptr},
118  // version 11 to 19 are reserved for possible changes in 2.4.x
119  {20, compat_load_020500, nullptr},
120  // version 21 to 29 are reserved for possible changes in 2.5.x
121  {30, compat_load_020600, nullptr},
122  // version 31 to 39 are reserved for possible changes in 2.6.x
123  {40, compat_load_030000, nullptr},
124  // version 41 to 49 are reserved for possible changes in 3.0.x
126  /* Current savefile version is listed above this line; it corresponds to
127  the definitions in this file. */
128 };
129 
130 static const int compat_num = ARRAY_SIZE(compat);
131 #define compat_current (compat_num - 1)
132 
140 void sg_load_compat(struct loaddata *loading, enum sgf_version format_class)
141 {
142  int i;
143 
144  // Check status and return if not OK (sg_success != TRUE).
145  sg_check_ret();
146 
147  loading->version =
148  secfile_lookup_int_default(loading->file, -1, "savefile.version");
149 #ifdef FREECIV_DEBUG
150  sg_failure_ret(0 < loading->version,
151  "Invalid savefile format version (%d).", loading->version);
152  if (loading->version > compat[compat_current].version) {
153  // Debug build can (TRY TO!) load newer versions but ...
154  qCritical("Savegame version newer than this build found (%d > %d). "
155  "Trying to load the game nevertheless ...",
156  loading->version, compat[compat_current].version);
157  }
158 #else // FREECIV_DEBUG
159  sg_failure_ret(0 < loading->version
160  && loading->version <= compat[compat_current].version,
161  "Unknown savefile format version (%d).", loading->version);
162 #endif // FREECIV_DEBUG
163 
164  for (i = 0; i < compat_num; i++) {
165  if (loading->version < compat[i].version && compat[i].load != nullptr) {
166  qInfo(_("Run compatibility function for version: <%d "
167  "(save file: %d; server: %d)."),
168  compat[i].version, loading->version,
170  compat[i].load(loading, format_class);
171  }
172  }
173 
174 #ifdef FREECIV_DEV_SAVE_COMPAT
175  if (loading->version == compat[compat_current].version) {
176  compat_load_dev(loading);
177  }
178 #endif // FREECIV_DEV_SAVE_COMPAT
179 }
180 
191 void sg_load_post_load_compat(struct loaddata *loading,
192  enum sgf_version format_class)
193 {
194  int i;
195 
196  // Check status and return if not OK (sg_success != TRUE).
197  sg_check_ret();
198 
199  for (i = 0; i < compat_num; i++) {
200  if (loading->version < compat[i].version
201  && compat[i].post_load != nullptr) {
202  qInfo(_("Run post load compatibility function for version: <%d "
203  "(save file: %d; server: %d)."),
204  compat[i].version, loading->version,
206  compat[i].post_load(loading, format_class);
207  }
208  }
209 
210 #ifdef FREECIV_DEV_SAVE_COMPAT
211  if (loading->version == compat[compat_current].version) {
212  compat_post_load_dev(loading);
213  }
214 #endif // FREECIV_DEV_SAVE_COMPAT
215 }
216 
221 
227 char bin2ascii_hex(int value, int halfbyte_wanted)
228 {
229  return hex_chars[((value) >> ((halfbyte_wanted) *4)) & 0xf];
230 }
231 
239 int ascii_hex2bin(char ch, int halfbyte)
240 {
241  const char *pch;
242 
243  if (ch == ' ') {
244  /* Sane value. It is unknow if there are savegames out there which
245  * need this fix. Savegame.c doesn't write such savegames
246  * (anymore) since the inclusion into CVS (2000-08-25). */
247  return 0;
248  }
249 
250  pch = strchr(hex_chars, ch);
251 
252  sg_failure_ret_val(nullptr != pch && '\0' != ch, 0,
253  "Unknown hex value: '%c' %d", ch, ch);
254  return (pch - hex_chars) << (halfbyte * 4);
255 }
256 
257 static const char num_chars[] =
258  "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-+";
259 
264 int char2num(char ch)
265 {
266  const char *pch;
267 
268  pch = strchr(num_chars, ch);
269 
270  sg_failure_ret_val(nullptr != pch, 0,
271  "Unknown ascii value for num: '%c' %d", ch, ch);
272 
273  return pch - num_chars;
274 }
275 
280 {
281  int i;
282 
283  for (i = 0; special_names[i] != nullptr; i++) {
284  if (!strcmp(name, special_names[i])) {
285  return static_cast<tile_special_type>(i);
286  }
287  }
288 
289  return S_LAST;
290 }
291 
295 const char *special_rule_name(enum tile_special_type type)
296 {
297  fc_assert(type >= 0 && type < S_LAST);
298 
299  return special_names[type];
300 }
301 
306 {
307  struct extra_type_list *elist =
308  extra_type_list_by_cause(static_cast<extra_cause>(EC_SPECIAL));
309 
310  if (spe < extra_type_list_size(elist)) {
311  return extra_type_list_get(elist, spe);
312  }
313 
314  return nullptr;
315 }
316 
321 struct extra_type *resource_by_identifier(const char identifier)
322 {
323  extra_type_by_cause_iterate(EC_RESOURCE, presource)
324  {
325  if (presource->data.resource->id_old_save == identifier) {
326  return presource;
327  }
328  }
330 
331  return nullptr;
332 }
333 
334 /* =======================================================================
335  * Compatibility functions for loading a game.
336  * ======================================================================= */
337 
341 static void compat_load_020400(struct loaddata *loading,
342  enum sgf_version format_class)
343 {
344  // Check status and return if not OK (sg_success != TRUE).
345  sg_check_ret();
346 
347  log_debug("Upgrading data from savegame to version 2.4.0");
348 
349  // Add the default player AI.
350  player_slots_iterate(pslot)
351  {
352  int ncities, i, plrno = player_slot_index(pslot);
353 
354  if (nullptr
355  == secfile_section_lookup(loading->file, "player%d", plrno)) {
356  continue;
357  }
358 
360  "player%d.ai_type", player_slot_index(pslot));
361 
362  /* Create dummy citizens informations. We do not know if citizens are
363  * activated due to the fact that this information
364  * (game.info.citizen_nationality) is not available, but adding the
365  * information does no harm. */
366  ncities = secfile_lookup_int_default(loading->file, 0,
367  "player%d.ncities", plrno);
368  if (ncities > 0) {
369  for (i = 0; i < ncities; i++) {
370  int size = secfile_lookup_int_default(loading->file, 0,
371  "player%d.c%d.size", plrno, i);
372  if (size > 0) {
373  secfile_insert_int(loading->file, size, "player%d.c%d.citizen%d",
374  plrno, i, plrno);
375  }
376  }
377  }
378  }
380 
381  /* Player colors are assigned at the end of player loading, as this
382  * needs information not available here. */
383 
384  /* Deal with buggy known tiles information from 2.3.0/2.3.1 (and the
385  * workaround in later 2.3.x); see gna bug #19029.
386  * (The structure of this code is odd as it avoids relying on knowledge of
387  * xsize/ysize, which haven't been extracted from the savefile yet.) */
388  {
389  if (has_capability("knownv2", secfile_lookup_str(loading->file,
390  "savefile.options"))) {
391  /* This savefile contains known information in a sane format.
392  * Just move any entries to where 2.4.x+ expect to find them. */
393  struct section *map = secfile_section_by_name(loading->file, "map");
394  if (map) {
395  entry_list_iterate(section_entries(map), pentry)
396  {
397  const char *name = entry_name(pentry);
398  if (strncmp(name, "kvb", 3) == 0) {
399  // Rename the "kvb..." entry to "k..."
400  char *name2 = fc_strdup(name), *newname = name2 + 2;
401  *newname = 'k';
402  /* Savefile probably contains existing "k" entries, which are
403  * bogus so we trash them */
404  secfile_entry_delete(loading->file, "map.%s", newname);
405  entry_set_name(pentry, newname);
406  delete[] name2;
407  name2 = nullptr;
408  }
409  }
411  }
412  /* Could remove "knownv2" from savefile.options, but it's doing
413  * no harm there. */
414  } else {
415  /* This savefile only contains known information in the broken
416  * format. Try to recover it to a sane format. */
417  // MAX_NUM_PLAYER_SLOTS in 2.3.x was 128
418  // MAP_MAX_LINEAR_SIZE in 2.3.x was 512
419  const int maxslots = 128, maxmapsize = 512;
420  const int lines = maxslots / 32;
421  int xsize = 0, y, l, j, x;
422  unsigned int known_row_old[lines * maxmapsize],
423  known_row[lines * maxmapsize];
424  // Process a map row at a time
425  for (y = 0; y < maxmapsize; y++) {
426  // Look for broken info to convert
427  bool found = false;
428  memset(known_row_old, 0, sizeof(known_row_old));
429  for (l = 0; l < lines; l++) {
430  for (j = 0; j < 8; j++) {
431  const char *s = secfile_lookup_str_default(
432  loading->file, nullptr, "map.k%02d_%04d", l * 8 + j, y);
433  if (s) {
434  found = true;
435  if (xsize == 0) {
436  xsize = qstrlen(s);
437  }
438  sg_failure_ret(xsize == qstrlen(s),
439  "Inconsistent xsize in map.k%02d_%04d",
440  l * 8 + j, y);
441  for (x = 0; x < xsize; x++) {
442  known_row_old[l * xsize + x] |= ascii_hex2bin(s[x], j);
443  }
444  }
445  }
446  }
447  if (found) {
448  /* At least one entry found for this row. Let's hope they were
449  * all there. */
450  // Attempt to munge into sane format
451  int p;
452  memset(known_row, 0, sizeof(known_row));
453  // Iterate over possible player slots
454  for (p = 0; p < maxslots; p++) {
455  l = p / 32;
456  for (x = 0; x < xsize; x++) {
457  /* This test causes bit-shifts of >=32 (undefined behaviour),
458  * but on common platforms, information happens not to be lost,
459  * just oddly arranged. */
460  if (known_row_old[l * xsize + x] & (1u << (p - l * 8))) {
461  known_row[l * xsize + x] |= (1u << (p - l * 32));
462  }
463  }
464  }
465  /* Save sane format back to memory representation of secfile for
466  * real loading code to pick up */
467  for (l = 0; l < lines; l++) {
468  for (j = 0; j < 8; j++) {
469  /* Save info for all slots (not just used ones). It's only
470  * memory, after all. */
471  char row[xsize + 1];
472  for (x = 0; x < xsize; x++) {
473  row[x] = bin2ascii_hex(known_row[l * xsize + x], j);
474  }
475  row[xsize] = '\0';
476  secfile_replace_str(loading->file, row, "map.k%02d_%04d",
477  l * 8 + j, y);
478  }
479  }
480  }
481  }
482  }
483  }
484 
485  // Server setting migration.
486  {
487  int set_count;
488  if (secfile_lookup_int(loading->file, &set_count,
489  "settings.set_count")) {
490  int i, new_opt = set_count;
491  bool gamestart_valid = secfile_lookup_bool_default(
492  loading->file, false, "settings.gamestart_valid");
493  for (i = 0; i < set_count; i++) {
494  const char *name =
495  secfile_lookup_str(loading->file, "settings.set%d.name", i);
496  if (!name) {
497  continue;
498  }
499 
500  /* In 2.3.x and prior, saveturns=0 meant no turn-based saves.
501  * This is now controlled by the "autosaves" setting. */
502  if (!fc_strcasecmp("saveturns", name)) {
503  /* XXX: hardcodes details from GAME_AUTOSAVES_DEFAULT
504  * and settings.c:autosaves_name() (but these defaults reflect
505  * 2.3's behaviour). */
506  const char *const nosave = "GAMEOVER|QUITIDLE|INTERRUPT";
507  const char *const save = "TURN|GAMEOVER|QUITIDLE|INTERRUPT";
508  int nturns;
509 
510  if (secfile_lookup_int(loading->file, &nturns,
511  "settings.set%d.value", i)) {
512  if (nturns == 0) {
513  // Invent a new "autosaves" setting
514  secfile_insert_str(loading->file, nosave,
515  "settings.set%d.value", new_opt);
516  // Pick something valid for saveturns
518  "settings.set%d.value", i);
519  } else {
520  secfile_insert_str(loading->file, save, "settings.set%d.value",
521  new_opt);
522  }
523  } else {
524  log_sg("Setting '%s': %s", name, secfile_error());
525  }
526  if (gamestart_valid) {
527  if (secfile_lookup_int(loading->file, &nturns,
528  "settings.set%d.gamestart", i)) {
529  if (nturns == 0) {
530  // Invent a new "autosaves" setting
531  secfile_insert_str(loading->file, nosave,
532  "settings.set%d.gamestart", new_opt);
533  // Pick something valid for saveturns
535  "settings.set%d.gamestart", i);
536  } else {
537  secfile_insert_str(loading->file, save,
538  "settings.set%d.gamestart", new_opt);
539  }
540  } else {
541  log_sg("Setting '%s': %s", name, secfile_error());
542  }
543  }
544  } else if (!fc_strcasecmp("autosaves", name)) {
545  /* Sanity check. This won't trigger on an option we've just
546  * invented, as the loop won't include it. */
547  log_sg("Unexpected \"autosaves\" setting found in pre-2.4 "
548  "savefile. It may have been overridden.");
549  }
550  }
551  }
552  }
553 }
554 
558 static const char *killcitizen_enum_str(secfile_data_t data, int bit)
559 {
560  switch (bit) {
561  case UMT_LAND:
562  return "LAND";
563  case UMT_SEA:
564  return "SEA";
565  case UMT_BOTH:
566  return "BOTH";
567  }
568 
569  return nullptr;
570 }
571 
575 static void compat_load_020500(struct loaddata *loading,
576  enum sgf_version format_class)
577 {
578  const char *modname[] = {"Road", "Railroad"};
579  const char *old_activities_names[] = {
580  "Idle", "Pollution", "Unused Road",
581  "Mine", "Irrigate", "Mine",
582  "Irrigate", "Fortified", "Fortress",
583  "Sentry", "Unused Railroad", "Pillage",
584  "Goto", "Explore", "Transform",
585  "Unused", "Unused Airbase", "Fortifying",
586  "Fallout", "Unused Patrol", "Base"};
587 
588  // Check status and return if not OK (sg_success != TRUE).
589  sg_check_ret();
590 
591  log_debug("Upgrading data from savegame to version 2.5.0");
592 
593  secfile_insert_int(loading->file, 2, "savefile.roads_size");
594  secfile_insert_int(loading->file, 0, "savefile.trait_size");
595 
596  secfile_insert_str_vec(loading->file, modname, 2, "savefile.roads_vector");
597 
598  secfile_insert_int(loading->file, 19, "savefile.activities_size");
599  secfile_insert_str_vec(loading->file, old_activities_names, 19,
600  "savefile.activities_vector");
601 
602  // Server setting migration.
603  {
604  int set_count;
605 
606  if (secfile_lookup_int(loading->file, &set_count,
607  "settings.set_count")) {
608  int i;
609  bool gamestart_valid = secfile_lookup_bool_default(
610  loading->file, false, "settings.gamestart_valid");
611  for (i = 0; i < set_count; i++) {
612  const char *name =
613  secfile_lookup_str(loading->file, "settings.set%d.name", i);
614  if (!name) {
615  continue;
616  }
617  /* In 2.4.x and prior, "killcitizen" listed move types that
618  * killed citizens after succesfull attack. Now killcitizen
619  * is just boolean and classes affected are defined in ruleset. */
620  if (!fc_strcasecmp("killcitizen", name)) {
621  int value;
622 
623  if (secfile_lookup_enum_data(loading->file, &value, true,
624  killcitizen_enum_str, nullptr,
625  "settings.set%d.value", i)) {
626  /* Lowest bit of old killcitizen value indicates if
627  * land units should kill citizens. We take that as
628  * new boolean killcitizen value. */
629  if (value & 0x1) {
630  secfile_replace_bool(loading->file, true,
631  "settings.set%d.value", i);
632  } else {
633  secfile_replace_bool(loading->file, false,
634  "settings.set%d.value", i);
635  }
636  } else {
637  log_sg("Setting '%s': %s", name, secfile_error());
638  }
639  if (gamestart_valid) {
640  if (secfile_lookup_enum_data(loading->file, &value, true,
641  killcitizen_enum_str, nullptr,
642  "settings.set%d.gamestart", i)) {
643  /* Lowest bit of old killcitizen value indicates if
644  * land units should kill citizens. We take that as
645  * new boolean killcitizen value. */
646  if (value & 0x1) {
647  secfile_replace_bool(loading->file, true,
648  "settings.set%d.gamestart", i);
649  } else {
650  secfile_replace_bool(loading->file, false,
651  "settings.set%d.gamestart", i);
652  }
653  } else {
654  log_sg("Setting '%s': %s", name, secfile_error());
655  }
656  }
657  }
658  }
659  }
660  }
661 }
662 
666 static const char *revolentype_str(enum revolen_type type)
667 {
668  switch (type) {
669  case REVOLEN_FIXED:
670  return "FIXED";
671  case REVOLEN_RANDOM:
672  return "RANDOM";
673  case REVOLEN_QUICKENING:
674  return "QUICKENING";
675  case REVOLEN_RANDQUICK:
676  return "RANDQUICK";
677  }
678 
679  return "";
680 }
681 
685 static void compat_load_020600(struct loaddata *loading,
686  enum sgf_version format_class)
687 {
688  bool team_pooled_research = GAME_DEFAULT_TEAM_POOLED_RESEARCH;
689  int tsize;
690  int ti;
691  int turn;
692 
693  // Check status and return if not OK (sg_success != TRUE).
694  sg_check_ret();
695 
696  log_debug("Upgrading data from savegame to version 2.6.0");
697 
698  /* Terrain mapping table - use current ruleset as we have no way to know
699  * any other old values. */
700  ti = 0;
701  terrain_type_iterate(pterr)
702  {
703  char buf[2];
704 
705  secfile_insert_str(loading->file, terrain_rule_name(pterr),
706  "savefile.terrident%d.name", ti);
707  buf[0] = terrain_identifier(pterr);
708  buf[1] = '\0';
709  secfile_insert_str(loading->file, buf, "savefile.terrident%d.identifier",
710  ti++);
711  }
713 
714  // Server setting migration.
715  {
716  int set_count;
717 
718  if (secfile_lookup_int(loading->file, &set_count,
719  "settings.set_count")) {
720  char value_buffer[1024] = "";
721  char gamestart_buffer[1024] = "";
722  int i;
723  int dcost = -1;
724  int dstartcost = -1;
727  bool gamestart_valid = secfile_lookup_bool_default(
728  loading->file, false, "settings.gamestart_valid");
729  int new_set_count;
730 
731  for (i = 0; i < set_count; i++) {
732  const char *name =
733  secfile_lookup_str(loading->file, "settings.set%d.name", i);
734  if (!name) {
735  continue;
736  }
737 
738  /* In 2.5.x and prior, "spacerace" boolean controlled if
739  * spacerace victory condition was active. */
740  if (!fc_strcasecmp("spacerace", name)) {
741  bool value;
742 
743  if (secfile_lookup_bool(loading->file, &value,
744  "settings.set%d.value", i)) {
745  if (value) {
746  if (value_buffer[0] != '\0') {
747  sz_strlcat(value_buffer, "|");
748  }
749  sz_strlcat(value_buffer, "SPACERACE");
750  }
751  } else {
752  log_sg("Setting '%s': %s", name, secfile_error());
753  }
754  if (secfile_lookup_bool(loading->file, &value,
755  "settings.set%d.gamestart", i)) {
756  if (value) {
757  if (gamestart_buffer[0] != '\0') {
758  sz_strlcat(gamestart_buffer, "|");
759  }
760  sz_strlcat(gamestart_buffer, "SPACERACE");
761  }
762  } else {
763  log_sg("Setting '%s': %s", name, secfile_error());
764  }
765 
766  /* We cannot delete old values from the secfile, or rather cannot
767  * change index of the later settings. Renumbering them is not easy
768  * as we don't know type of each setting we would encounter.
769  * So we keep old setting values and only add new "victories"
770  * setting. */
771  } else if (!fc_strcasecmp("alliedvictory", name)) {
772  bool value;
773 
774  if (secfile_lookup_bool(loading->file, &value,
775  "settings.set%d.value", i)) {
776  if (value) {
777  if (value_buffer[0] != '\0') {
778  sz_strlcat(value_buffer, "|");
779  }
780  sz_strlcat(value_buffer, "ALLIED");
781  }
782  } else {
783  log_sg("Setting '%s': %s", name, secfile_error());
784  }
785  if (secfile_lookup_bool(loading->file, &value,
786  "settings.set%d.gamestart", i)) {
787  if (value) {
788  if (gamestart_buffer[0] != '\0') {
789  sz_strlcat(gamestart_buffer, "|");
790  }
791  sz_strlcat(gamestart_buffer, "ALLIED");
792  }
793  } else {
794  log_sg("Setting '%s': %s", name, secfile_error());
795  }
796  } else if (!fc_strcasecmp("revolen", name)) {
797  int value;
798 
799  if (secfile_lookup_int(loading->file, &value,
800  "settings.set%d.value", i)) {
801  // 0 meant RANDOM 1-5
802  if (value == 0) {
803  rlt = REVOLEN_RANDOM;
804  secfile_replace_int(loading->file, 5, "settings.set%d.value",
805  i);
806  } else {
807  rlt = REVOLEN_FIXED;
808  }
809  } else {
810  log_sg("Setting '%s': %s", name, secfile_error());
811  }
812  if (secfile_lookup_int(loading->file, &value,
813  "settings.set%d.gamestart", i)) {
814  // 0 meant RANDOM 1-5
815  if (value == 0) {
816  gsrlt = REVOLEN_RANDOM;
817  secfile_replace_int(loading->file, 5,
818  "settings.set%d.gamestart", i);
819  } else {
820  gsrlt = REVOLEN_FIXED;
821  }
822  } else {
823  log_sg("Setting '%s': %s", name, secfile_error());
824  }
825  } else if (!fc_strcasecmp("happyborders", name)) {
826  bool value;
827 
828  if (secfile_lookup_bool(loading->file, &value,
829  "settings.set%d.value", i)) {
830  secfile_entry_delete(loading->file, "settings.set%d.value", i);
831  if (value) {
832  secfile_insert_str(loading->file, "NATIONAL",
833  "settings.set%d.value", i);
834  } else {
835  secfile_insert_str(loading->file, "DISABLED",
836  "settings.set%d.value", i);
837  }
838  } else {
839  log_sg("Setting '%s': %s", name, secfile_error());
840  }
841  if (secfile_lookup_bool(loading->file, &value,
842  "settings.set%d.gamestart", i)) {
843  secfile_entry_delete(loading->file, "settings.set%d.gamestart",
844  i);
845  if (value) {
846  secfile_insert_str(loading->file, "NATIONAL",
847  "settings.set%d.gamestart", i);
848  } else {
849  secfile_insert_str(loading->file, "DISABLED",
850  "settings.set%d.gamestart", i);
851  }
852  } else {
853  log_sg("Setting '%s': %s", name, secfile_error());
854  }
855  } else if (!fc_strcasecmp("team_pooled_research", name)) {
856  sg_warn(secfile_lookup_bool(loading->file, &team_pooled_research,
857  "settings.set%d.value", i),
858  "%s", secfile_error());
859  } else if (!fc_strcasecmp("diplcost", name)) {
860  // Old 'diplcost' split to 'diplbulbcost' and 'diplgoldcost'
861  if (secfile_lookup_int(loading->file, &dcost,
862  "settings.set%d.value", i)) {
863  } else {
864  log_sg("Setting '%s': %s", name, secfile_error());
865  }
866 
867  if (secfile_lookup_int(loading->file, &dstartcost,
868  "settings.set%d.gamestart", i)) {
869  } else {
870  log_sg("Setting '%s': %s", name, secfile_error());
871  }
872  } else if (!fc_strcasecmp("huts", name)) {
873  // Scale of 'huts' changed.
874  int hcount;
875 
876  if (secfile_lookup_int(loading->file, &hcount,
877  "settings.set%d.value", i)) {
878  } else {
879  log_sg("Setting '%s': %s", name, secfile_error());
880  }
881 
882  // Store old-style absolute value.
883  wld.map.server.huts_absolute = hcount;
884  }
885  }
886 
887  new_set_count = set_count + 2; // 'victories' and 'revolentype'
888 
889  if (dcost >= 0) {
890  new_set_count += 2;
891  }
892 
893  secfile_replace_int(loading->file, new_set_count,
894  "settings.set_count");
895 
896  secfile_insert_str(loading->file, "victories", "settings.set%d.name",
897  set_count);
898  secfile_insert_str(loading->file, value_buffer, "settings.set%d.value",
899  set_count);
900  secfile_insert_str(loading->file, "revolentype", "settings.set%d.name",
901  set_count + 1);
902  secfile_insert_str(loading->file, revolentype_str(rlt),
903  "settings.set%d.value", set_count + 1);
904 
905  if (dcost >= 0) {
906  secfile_insert_str(loading->file, "diplbulbcost",
907  "settings.set%d.name", set_count + 2);
908  secfile_insert_int(loading->file, dcost, "settings.set%d.value",
909  set_count + 2);
910  secfile_insert_str(loading->file, "diplgoldcost",
911  "settings.set%d.name", set_count + 3);
912  secfile_insert_int(loading->file, dcost, "settings.set%d.value",
913  set_count + 3);
914  }
915 
916  if (gamestart_valid) {
917  secfile_insert_str(loading->file, gamestart_buffer,
918  "settings.set%d.gamestart", set_count);
919  secfile_insert_str(loading->file, revolentype_str(gsrlt),
920  "settings.set%d.gamestart", set_count + 1);
921 
922  if (dcost >= 0) {
923  secfile_insert_int(loading->file, dstartcost,
924  "settings.set%d.gamestart", set_count + 2);
925  secfile_insert_int(loading->file, dstartcost,
926  "settings.set%d.gamestart", set_count + 3);
927  }
928  }
929  }
930  }
931 
933  secfile_lookup_int(loading->file, &tsize, "savefile.trait_size"),
934  "Trait size: %s", secfile_error());
935 
936  turn = secfile_lookup_int_default(loading->file, 0, "game.turn");
937 
938  player_slots_iterate(pslot)
939  {
940  int plrno = player_slot_index(pslot);
941  bool got_first_city;
942  int old_barb_type;
943  enum barbarian_type new_barb_type;
944  int i;
945  const char *name;
946  int score;
947  int units_num;
948 
949  if (nullptr
950  == secfile_section_lookup(loading->file, "player%d", plrno)) {
951  continue;
952  }
953 
954  // Renamed 'capital' to 'got_first_city'.
955  if (secfile_lookup_bool(loading->file, &got_first_city,
956  "player%d.capital", plrno)) {
957  secfile_insert_bool(loading->file, got_first_city,
958  "player%d.got_first_city", plrno);
959  }
960 
961  // Add 'anonymous' qualifiers for user names
962  name = secfile_lookup_str_default(loading->file, "", "player%d.username",
963  plrno);
964  secfile_insert_bool(loading->file, (!strcmp(name, ANON_USER_NAME)),
965  "player%d.unassigned_user", plrno);
966 
967  name = secfile_lookup_str_default(loading->file, "",
968  "player%d.ranked_username", plrno);
969  secfile_insert_bool(loading->file, (!strcmp(name, ANON_USER_NAME)),
970  "player%d.unassigned_ranked", plrno);
971 
972  // Convert numeric barbarian type to textual
973  old_barb_type = secfile_lookup_int_default(
974  loading->file, 0, "player%d.ai.is_barbarian", plrno);
975  new_barb_type = barb_type_convert(old_barb_type);
976  secfile_insert_str(loading->file, barbarian_type_name(new_barb_type),
977  "player%d.ai.barb_type", plrno);
978 
979  /* Pre-2.6 didn't record when a player was created or died, so we have
980  * to assume they lived from the start of the game until last turn */
981  secfile_insert_int(loading->file, turn, "player%d.turns_alive", plrno);
982 
983  // As if there never has been a war.
984  secfile_insert_int(loading->file, -1, "player%d.last_war", plrno);
985 
986  // Assume people were playing until current reload
987  secfile_insert_int(loading->file, 0, "player%d.idle_turns", plrno);
988 
989  for (i = 0; i < tsize; i++) {
990  int val;
991 
992  val = secfile_lookup_int_default(loading->file, -1,
993  "player%d.trait.val%d", plrno, i);
994  if (val != -1) {
995  secfile_insert_int(loading->file, val, "player%d.trait%d.val", plrno,
996  i);
997  }
998 
999  sg_failure_ret(secfile_lookup_int(loading->file, &val,
1000  "player%d.trait.mod%d", plrno, i),
1001  "Trait mod: %s", secfile_error());
1002  secfile_insert_int(loading->file, val, "player%d.trait%d.mod", plrno,
1003  i);
1004  }
1005 
1006  score = secfile_lookup_int_default(loading->file, -1,
1007  "player%d.units_built", plrno);
1008  if (score >= 0) {
1009  secfile_insert_int(loading->file, score, "score%d.units_built", plrno);
1010  }
1011 
1012  score = secfile_lookup_int_default(loading->file, -1,
1013  "player%d.units_killed", plrno);
1014  if (score >= 0) {
1015  secfile_insert_int(loading->file, score, "score%d.units_killed",
1016  plrno);
1017  }
1018 
1019  score = secfile_lookup_int_default(loading->file, -1,
1020  "player%d.units_lost", plrno);
1021  if (score >= 0) {
1022  secfile_insert_int(loading->file, score, "score%d.units_lost", plrno);
1023  }
1024 
1025  // Units orders.
1026  units_num = secfile_lookup_int_default(loading->file, 0,
1027  "player%d.nunits", plrno);
1028 
1029  for (i = 0; i < units_num; i++) {
1030  int len;
1031 
1032  if (secfile_lookup_bool_default(loading->file, false,
1033  "player%d.u%d.orders_last_move_safe",
1034  plrno, i)) {
1035  continue;
1036  }
1037 
1039  loading->file, 0, "player%d.u%d.orders_length", plrno, i);
1040  if (len > 0) {
1041  char orders_str[len + 1];
1042  char *p;
1043 
1045  loading->file, "",
1046  "player%d.u%d.orders_list", plrno, i));
1047  if ((p = strrchr(orders_str, 'm'))
1048  || (p = strrchr(orders_str, 'M'))) {
1049  *p = 'x'; // ORDER_MOVE -> ORDER_ACTION_MOVE
1050  secfile_replace_str(loading->file, orders_str,
1051  "player%d.u%d.orders_list", plrno, i);
1052  }
1053  }
1054  }
1055  }
1057 
1058  /* Add specialist order - loading time order is ok here, as we will use
1059  * that when we in later part of compatibility conversion use the
1060  * specialist values */
1062  "savefile.specialists_size");
1063  {
1064  const char **modname;
1065  int i = 0;
1066 
1067  modname = new const char *[specialist_count()]();
1069  {
1070  modname[i++] = specialist_rule_name(specialist_by_number(sp));
1071  }
1073 
1074  secfile_insert_str_vec(loading->file, modname, specialist_count(),
1075  "savefile.specialists_vector");
1076 
1077  delete[] modname;
1078  }
1079 
1080  // Replace all city specialist count fields with correct names
1081  player_slots_iterate(pslot)
1082  {
1083  int plrno = player_slot_index(pslot);
1084  int ncities;
1085  int i;
1086 
1087  if (nullptr
1088  == secfile_section_lookup(loading->file, "player%d", plrno)) {
1089  continue;
1090  }
1091 
1092  ncities = secfile_lookup_int_default(loading->file, 0,
1093  "player%d.ncities", plrno);
1094 
1095  for (i = 0; i < ncities; i++) {
1096  int k = 0;
1097 
1099  {
1100  struct specialist *psp = specialist_by_number(sp);
1101  int count;
1102 
1103  sg_failure_ret(secfile_lookup_int(loading->file, &count,
1104  "player%d.c%d.n%s", plrno, i,
1105  specialist_rule_name(psp)),
1106  "specialist error: %s", secfile_error());
1107  secfile_entry_delete(loading->file, "player%d.c%d.n%s", plrno, i,
1108  specialist_rule_name(psp));
1109  secfile_insert_int(loading->file, count, "player%d.c%d.nspe%d",
1110  plrno, i, k++);
1111  }
1113  }
1114  }
1116 
1117  // Build [research].
1118  {
1119  const struct {
1120  const char *name;
1121  enum entry_type type;
1122  } entries[] = {{"goal_name", ENTRY_STR}, {"techs", ENTRY_INT},
1123  {"futuretech", ENTRY_INT}, {"bulbs_before", ENTRY_INT},
1124  {"saved_name", ENTRY_STR}, {"bulbs", ENTRY_INT},
1125  {"now_name", ENTRY_STR}, {"got_tech", ENTRY_BOOL},
1126  {"done", ENTRY_STR}};
1127 
1128  int researches[MAX(MAX_NUM_PLAYER_SLOTS, team_slot_count())];
1129  int count = 0;
1130  int i;
1131 
1132  for (i = 0; i < ARRAY_SIZE(researches); i++) {
1133  researches[i] = -1;
1134  }
1135 
1136  player_slots_iterate(pslot)
1137  {
1138  int plrno = player_slot_index(pslot);
1139  int ival;
1140  bool bval;
1141  const char *sval;
1142  int j;
1143 
1144  if (secfile_section_lookup(loading->file, "player%d", plrno)
1145  == nullptr) {
1146  continue;
1147  }
1148 
1149  // Get the research number.
1150  if (team_pooled_research) {
1151  i = secfile_lookup_int_default(loading->file, plrno,
1152  "player%d.team_no", plrno);
1153  } else {
1154  i = plrno;
1155  }
1156 
1157  sg_failure_ret(i >= 0 && i < ARRAY_SIZE(researches),
1158  "Research out of bounds (%d)!", i);
1159 
1160  // Find the index in [research] section.
1161  if (researches[i] == -1) {
1162  // This is the first player for this research.
1163  secfile_insert_int(loading->file, i, "research.r%d.number", count);
1164  researches[i] = count;
1165  count++;
1166  }
1167  i = researches[i];
1168 
1169  // Move entries.
1170  for (j = 0; j < ARRAY_SIZE(entries); j++) {
1171  switch (entries[j].type) {
1172  case ENTRY_BOOL:
1173  if (secfile_lookup_bool(loading->file, &bval,
1174  "player%d.research.%s", plrno,
1175  entries[j].name)) {
1176  secfile_insert_bool(loading->file, bval, "research.r%d.%s", i,
1177  entries[j].name);
1178  }
1179  break;
1180  case ENTRY_INT:
1181  if (secfile_lookup_int(loading->file, &ival,
1182  "player%d.research.%s", plrno,
1183  entries[j].name)) {
1184  secfile_insert_int(loading->file, ival, "research.r%d.%s", i,
1185  entries[j].name);
1186  }
1187  break;
1188  case ENTRY_STR:
1189  if ((sval =
1190  secfile_lookup_str(loading->file, "player%d.research.%s",
1191  plrno, entries[j].name))) {
1192  secfile_insert_str(loading->file, sval, "research.r%d.%s", i,
1193  entries[j].name);
1194  }
1195  break;
1196  case ENTRY_FLOAT:
1197  sg_failure_ret(entries[j].type != ENTRY_FLOAT,
1198  "Research related entry marked as float.");
1199  break;
1200  case ENTRY_FILEREFERENCE:
1201  fc_assert(entries[j].type != ENTRY_FILEREFERENCE);
1202  break;
1203  case ENTRY_ILLEGAL:
1204  fc_assert(entries[j].type != ENTRY_ILLEGAL);
1205  break;
1206  }
1207  }
1208  }
1210  secfile_insert_int(loading->file, count, "research.count");
1211  }
1212 
1213  // Add diplstate type order.
1214  secfile_insert_int(loading->file, DS_LAST, "savefile.diplstate_type_size");
1215  const char **modname;
1216  int i;
1217  int j;
1218  i = 0;
1219  modname = new const char *[DS_LAST]();
1220  for (j = 0; j < DS_LAST; j++) {
1221  modname[i++] = diplstate_type_name(static_cast<diplstate_type>(j));
1222  }
1223  secfile_insert_str_vec(loading->file, modname, DS_LAST,
1224  "savefile.diplstate_type_vector");
1225  delete[] modname;
1226 
1227  /* Fix save games from legacy freeciv versions with a bug that made it view
1228  * "Never met" as closer than "Peace" or "Alliance". */
1229  player_slots_iterate(pslot)
1230  {
1231  int plrno = player_slot_index(pslot);
1232 
1233  if (nullptr
1234  == secfile_section_lookup(loading->file, "player%d", plrno)) {
1235  continue;
1236  }
1237 
1238  player_slots_iterate(pslot2)
1239  {
1240  int i = player_slot_index(pslot2);
1241  char buf[32];
1242  int current;
1243  int closest;
1244 
1245  if (nullptr == secfile_section_lookup(loading->file, "player%d", i)) {
1246  continue;
1247  }
1248 
1249  fc_snprintf(buf, sizeof(buf), "player%d.diplstate%d", plrno, i);
1250 
1251  // Read the current diplomatic state.
1252  current = secfile_lookup_int_default(loading->file, DS_NO_CONTACT,
1253  "%s.type", buf);
1254 
1255  // Read the closest diplomatic state.
1256  closest = secfile_lookup_int_default(loading->file, DS_NO_CONTACT,
1257  "%s.max_state", buf);
1258 
1259  if (closest == DS_NO_CONTACT
1260  && (current == DS_PEACE || current == DS_ALLIANCE)) {
1261  const char *name1 = secfile_lookup_str_default(
1262  loading->file, "", "player%d.name", plrno);
1263  const char *name2 = secfile_lookup_str_default(loading->file, "",
1264  "player%d.name", i);
1265  /* The current relationship is closer than what the save game
1266  * claims is the closes relationship ever. */
1267 
1268  log_sg(
1269  _("The save game is wrong about what the closest"
1270  " relationship %s (player %d) and %s (player %d) have had is."
1271  " Fixing it..."),
1272  name1, plrno, name2, i);
1273 
1274  secfile_replace_int(loading->file, current, "%s.max_state", buf);
1275  }
1276  }
1278  }
1280 }
1281 
1285 static int increase_secfile_turn_int(struct loaddata *loading,
1286  const char *key, int old_def,
1287  bool keep_default)
1288 {
1289  int value;
1290 
1291  value = secfile_lookup_int_default(loading->file, old_def, "%s", key);
1292 
1293  if (value != old_def || !keep_default) {
1294  value++;
1295  secfile_replace_int(loading->file, value, "%s", key);
1296  }
1297 
1298  return value;
1299 }
1300 
1307 static void compat_load_030000(struct loaddata *loading,
1308  enum sgf_version format_class)
1309 {
1310  bool randsaved;
1311  int num_settings;
1312  bool started;
1313  int old_turn = 0;
1314 
1315  // Check status and return if not OK (sg_success != TRUE).
1316  sg_check_ret();
1317 
1318  log_debug("Upgrading data from savegame to version 3.0.0");
1319 
1320  /* Rename "random.save" as "random.saved"
1321  * Note that it's not an error if a scenario does not have [random] at all.
1322  */
1323  if (secfile_lookup_bool(loading->file, &randsaved, "random.save")) {
1324  secfile_insert_bool(loading->file, randsaved, "random.saved");
1325  }
1326 
1327  // Already started games should have their turn counts increased by 1
1328  if (secfile_lookup_bool_default(loading->file, true,
1329  "game.save_players")) {
1330  started = true;
1331 
1332  old_turn = increase_secfile_turn_int(loading, "game.turn", 0, false) - 1;
1333  increase_secfile_turn_int(loading, "game.scoreturn",
1334  old_turn + GAME_DEFAULT_SCORETURN, false);
1335  increase_secfile_turn_int(loading, "history.turn", -2, true);
1336  } else {
1337  started = false;
1338  }
1339 
1340  player_slots_iterate(pslot)
1341  {
1342  int plrno = player_slot_index(pslot);
1343  const char *flag_names[1];
1344 
1345  if (secfile_section_lookup(loading->file, "player%d", plrno)
1346  == nullptr) {
1347  continue;
1348  }
1349 
1350  if (secfile_lookup_bool_default(loading->file, false,
1351  "player%d.ai.control", plrno)) {
1352  flag_names[0] = plr_flag_id_name(PLRF_AI);
1353 
1354  secfile_insert_str_vec(loading->file, flag_names, 1, "player%d.flags",
1355  plrno);
1356  }
1357 
1358  if (started) {
1359  int num = secfile_lookup_int_default(loading->file, 0,
1360  "player%d.nunits", plrno);
1361  int i;
1362 
1363  for (i = 0; i < num; i++) {
1364  char buf[64];
1365 
1366  fc_snprintf(buf, sizeof(buf), "player%d.u%d.born", plrno, i);
1367 
1368  increase_secfile_turn_int(loading, buf, old_turn, false);
1369  }
1370 
1371  num = secfile_lookup_int_default(loading->file, 0, "player%d.ncities",
1372  plrno);
1373 
1374  for (i = 0; i < num; i++) {
1375  char buf[64];
1376 
1377  fc_snprintf(buf, sizeof(buf), "player%d.c%d.turn_founded", plrno, i);
1378 
1379  increase_secfile_turn_int(loading, buf, -2, true);
1380  }
1381  }
1382  }
1384 
1385  // Settings
1386  num_settings =
1387  secfile_lookup_int_default(loading->file, 0, "settings.set_count");
1388 
1389  // User meta server message is now a setting.
1390  if (secfile_lookup_bool_default(loading->file, false,
1391  "game.meta_usermessage")) {
1392  const char *metamessage;
1393 
1394  metamessage =
1395  secfile_lookup_str_default(loading->file, "", "game.meta_message");
1396 
1397  // Insert the meta message as a setting
1398  secfile_insert_str(loading->file, "metamessage", "settings.set%d.name",
1399  num_settings);
1400  secfile_insert_str(loading->file, metamessage, "settings.set%d.value",
1401  num_settings);
1402  secfile_insert_str(loading->file, "", "settings.set%d.gamestart",
1403  num_settings);
1404  num_settings++;
1405  }
1406 
1407  secfile_replace_int(loading->file, num_settings, "settings.set_count");
1408 }
1409 
1410 /*
1411  Insert server side agent information.
1412  */
1413 static void insert_server_side_agent(struct loaddata *loading,
1414  enum sgf_version format_class)
1415 {
1416  int ssa_size;
1417 
1418  if (format_class == SAVEGAME_2) {
1419  // Handled in savegame2
1420  return;
1421  }
1422 
1423  ssa_size = secfile_lookup_int_default(loading->file, 0,
1424  "savefile.server_side_agent_size");
1425 
1426  if (ssa_size != 0) {
1427  // Already inserted.
1428  return;
1429  }
1430 
1431  // Add server side agent order.
1432  secfile_insert_int(loading->file, SSA_COUNT,
1433  "savefile.server_side_agent_size");
1434  const char **modname;
1435  int i;
1436  int j;
1437  i = 0;
1438  modname = new const char *[SSA_COUNT]();
1439  for (j = 0; j < SSA_COUNT; j++) {
1440  modname[i++] = server_side_agent_name(static_cast<server_side_agent>(j));
1441  }
1442  secfile_insert_str_vec(loading->file, modname, SSA_COUNT,
1443  "savefile.server_side_agent_list");
1444  delete[] modname;
1445 
1446  // Insert server_side_agent unit field.
1447  player_slots_iterate(pslot)
1448  {
1449  int unit;
1450  int units_num;
1451  int plrno = player_slot_index(pslot);
1452 
1453  if (secfile_section_lookup(loading->file, "player%d", plrno)
1454  == nullptr) {
1455  continue;
1456  }
1457 
1458  // Number of units the player has.
1459  units_num = secfile_lookup_int_default(loading->file, 0,
1460  "player%d.nunits", plrno);
1461 
1462  for (unit = 0; unit < units_num; unit++) {
1463  bool ai;
1464 
1466  loading->file, "player%d.u%d.server_side_agent", plrno, unit)
1467  != nullptr) {
1468  // Already updated?
1469  continue;
1470  }
1471 
1472  ai = secfile_lookup_bool_default(loading->file, false,
1473  "player%d.u%d.ai", plrno, unit);
1474 
1475  if (ai) {
1476  /* Autosettler and Auotexplore are separated by
1477  * compat_post_load_030100() when set to SSA_AUTOSETTLER */
1478  secfile_insert_int(loading->file, SSA_AUTOSETTLER,
1479  "player%d.u%d.server_side_agent", plrno, unit);
1480  } else {
1481  secfile_insert_int(loading->file, SSA_NONE,
1482  "player%d.u%d.server_side_agent", plrno, unit);
1483  }
1484  }
1485  }
1487 }
1488 
1495 static void compat_load_030100(struct loaddata *loading,
1496  enum sgf_version format_class)
1497 {
1498  // Check status and return if not OK (sg_success != TRUE).
1499  sg_check_ret();
1500 
1501  log_debug("Upgrading data from savegame to version 3.1.0");
1502 
1503  // Actions are now stored by number.
1504  player_slots_iterate(pslot)
1505  {
1506  int unit;
1507  int units_num;
1508  int plrno = player_slot_index(pslot);
1509 
1510  if (secfile_section_lookup(loading->file, "player%d", plrno)
1511  == nullptr) {
1512  continue;
1513  }
1514 
1515  // Number of units the player has.
1516  units_num = secfile_lookup_int_default(loading->file, 0,
1517  "player%d.nunits", plrno);
1518 
1519  for (unit = 0; unit < units_num; unit++) {
1520  const char *action_unitstr;
1521  int order_len;
1522 
1523  order_len = secfile_lookup_int_default(
1524  loading->file, 0, "player%d.u%d.orders_length", plrno, unit);
1525  action_unitstr = secfile_lookup_str_default(
1526  loading->file, "", "player%d.u%d.action_list", plrno, unit);
1527  if (action_unitstr) {
1528  int order_num;
1529 
1530  if (order_len > qstrlen(action_unitstr)) {
1531  order_len = qstrlen(action_unitstr);
1532  }
1533 
1534  for (order_num = 0; order_num < order_len; order_num++) {
1535  int unconverted_action_id;
1536 
1537  if (action_unitstr[order_num] == '?') {
1538  unconverted_action_id = -1;
1539  } else {
1540  unconverted_action_id = char2num(action_unitstr[order_num]);
1541  }
1542 
1543  if (order_num == 0) {
1544  // The start of a vector has no number.
1545  secfile_insert_int(loading->file, unconverted_action_id,
1546  "player%d.u%d.action_vec", plrno, unit);
1547  } else {
1548  secfile_insert_int(loading->file, unconverted_action_id,
1549  "player%d.u%d.action_vec,%d", plrno, unit,
1550  order_num);
1551  }
1552  }
1553  }
1554  }
1555  }
1557 
1558  // Explicit server side agent was new in 3.1
1559  insert_server_side_agent(loading, format_class);
1560 }
1561 
1565 static void unit_order_activity_to_action(struct unit *act_unit)
1566 {
1567  int i;
1568 
1569  for (i = 0; i < act_unit->orders.length; i++) {
1570  struct unit_order *order = &act_unit->orders.list[i];
1571 
1572  if (order->order != ORDER_ACTIVITY) {
1573  continue;
1574  }
1575 
1576  switch (order->activity) {
1577  case ACTIVITY_FALLOUT:
1578  case ACTIVITY_POLLUTION:
1579  case ACTIVITY_MINE:
1580  case ACTIVITY_IRRIGATE:
1581  case ACTIVITY_PLANT:
1582  case ACTIVITY_CULTIVATE:
1583  case ACTIVITY_TRANSFORM:
1584  case ACTIVITY_CONVERT:
1585  case ACTIVITY_FORTIFYING:
1586  case ACTIVITY_BASE:
1587  case ACTIVITY_GEN_ROAD:
1588  case ACTIVITY_PILLAGE:
1589  action_iterate(act_id)
1590  {
1591  struct action *paction = action_by_number(act_id);
1592  if (action_get_activity(paction) == order->activity) {
1593  order->order = ORDER_PERFORM_ACTION;
1594  order->action = action_number(paction);
1595  order->activity = ACTIVITY_LAST;
1596  break;
1597  }
1598  }
1600  break;
1601  case ACTIVITY_SENTRY:
1602  // Not an action
1603  break;
1604  case ACTIVITY_EXPLORE:
1605  case ACTIVITY_IDLE:
1606  case ACTIVITY_GOTO:
1607  case ACTIVITY_FORTIFIED:
1608  case ACTIVITY_OLD_ROAD:
1609  case ACTIVITY_OLD_RAILROAD:
1610  case ACTIVITY_FORTRESS:
1611  case ACTIVITY_AIRBASE:
1612  case ACTIVITY_PATROL_UNUSED:
1613  case ACTIVITY_LAST:
1614  case ACTIVITY_UNKNOWN:
1615  qCritical("Activity %d is not supposed to appear in unit orders",
1616  order->activity);
1617  break;
1618  }
1619  }
1620 }
1621 
1625 static enum direction8 dir_opposite(enum direction8 dir)
1626 {
1627  switch (dir) {
1628  case DIR8_NORTH:
1629  return DIR8_SOUTH;
1630  case DIR8_NORTHEAST:
1631  return DIR8_SOUTHWEST;
1632  case DIR8_EAST:
1633  return DIR8_WEST;
1634  case DIR8_SOUTHEAST:
1635  return DIR8_NORTHWEST;
1636  case DIR8_SOUTH:
1637  return DIR8_NORTH;
1638  case DIR8_SOUTHWEST:
1639  return DIR8_NORTHEAST;
1640  case DIR8_WEST:
1641  return DIR8_EAST;
1642  case DIR8_NORTHWEST:
1643  return DIR8_SOUTHEAST;
1644  }
1645 
1646  return DIR8_ORIGIN;
1647 }
1648 
1652 static void upgrade_unit_order_targets(struct unit *act_unit)
1653 {
1654  int i;
1655  struct tile *current_tile;
1656  struct tile *tgt_tile;
1657 
1658  if (!unit_has_orders(act_unit)) {
1659  return;
1660  }
1661 
1662  // The order index is for the unit at its current tile.
1663  current_tile = unit_tile(act_unit);
1664 
1665  // Rewind to the beginning of the orders
1666  for (i = act_unit->orders.index; i > 0; i--) {
1667  struct unit_order *prev_order = &act_unit->orders.list[i - 1];
1668 
1669  if (!(prev_order->order == ORDER_PERFORM_ACTION
1671  unit_type_get(act_unit)))
1672  && direction8_is_valid(prev_order->dir)) {
1673  current_tile =
1674  mapstep(&(wld.map), current_tile, dir_opposite(prev_order->dir));
1675  }
1676  }
1677 
1678  // Upgrade to explicit target tile
1679  for (i = 0; i < act_unit->orders.length; i++) {
1680  struct unit_order *order = &act_unit->orders.list[i];
1681 
1682  if (order->order == ORDER_PERFORM_ACTION && order->target != NO_TARGET) {
1683  // The target is already specified in the new format.
1684  tgt_tile = index_to_tile(&(wld.map), order->target);
1685  fc_assert(tgt_tile != nullptr);
1686  return;
1687  }
1688 
1689  if (!direction8_is_valid(order->dir)) {
1690  // The target of the action is on the actor's tile.
1691  tgt_tile = current_tile;
1692  } else {
1693  // The target of the action is on a tile next to the actor.
1694  tgt_tile = mapstep(&(wld.map), current_tile, order->dir);
1695  }
1696 
1697  if (order->order == ORDER_PERFORM_ACTION) {
1698  struct action *paction = action_by_number(order->action);
1699 
1700  order->target = tgt_tile->index;
1701  // Leave no traces.
1702  order->dir = DIR8_ORIGIN;
1703 
1704  if (!utype_is_unmoved_by_action(paction, unit_type_get(act_unit))) {
1705  /* The action moves the unit to the target tile (unless this is the
1706  * final order) */
1707  fc_assert(
1709  || i == act_unit->orders.length - 1);
1710  current_tile = tgt_tile;
1711  }
1712  } else {
1713  current_tile = tgt_tile;
1714  }
1715  }
1716 }
1717 
1718 /*
1719  Correct the server side agent information.
1720  */
1721 static void upgrade_server_side_agent(struct loaddata *loading)
1722 {
1723  players_iterate_alive(pplayer)
1724  {
1725  unit_list_iterate(pplayer->units, punit)
1726  {
1727  if (punit->activity == ACTIVITY_EXPLORE) {
1728  punit->ssa_controller = SSA_AUTOEXPLORE;
1729  }
1730  }
1732  }
1734 }
1735 
1739 static void compat_post_load_030100(struct loaddata *loading,
1740  enum sgf_version format_class)
1741 {
1742  // Check status and return if not OK (sg_success != TRUE).
1743  sg_check_ret();
1744 
1745  // Action orders were new in 3.0
1746  if (format_class == SAVEGAME_3) {
1747  // Only 3.0 savegames may have "Attack" action orders.
1748  players_iterate_alive(pplayer)
1749  {
1750  unit_list_iterate(pplayer->units, punit)
1751  {
1752  int i;
1753 
1754  if (!punit->has_orders) {
1755  continue;
1756  }
1757 
1758  fc_assert_action(punit->orders.length == 0
1759  || punit->orders.list != nullptr,
1760  continue);
1761 
1762  for (i = 0; i < punit->orders.length; i++) {
1763  // "Attack" was split in "Suicide Attack" and "Attack" in 3.1.
1764  if (punit->orders.list[i].order == ORDER_PERFORM_ACTION
1765  && punit->orders.list[i].action == ACTION_ATTACK
1766  && !unit_can_do_action(punit, ACTION_ATTACK)
1767  && unit_can_do_action(punit, ACTION_SUICIDE_ATTACK)) {
1768  punit->orders.list[i].action = ACTION_SUICIDE_ATTACK;
1769  }
1770 
1771  /* Production targeted actions were split from building targeted
1772  * actions in 3.1. The building sub target encoding changed. */
1773  if (punit->orders.list[i].order == ORDER_PERFORM_ACTION
1774  && ((punit->orders.list[i].action
1775  == ACTION_SPY_TARGETED_SABOTAGE_CITY)
1776  || (punit->orders.list[i].action
1777  == ACTION_SPY_TARGETED_SABOTAGE_CITY_ESC))) {
1778  punit->orders.list[i].sub_target -= 1;
1779  }
1780  if (punit->orders.list[i].order == ORDER_PERFORM_ACTION
1781  && (punit->orders.list[i].action
1782  == ACTION_SPY_TARGETED_SABOTAGE_CITY)
1783  && punit->orders.list[i].sub_target == -1) {
1784  punit->orders.list[i].action =
1785  ACTION_SPY_SABOTAGE_CITY_PRODUCTION;
1786  }
1787  if (punit->orders.list[i].order == ORDER_PERFORM_ACTION
1788  && (punit->orders.list[i].action
1789  == ACTION_SPY_TARGETED_SABOTAGE_CITY_ESC)
1790  && punit->orders.list[i].sub_target == -1) {
1791  punit->orders.list[i].action =
1792  ACTION_SPY_SABOTAGE_CITY_PRODUCTION_ESC;
1793  }
1794  }
1795  }
1797  }
1799  }
1800 
1801  // Explicit server side agent was new in 3.1
1802  upgrade_server_side_agent(loading);
1803 
1804  // Some activities should only be ordered in action orders.
1805  players_iterate_alive(pplayer)
1806  {
1807  unit_list_iterate(pplayer->units, punit)
1808  {
1810  }
1812  }
1814 
1815  // Unit order action target isn't dir anymore
1816  players_iterate_alive(pplayer)
1817  {
1818  unit_list_iterate(pplayer->units, punit)
1819  {
1821  }
1823  }
1825 
1826  /* Backward compatibility: if we had any open-ended orders (pillage)
1827  * in the savegame, assign specific targets now */
1828  players_iterate_alive(pplayer)
1829  {
1830  unit_list_iterate(pplayer->units, punit)
1831  {
1832  unit_assign_specific_activity_target(punit, &punit->activity,
1833  &punit->activity_target);
1834  }
1836  }
1838 }
1839 
1844 #ifdef FREECIV_DEV_SAVE_COMPAT
1845 static void compat_load_dev(struct loaddata *loading)
1846 {
1847  int game_version;
1848 
1849  // Check status and return if not OK (sg_success != TRUE).
1850  sg_check_ret();
1851 
1852  log_debug("Upgrading data between development revisions");
1853 
1854  if (!secfile_lookup_int(loading->file, &game_version,
1855  "scenario.game_version")) {
1856  game_version = 2060000;
1857  }
1858 
1859 #ifdef FREECIV_DEV_SAVE_COMPAT_3_1
1860 
1861  if (game_version < 3009200) {
1862  // Before version number bump to 3.0.92, beginning of 2020
1863 
1864  // Renamed actions.
1865  loading->action.size =
1866  secfile_lookup_int_default(loading->file, 0, "savefile.action_size");
1867  if (loading->action.size) {
1868  const char **modname;
1869  int j;
1870 
1871  modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
1872  "savefile.action_vector");
1873 
1874  for (j = 0; j < loading->action.size; j++) {
1875  if (fc_strcasecmp(modname[j], "Targeted Steal Tech Escape") == 0) {
1876  secfile_replace_str(loading->file,
1877  "Targeted Steal Tech Escape Expected",
1878  "savefile.action_vector,%d", j);
1879  } else if (fc_strcasecmp(modname[j], "Steal Tech Escape") == 0) {
1880  secfile_replace_str(loading->file, "Steal Tech Escape Expected",
1881  "savefile.action_vector,%d", j);
1882  } else if (fc_strcasecmp(modname[j], "Road") == 0) {
1883  secfile_replace_str(loading->file, "Build Road",
1884  "savefile.action_vector,%d", j);
1885  }
1886  }
1887 
1888  delete[] modname;
1889  }
1890 
1891  // Old unit order tgt_vec refers to order sub targets
1892  player_slots_iterate(pslot)
1893  {
1894  int unit;
1895  int units_num;
1896  int plrno = player_slot_index(pslot);
1897 
1898  if (secfile_section_lookup(loading->file, "player%d", plrno)
1899  == nullptr) {
1900  continue;
1901  }
1902 
1903  // Number of units the player has.
1904  units_num = secfile_lookup_int_default(loading->file, 0,
1905  "player%d.nunits", plrno);
1906 
1907  for (unit = 0; unit < units_num; unit++) {
1908  size_t old_tgt_size;
1909  int *old_tgt_vec;
1910  old_tgt_vec =
1911  secfile_lookup_int_vec(loading->file, &old_tgt_size,
1912  "player%d.u%d.tgt_vec", plrno, unit);
1913  if (old_tgt_vec) {
1914  secfile_insert_int_vec(loading->file, old_tgt_vec, old_tgt_size,
1915  "player%d.u%d.sub_tgt_vec", plrno, unit);
1916  delete[] old_tgt_vec;
1917  old_tgt_vec = nullptr;
1918  }
1919  }
1920  }
1922 
1923  /* Unit order extra sub targets was for a while stored separate from tech
1924  * and building sub targets. */
1925  player_slots_iterate(pslot)
1926  {
1927  int unit;
1928  int units_num;
1929  int plrno = player_slot_index(pslot);
1930 
1931  if (secfile_section_lookup(loading->file, "player%d", plrno)
1932  == nullptr) {
1933  continue;
1934  }
1935 
1936  // Number of units the player has.
1937  units_num = secfile_lookup_int_default(loading->file, 0,
1938  "player%d.nunits", plrno);
1939 
1940  for (unit = 0; unit < units_num; unit++) {
1941  size_t extra_vec_size;
1942  int *extra_vec;
1943 
1944  if ((extra_vec = secfile_lookup_int_vec(
1945  loading->file, &extra_vec_size, "player%d.u%d.extra_vec",
1946  plrno, unit))) {
1947  int order_num;
1948 
1949  for (order_num = 0; order_num < extra_vec_size; order_num++) {
1950  if (extra_vec[order_num] != -1) {
1951  if (order_num) {
1952  secfile_replace_int(loading->file, extra_vec[order_num],
1953  "player%d.u%d.sub_tgt_vec,%d", plrno,
1954  unit, order_num);
1955  } else {
1956  secfile_replace_int(loading->file, extra_vec[order_num],
1957  "player%d.u%d.sub_tgt_vec", plrno, unit);
1958  }
1959  }
1960  }
1961  delete[] extra_vec;
1962  }
1963  }
1964  }
1966 
1967  player_slots_iterate(pslot)
1968  {
1969  int plrno = player_slot_index(pslot);
1970  int history;
1971 
1972  history = secfile_lookup_int_default(loading->file, 0,
1973  "player%d.culture", plrno);
1974 
1975  if (history > 0) {
1976  /* Savefile had player history value saved to field named 'culture'.
1977  * Save it to 'history'. */
1978  secfile_insert_int(loading->file, history, "player%d.history",
1979  plrno);
1980  }
1981  }
1983 
1984  {
1985  int action_count;
1986 
1987  action_count = secfile_lookup_int_default(loading->file, 0,
1988  "savefile.action_size");
1989  if (action_count > 0) {
1990  const char **modname;
1991  const char **modname_new;
1992  const char *plant_name = "Plant";
1993  const char *cultivate_name = "Cultivate";
1994  int j;
1995 
1996  modname = secfile_lookup_str_vec(
1997  loading->file, &loading->action.size, "savefile.action_vector");
1998 
1999  modname_new = new action_count();
2000  for (j = 0; j < action_count; j++) {
2001  const char *aname = modname[j];
2002 
2003  if (!fc_strcasecmp("Mine TF", aname)) {
2004  modname_new[j] = plant_name;
2005  } else if (!fc_strcasecmp("Irrigate TF", aname)) {
2006  modname_new[j] = cultivate_name;
2007  } else {
2008  modname_new[j] = aname;
2009  }
2010  }
2011 
2012  secfile_replace_str_vec(loading->file, modname_new, action_count,
2013  "savefile.action_vector");
2014 
2015  free(modname_new);
2016  }
2017  }
2018 
2019  // Actions are now stored by number.
2020  player_slots_iterate(pslot)
2021  {
2022  int unit;
2023  int units_num;
2024  int plrno = player_slot_index(pslot);
2025 
2026  if (secfile_section_lookup(loading->file, "player%d", plrno)
2027  == nullptr) {
2028  continue;
2029  }
2030 
2031  // Number of units the player has.
2032  units_num = secfile_lookup_int_default(loading->file, 0,
2033  "player%d.nunits", plrno);
2034 
2035  for (unit = 0; unit < units_num; unit++) {
2036  const char *action_unitstr;
2037  int order_len;
2038 
2039  order_len = secfile_lookup_int_default(
2040  loading->file, 0, "player%d.u%d.orders_length", plrno, unit);
2041  action_unitstr = secfile_lookup_str_default(
2042  loading->file, "", "player%d.u%d.action_list", plrno, unit);
2043  if (action_unitstr) {
2044  int order_num;
2045 
2046  if (order_len > qstrlen(action_unitstr)) {
2047  order_len = qstrlen(action_unitstr);
2048  }
2049 
2050  for (order_num = 0; order_num < order_len; order_num++) {
2051  int unconverted_action_id;
2052 
2053  if (action_unitstr[order_num] == '?') {
2054  unconverted_action_id = -1;
2055  } else {
2056  unconverted_action_id = char2num(action_unitstr[order_num]);
2057  }
2058 
2059  if (order_num == 0) {
2060  // The start of a vector has no number.
2061  secfile_insert_int(loading->file, unconverted_action_id,
2062  "player%d.u%d.action_vec", plrno, unit);
2063  } else {
2064  secfile_insert_int(loading->file, unconverted_action_id,
2065  "player%d.u%d.action_vec,%d", plrno, unit,
2066  order_num);
2067  }
2068  }
2069  }
2070  }
2071  }
2073  player_slots_iterate(pslot)
2074  {
2075  int city;
2076  int city_num;
2077  int plrno = player_slot_index(pslot);
2078 
2079  if (secfile_section_lookup(loading->file, "player%d", plrno)
2080  == nullptr) {
2081  continue;
2082  }
2083 
2084  // Number of cities the player has.
2085  city_num = secfile_lookup_int_default(loading->file, 0,
2086  "player%d.ncities", plrno);
2087 
2088  for (city = 0; city < city_num; city++) {
2089  const char *action_citystr;
2090  int order_len;
2091 
2092  order_len = secfile_lookup_int_default(
2093  loading->file, 0, "player%d.c%d.rally_point_length", plrno,
2094  city);
2095  action_citystr = secfile_lookup_str_default(
2096  loading->file, "", "player%d.c%d.rally_point_actions", plrno,
2097  city);
2098  if (action_citystr) {
2099  int order_num;
2100 
2101  if (order_len > qstrlen(action_citystr)) {
2102  order_len = qstrlen(action_citystr);
2103  }
2104 
2105  for (order_num = 0; order_num < order_len; order_num++) {
2106  int unconverted_action_id;
2107 
2108  if (action_citystr[order_num] == '?') {
2109  unconverted_action_id = -1;
2110  } else {
2111  unconverted_action_id = char2num(action_citystr[order_num]);
2112  }
2113 
2114  if (order_num == 0) {
2115  // The start of a vector has no number.
2116  secfile_insert_int(loading->file, unconverted_action_id,
2117  "player%d.c%d.rally_point_action_vec",
2118  plrno, city);
2119  } else {
2120  secfile_insert_int(loading->file, unconverted_action_id,
2121  "player%d.c%d.rally_point_action_vec,%d",
2122  plrno, city, order_num);
2123  }
2124  }
2125  }
2126  }
2127  }
2129  } // Version < 3.0.92
2130 
2131  if (game_version < 3009300) {
2132  // Before version number bump to 3.0.93
2133 
2134  // Explicit server side agent was new in 3.1
2136  } // Version < 3.0.93
2137 
2138 #endif // FREECIV_DEV_SAVE_COMPAT_3_1
2139 }
2140 
2145 static void compat_post_load_dev(struct loaddata *loading)
2146 {
2147  int game_version;
2148 
2149  // Check status and return if not OK (sg_success != TRUE).
2150  sg_check_ret();
2151 
2152  if (!secfile_lookup_int(loading->file, &game_version,
2153  "scenario.game_version")) {
2154  game_version = 2060000;
2155  }
2156 
2157  if (game_version < 3009300) {
2158  players_iterate_alive(pplayer)
2159  {
2160  unit_list_iterate(pplayer->units, punit)
2161  {
2162  int i;
2163 
2164  if (!punit->has_orders) {
2165  continue;
2166  }
2167 
2168  fc_assert_action(punit->orders.length == 0
2169  || punit->orders.list != nullptr,
2170  continue);
2171 
2172  for (i = 0; i < punit->orders.length; i++) {
2173  // "Attack" was split in "Suicide Attack" and "Attack" in 3.1.
2174  if (punit->orders.list[i].order == ORDER_PERFORM_ACTION
2175  && punit->orders.list[i].action == ACTION_ATTACK
2176  && !unit_can_do_action(punit, ACTION_ATTACK)
2177  && unit_can_do_action(punit, ACTION_SUICIDE_ATTACK)) {
2178  punit->orders.list[i].action = ACTION_SUICIDE_ATTACK;
2179  }
2180  }
2181  }
2183  }
2185 
2186  // Explicit server side agent was new in 3.1
2187  upgrade_server_side_agent(loading);
2188 
2189  // Some activities should only be ordered in action orders.
2190  players_iterate_alive(pplayer)
2191  {
2192  unit_list_iterate(pplayer->units, punit)
2193  {
2195  }
2197  }
2199 
2200  // Unit order action target isn't dir anymore
2201  players_iterate_alive(pplayer)
2202  {
2203  unit_list_iterate(pplayer->units, punit)
2204  {
2206  }
2208  }
2210 
2211  /* Backward compatibility: if we had any open-ended orders (pillage)
2212  * in the savegame, assign specific targets now */
2213  players_iterate_alive(pplayer)
2214  {
2215  unit_list_iterate(pplayer->units, punit)
2216  {
2217  unit_assign_specific_activity_target(punit, &punit->activity,
2218  &punit->activity_target);
2219  }
2221  }
2223  } // Version < 3.0.93
2224 }
2225 #endif // FREECIV_DEV_SAVE_COMPAT
2226 
2230 enum ai_level ai_level_convert(int old_level)
2231 {
2232  switch (old_level) {
2233  case 1:
2234  return AI_LEVEL_AWAY;
2235  case 2:
2236  return AI_LEVEL_NOVICE;
2237  case 3:
2238  return AI_LEVEL_EASY;
2239  case 5:
2240  return AI_LEVEL_NORMAL;
2241  case 7:
2242  return AI_LEVEL_HARD;
2243  case 8:
2244  return AI_LEVEL_CHEATING;
2245  case 10:
2246 #ifdef FREECIV_DEBUG
2247  return AI_LEVEL_EXPERIMENTAL;
2248 #else // FREECIV_DEBUG
2249  return AI_LEVEL_HARD;
2250 #endif // FREECIV_DEBUG
2251  }
2252 
2253  return ai_level_invalid();
2254 }
2255 
2259 enum barbarian_type barb_type_convert(int old_type)
2260 {
2261  switch (old_type) {
2262  case 0:
2263  return NOT_A_BARBARIAN;
2264  case 1:
2265  return LAND_BARBARIAN;
2266  case 2:
2267  return SEA_BARBARIAN;
2268  }
2269 
2270  return barbarian_type_invalid();
2271 }
2272 
2277 {
2278  set_unit_activity_targeted(punit, ACTIVITY_BASE,
2280 }
2281 
2286 {
2287  set_unit_activity_targeted(punit, ACTIVITY_GEN_ROAD,
2289 }
2290 
2311 int sg_order_to_action(int order, struct unit *act_unit,
2312  struct tile *tgt_tile)
2313 {
2314  switch (order) {
2315  case ORDER_OLD_BUILD_CITY:
2316  if (tile_city(tgt_tile)
2317  && city_owner(tile_city(tgt_tile)) == unit_owner(act_unit)) {
2318  /* The player's cities are loaded right before his units. It wasn't
2319  * possible for rulesets to allow joining foreign cities before 3.0.
2320  * This means that a converted build city order only can be a Join
2321  * City order if it targets a domestic city. */
2322  return ACTION_JOIN_CITY;
2323  } else {
2324  // Assume that the intention was to found a new city.
2325  return ACTION_FOUND_CITY;
2326  }
2328  // Maps one to one with each other.
2329  return ACTION_HELP_WONDER;
2330  case ORDER_OLD_TRADE_ROUTE:
2331  // Maps one to one with each other.
2332  return ACTION_TRADE_ROUTE;
2333  case ORDER_OLD_DISBAND:
2334  /* Added to the order system in the same commit as Help Wonder. Assume
2335  * that anyone that intended to order Help Wonder used Help Wonder. */
2336  /* Could in theory be intended as an order to disband in the field. Why
2337  * would the player give a unit an order to go to a non city location
2338  * and disband there? Assume the intention was to recycle the unit
2339  * until a non recycle disband order is found. */
2340  return ACTION_RECYCLE_UNIT;
2341  case ORDER_OLD_HOMECITY:
2342  return ACTION_HOME_CITY;
2343  }
2344 
2345  // The order hasn't been replaced by an action.
2346  return ACTION_NONE;
2347 }
int action_number(const struct action *action)
Get the universal number of the action.
Definition: actions.cpp:1338
struct action * action_by_number(action_id act_id)
Return the action with the given id.
Definition: actions.cpp:1149
enum unit_activity action_get_activity(const struct action *paction)
Returns the unit activity this action may cause or ACTIVITY_LAST if the action doesn't result in a un...
Definition: actions.cpp:1557
#define action_iterate_end
Definition: actions.h:383
#define action_iterate(_act_)
Definition: actions.h:378
#define ACTION_NONE
Definition: actions.h:220
const char * default_ai_type_name()
Return name of default ai type.
Definition: aiiface.cpp:265
struct extra_type * base_extra_get(const struct base_type *pbase)
Return extra that base is.
Definition: base.cpp:144
struct base_type * base_by_number(const Base_type_id id)
Returns base_type entry for an ID value.
Definition: base.cpp:119
bool has_capability(const char *cap, const char *capstr)
Wrapper for fc_has_capability() for nullptr terminated strings.
Definition: capability.cpp:71
struct player * city_owner(const struct city *pcity)
Return the owner of the city.
Definition: city.cpp:1083
static void road(QVariant data1, QVariant data2)
Action "Build Road" for choice dialog.
Definition: dialogs.cpp:2374
static void base(QVariant data1, QVariant data2)
Action "Build Base" for choice dialog.
Definition: dialogs.cpp:2393
struct extra_type_list * extra_type_list_by_cause(enum extra_cause cause)
Returns extra type for given cause.
Definition: extras.cpp:224
#define extra_type_by_cause_iterate_end
Definition: extras.h:307
#define extra_type_by_cause_iterate(_cause, _extra)
Definition: extras.h:299
#define NO_TARGET
Definition: fc_types.h:271
int Road_type_id
Definition: fc_types.h:301
#define EC_SPECIAL
Definition: fc_types.h:935
revolen_type
Definition: fc_types.h:1087
@ REVOLEN_RANDOM
Definition: fc_types.h:1089
@ REVOLEN_RANDQUICK
Definition: fc_types.h:1091
@ REVOLEN_FIXED
Definition: fc_types.h:1088
@ REVOLEN_QUICKENING
Definition: fc_types.h:1090
#define DIR8_ORIGIN
Definition: fc_types.h:372
#define MAX_NUM_PLAYER_SLOTS
Definition: fc_types.h:24
int Base_type_id
Definition: fc_types.h:300
#define _(String)
Definition: fcintl.h:50
struct world wld
Definition: game.cpp:48
#define GAME_DEFAULT_REVOLENTYPE
Definition: game.h:675
#define GAME_DEFAULT_SCORETURN
Definition: game.h:541
#define GAME_DEFAULT_SAVETURNS
Definition: game.h:632
#define GAME_DEFAULT_TEAM_POOLED_RESEARCH
Definition: game.h:525
const char * name
Definition: inputfile.cpp:118
#define fc_assert(condition)
Definition: log.h:89
#define fc_assert_action(condition, action)
Definition: log.h:104
#define log_debug(message,...)
Definition: log.h:65
struct tile * index_to_tile(const struct civ_map *imap, int mindex)
Return the tile for the given index position.
Definition: map.cpp:429
struct tile * mapstep(const struct civ_map *nmap, const struct tile *ptile, enum direction8 dir)
Step from the given tile in the given direction.
Definition: map.cpp:342
char * lines
Definition: packhand.cpp:131
int len
Definition: packhand.cpp:127
int player_slot_index(const struct player_slot *pslot)
Returns the index of the player slot.
Definition: player.cpp:373
#define ANON_USER_NAME
Definition: player.h:31
#define player_slots_iterate(_pslot)
Definition: player.h:505
#define players_iterate_alive_end
Definition: player.h:532
#define player_slots_iterate_end
Definition: player.h:509
#define players_iterate_alive(_pplayer)
Definition: player.h:526
const char * secfile_error()
Returns the last error which occurred in a string.
bool secfile_lookup_int(const struct section_file *secfile, int *ival, const char *path,...)
Lookup a integer value in the secfile.
bool secfile_entry_delete(struct section_file *secfile, const char *path,...)
Delete an entry.
bool entry_set_name(struct entry *pentry, const char *name)
Sets the name of the entry.
bool secfile_lookup_enum_data(const struct section_file *secfile, int *pvalue, bool bitwise, secfile_enum_name_data_fn_t name_fn, secfile_data_t data, const char *path,...)
Lookup a value saved as string in the secfile.
int * secfile_lookup_int_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
Lookup a integer vector in the secfile.
const char * entry_name(const struct entry *pentry)
Returns the name of this entry.
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
Lookup a string value in the secfile.
const char ** secfile_lookup_str_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
Lookup a string vector in the secfile.
struct section * secfile_section_by_name(const struct section_file *secfile, const QString &name)
Returns the first section matching the name.
bool secfile_lookup_bool_default(const struct section_file *secfile, bool def, const char *path,...)
Lookup a boolean value in the secfile.
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
Lookup a string value in the secfile.
int secfile_lookup_int_default(const struct section_file *secfile, int def, const char *path,...)
Lookup a integer value in the secfile.
struct section * secfile_section_lookup(const struct section_file *secfile, const char *path,...)
Find a section by path.
const struct entry_list * section_entries(const struct section *psection)
Returns a list containing all the entries.
bool secfile_lookup_bool(const struct section_file *secfile, bool *bval, const char *path,...)
Lookup a boolean value in the secfile.
#define secfile_replace_str_vec(secfile, strings, dim, path,...)
Definition: registry_ini.h:218
#define secfile_insert_int(secfile, value, path,...)
Definition: registry_ini.h:116
entry_type
Definition: registry_ini.h:533
@ ENTRY_FILEREFERENCE
Definition: registry_ini.h:538
@ ENTRY_INT
Definition: registry_ini.h:535
@ ENTRY_FLOAT
Definition: registry_ini.h:536
@ ENTRY_STR
Definition: registry_ini.h:537
@ ENTRY_ILLEGAL
Definition: registry_ini.h:539
@ ENTRY_BOOL
Definition: registry_ini.h:534
#define secfile_insert_int_vec(secfile, values, dim, path,...)
Definition: registry_ini.h:131
#define secfile_insert_str_vec(secfile, strings, dim, path,...)
Definition: registry_ini.h:204
#define secfile_replace_int(secfile, value, path,...)
Definition: registry_ini.h:122
#define entry_list_iterate_end
Definition: registry_ini.h:58
#define secfile_insert_str(secfile, string, path,...)
Definition: registry_ini.h:167
#define secfile_insert_bool(secfile, value, path,...)
Definition: registry_ini.h:79
#define secfile_replace_str(secfile, string, path,...)
Definition: registry_ini.h:180
#define entry_list_iterate(entlist, pentry)
Definition: registry_ini.h:56
#define secfile_replace_bool(secfile, value, path,...)
Definition: registry_ini.h:85
const void * secfile_data_t
Definition: registry_ini.h:28
struct road_type * road_by_number(Road_type_id id)
Return road type of given id.
Definition: road.cpp:46
struct extra_type * road_extra_get(const struct road_type *proad)
Return extra that road is.
Definition: road.cpp:33
struct extra_type * resource_by_identifier(const char identifier)
Return the resource type matching the identifier, or nullptr when none matches.
Definition: savecompat.cpp:321
static void compat_post_load_030100(struct loaddata *loading, enum sgf_version format_class)
Update loaded game data from 3.0.x to something usable by 3.1.0.
static const char * killcitizen_enum_str(secfile_data_t data, int bit)
Callback to get name of old killcitizen setting bit.
Definition: savecompat.cpp:558
int sg_order_to_action(int order, struct unit *act_unit, struct tile *tgt_tile)
Returns the action id corresponding to the specified order id.
const char * special_rule_name(enum tile_special_type type)
Return the untranslated name of the given special.
Definition: savecompat.cpp:295
static void compat_load_030000(struct loaddata *loading, enum sgf_version format_class)
Translate savegame secfile data from 2.6.x to 3.0.0 format.
static const char num_chars[]
Definition: savecompat.cpp:257
bool sg_success
Definition: savecompat.cpp:30
enum barbarian_type barb_type_convert(int old_type)
Convert old barbarian type value to barbarian_type.
static struct compatibility compat[]
Definition: savecompat.cpp:109
void set_unit_activity_road(struct unit *punit, Road_type_id road)
Assign a new road building task to unit.
static void compat_load_020400(struct loaddata *loading, enum sgf_version format_class)
Translate savegame secfile data from 2.3.x to 2.4.0 format.
Definition: savecompat.cpp:341
static void upgrade_unit_order_targets(struct unit *act_unit)
Upgrade unit action order target encoding.
static const char * special_names[]
Definition: savecompat.cpp:32
struct extra_type * special_extra_get(int spe)
Get extra of the given special.
Definition: savecompat.cpp:305
char bin2ascii_hex(int value, int halfbyte_wanted)
This returns an ascii hex value of the given half-byte of the binary integer.
Definition: savecompat.cpp:227
static const int compat_num
Definition: savecompat.cpp:130
static void compat_load_020600(struct loaddata *loading, enum sgf_version format_class)
Translate savegame secfile data from 2.5.x to 2.6.0 format.
Definition: savecompat.cpp:685
static enum direction8 dir_opposite(enum direction8 dir)
Returns the opposite direction.
void(* load_version_func_t)(struct loaddata *loading, enum sgf_version format_class)
Definition: savecompat.cpp:88
int char2num(char ch)
Converts single character into numerical value.
Definition: savecompat.cpp:264
static void upgrade_server_side_agent(struct loaddata *loading)
void sg_load_compat(struct loaddata *loading, enum sgf_version format_class)
Compatibility functions for loaded game.
Definition: savecompat.cpp:140
static void unit_order_activity_to_action(struct unit *act_unit)
Upgrade unit activity orders to unit action orders.
static int increase_secfile_turn_int(struct loaddata *loading, const char *key, int old_def, bool keep_default)
Increase turn value in secfile by one.
enum ai_level ai_level_convert(int old_level)
Translate savegame secfile data from earlier development version format to current one.
void set_unit_activity_base(struct unit *punit, Base_type_id base)
Assign a new base building task to unit.
int ascii_hex2bin(char ch, int halfbyte)
This returns a binary integer value of the ascii hex char, offset by the given number of half-bytes.
Definition: savecompat.cpp:239
static void compat_load_020500(struct loaddata *loading, enum sgf_version format_class)
Translate savegame secfile data from 2.4.x to 2.5.0 format.
Definition: savecompat.cpp:575
enum tile_special_type special_by_rule_name(const char *name)
Return the special with the given name, or S_LAST.
Definition: savecompat.cpp:279
void sg_load_post_load_compat(struct loaddata *loading, enum sgf_version format_class)
Compatibility functions for loaded game that needs game state.
Definition: savecompat.cpp:191
static void compat_load_030100(struct loaddata *loading, enum sgf_version format_class)
Translate savegame secfile data from 3.0.x to 3.1.0 format.
static void insert_server_side_agent(struct loaddata *loading, enum sgf_version format_class)
int current_compat_ver()
Return current compatibility version.
Definition: savecompat.cpp:220
static const char * revolentype_str(enum revolen_type type)
Return string representation of revolentype.
Definition: savecompat.cpp:666
#define compat_current
Definition: savecompat.cpp:131
#define sg_check_ret(...)
Definition: savecompat.h:134
#define sg_warn(condition, message,...)
Definition: savecompat.h:143
tile_special_type
Definition: savecompat.h:28
@ S_LAST
Definition: savecompat.h:37
#define hex_chars
Definition: savecompat.h:176
#define sg_failure_ret_val(condition, _val, message,...)
Definition: savecompat.h:164
#define sg_failure_ret(condition, message,...)
Definition: savecompat.h:158
#define ORDER_OLD_BUILD_WONDER
Definition: savecompat.h:197
sgf_version
Definition: savecompat.h:26
@ SAVEGAME_2
Definition: savecompat.h:26
@ SAVEGAME_3
Definition: savecompat.h:26
#define ORDER_OLD_BUILD_CITY
Definition: savecompat.h:195
#define ORDER_OLD_DISBAND
Definition: savecompat.h:196
#define log_sg
Definition: savecompat.h:132
#define ORDER_OLD_HOMECITY
Definition: savecompat.h:199
#define ORDER_OLD_TRADE_ROUTE
Definition: savecompat.h:198
#define ARRAY_SIZE(x)
Definition: shared.h:79
#define MAX(x, y)
Definition: shared.h:48
const char * specialist_rule_name(const struct specialist *sp)
Return the (untranslated) rule name of the specialist type.
Definition: specialist.cpp:142
struct specialist * specialist_by_number(const Specialist_type_id id)
Return the specialist pointer for the given number.
Definition: specialist.cpp:92
Specialist_type_id specialist_count()
Return the number of specialist_types.
Definition: specialist.cpp:63
#define specialist_type_iterate_end
Definition: specialist.h:73
#define specialist_type_iterate(sp)
Definition: specialist.h:67
size_t size
Definition: specvec.h:64
Definition: city.h:291
struct civ_map::@39::@41 server
const load_version_func_t post_load
Definition: savecompat.cpp:94
const load_version_func_t load
Definition: savecompat.cpp:93
int version
Definition: savecompat.h:46
size_t size
Definition: savecompat.h:51
struct loaddata::@104 action
struct section_file * file
Definition: savecompat.h:44
struct name_translation name
Definition: specialist.h:25
Definition: tile.h:42
int index
Definition: tile.h:43
enum unit_activity activity
Definition: unit.h:81
enum unit_orders order
Definition: unit.h:80
int action
Definition: unit.h:87
enum direction8 dir
Definition: unit.h:89
int target
Definition: unit.h:84
Definition: unit.h:134
int length
Definition: unit.h:192
int index
Definition: unit.h:192
struct unit_order * list
Definition: unit.h:195
struct unit::@75 orders
struct civ_map map
Definition: world_object.h:21
int fc_snprintf(char *str, size_t n, const char *format,...)
See also fc_utf8_snprintf_trunc(), fc_utf8_snprintf_rep().
Definition: support.cpp:537
int fc_strcasecmp(const char *str0, const char *str1)
Compare strings like strcmp(), but ignoring case.
Definition: support.cpp:89
#define sz_strlcpy(dest, src)
Definition: support.h:140
#define fc_strdup(str)
Definition: support.h:111
#define sz_strlcat(dest, src)
Definition: support.h:142
int team_slot_count()
Returns the total number of team slots (including used slots).
Definition: team.cpp:101
char terrain_identifier(const struct terrain *pterrain)
Return the terrain identifier.
Definition: terrain.cpp:98
const char * terrain_rule_name(const struct terrain *pterrain)
Return the (untranslated) rule name of the terrain.
Definition: terrain.cpp:184
#define terrain_type_iterate(_p)
Definition: terrain.h:331
#define terrain_type_iterate_end
Definition: terrain.h:337
struct city * tile_city(const struct tile *ptile)
Return the city on this tile (or nullptr), checking for city center.
Definition: tile.cpp:72
bool unit_can_do_action(const struct unit *punit, const action_id act_id)
Return TRUE iff this unit can do the specified generalized (ruleset defined) action enabler controlle...
Definition: unit.cpp:309
void set_unit_activity_targeted(struct unit *punit, enum unit_activity new_activity, struct extra_type *new_target)
assign a new targeted task to a unit.
Definition: unit.cpp:1028
bool unit_has_orders(const struct unit *punit)
Return TRUE iff the unit is following client-side orders.
Definition: unit.cpp:195
#define unit_tile(_pu)
Definition: unit.h:371
@ ORDER_ACTIVITY
Definition: unit.h:35
@ ORDER_PERFORM_ACTION
Definition: unit.h:41
#define unit_owner(_pu)
Definition: unit.h:370
#define unit_list_iterate(unitlist, punit)
Definition: unitlist.h:25
#define unit_list_iterate_end
Definition: unitlist.h:27
void unit_assign_specific_activity_target(struct unit *punit, enum unit_activity *activity, struct extra_type **target)
For some activities (currently only pillaging), the precise target can be assigned by the server rath...
Definition: unittools.cpp:1105
const struct unit_type * unit_type_get(const struct unit *punit)
Return the unit type for this unit.
Definition: unittype.cpp:114
bool utype_is_moved_to_tgt_by_action(const struct action *paction, const struct unit_type *utype)
Returns TRUE iff successfully performing the specified action always will move the actor unit of the ...
Definition: unittype.cpp:969
bool utype_is_unmoved_by_action(const struct action *paction, const struct unit_type *utype)
Returns TRUE iff successfully performing the specified action never will move the actor unit from its...
Definition: unittype.cpp:1009