1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
15 #include <fc_config.h>
19 #include "capability.h"
23 #include "specialist.h"
28 #include "savecompat.h"
32 static char *special_names
[] =
34 "Irrigation", "Mine", "Pollution", "Hut", "Farmland",
39 For each savefile format after 2.3.0, compatibility functions are defined
40 which translate secfile structures from previous version to that version;
41 all necessary compat functions are called in order to
42 translate between the file and current version. See sg_load_compat().
44 The integer version ID should be increased every time the format is changed.
45 If the change is not backwards compatible, please state the changes in the
46 following list and update the compat functions at the end of this file.
48 - what was added / removed
49 - when was it added / removed (date and version)
50 - when can additional capability checks be set to mandatory (version)
51 - which compatibility checks are needed and till when (version)
53 freeciv | what | date | id
54 --------+------------------------------------------------+------------+----
55 current | (mapped to current savegame format) | ----/--/-- | 0
56 | first version (svn17538) | 2010/07/05 | -
57 2.3.0 | 2.3.0 release | 2010/11/?? | 3
58 2.4.0 | 2.4.0 release | 201./../.. | 10
59 | * player ai type | |
62 | * save player color | |
63 | * "known" info format change | |
64 2.5.0 | 2.5.0 release | 201./../.. | 20
65 2.6.0 | 2.6.0 release | 201./../.. | 30
66 3.0.0 | 3.0.0 release | 201./../.. | 40
67 3.1.0 | 3.0.0 release (development) | 201./../.. | 50
71 static void compat_load_020400(struct loaddata
*loading
, enum sgf_version format_class
);
72 static void compat_load_020500(struct loaddata
*loading
, enum sgf_version format_class
);
73 static void compat_load_020600(struct loaddata
*loading
, enum sgf_version format_class
);
74 static void compat_load_030000(struct loaddata
*loading
, enum sgf_version format_class
);
75 static void compat_load_030100(struct loaddata
*loading
, enum sgf_version format_class
);
77 #ifdef FREECIV_DEV_SAVE_COMPAT
78 static void compat_load_dev(struct loaddata
*loading
);
79 #endif /* FREECIV_DEV_SAVE_COMPAT */
81 typedef void (*load_version_func_t
) (struct loaddata
*loading
, enum sgf_version format_class
);
83 struct compatibility
{
85 const load_version_func_t load
;
88 /* The struct below contains the information about the savegame versions. It
89 * is identified by the version number (first element), which should be
90 * steadily increasing. It is saved as 'savefile.version'. The support
91 * string (first element of 'name') is not saved in the savegame; it is
92 * saved in settings files (so, once assigned, cannot be changed). The
93 * 'pretty' string (second element of 'name') can be changed if necessary
94 * For changes in the development version, edit the definitions above and
95 * add the needed code to load the old version below. Thus, old
96 * savegames can still be loaded while the main definition
97 * represents the current state of the art. */
98 /* While developing freeciv 3.1.0, add the compatibility functions to
99 * - compat_load_030100 to load old savegame. */
100 static struct compatibility compat
[] = {
101 /* dummy; equal to the current version (last element) */
103 /* version 1 and 2 is not used */
104 /* version 3: first savegame2 format, so no compat functions for translation
105 * from previous format */
107 /* version 4 to 9 are reserved for possible changes in 2.3.x */
108 { 10, compat_load_020400
},
109 /* version 11 to 19 are reserved for possible changes in 2.4.x */
110 { 20, compat_load_020500
},
111 /* version 21 to 29 are reserved for possible changes in 2.5.x */
112 { 30, compat_load_020600
},
113 /* version 31 to 39 are reserved for possible changes in 2.6.x */
114 { 40, compat_load_030000
},
115 /* version 41 to 49 are reserved for possible changes in 3.0.x */
116 { 50, compat_load_030100
},
117 /* Current savefile version is listed above this line; it corresponds to
118 the definitions in this file. */
121 static const int compat_num
= ARRAY_SIZE(compat
);
122 #define compat_current (compat_num - 1)
124 /****************************************************************************
125 Compatibility functions for loaded game.
127 This function is called at the beginning of loading a savegame. The data in
128 loading->file should be change such, that the current loading functions can
129 be executed without errors.
130 ****************************************************************************/
131 void sg_load_compat(struct loaddata
*loading
, enum sgf_version format_class
)
135 /* Check status and return if not OK (sg_success != TRUE). */
138 loading
->version
= secfile_lookup_int_default(loading
->file
, -1,
141 sg_failure_ret(0 < loading
->version
, "Invalid savefile format version (%d).",
143 if (loading
->version
> compat
[compat_current
].version
) {
144 /* Debug build can (TRY TO!) load newer versions but ... */
145 log_error("Savegame version newer than this build found (%d > %d). "
146 "Trying to load the game nevertheless ...", loading
->version
,
147 compat
[compat_current
].version
);
149 #else /* FREECIV_DEBUG */
150 sg_failure_ret(0 < loading
->version
151 && loading
->version
<= compat
[compat_current
].version
,
152 "Unknown savefile format version (%d).", loading
->version
);
153 #endif /* FREECIV_DEBUG */
156 for (i
= 0; i
< compat_num
; i
++) {
157 if (loading
->version
< compat
[i
].version
&& compat
[i
].load
!= NULL
) {
158 log_normal(_("Run compatibility function for version: <%d "
159 "(save file: %d; server: %d)."), compat
[i
].version
,
160 loading
->version
, compat
[compat_current
].version
);
161 compat
[i
].load(loading
, format_class
);
165 #ifdef FREECIV_DEV_SAVE_COMPAT
166 if (loading
->version
== compat
[compat_current
].version
167 #ifdef FREECIV_DEV_SAVE_COMPAT_3_0
168 /* Make use of 3.0 compatibility while it is there. */
169 || loading
->version
== 40
170 #endif /* FREECIV_DEV_SAVE_COMPAT_3_0 */
172 compat_load_dev(loading
);
174 #endif /* FREECIV_DEV_SAVE_COMPAT */
177 /****************************************************************************
178 Return current compatibility version
179 ****************************************************************************/
180 int current_compat_ver(void)
182 return compat
[compat_current
].version
;
185 /****************************************************************************
186 This returns an ascii hex value of the given half-byte of the binary
187 integer. See ascii_hex2bin().
188 example: bin2ascii_hex(0xa00, 2) == 'a'
189 ****************************************************************************/
190 char bin2ascii_hex(int value
, int halfbyte_wanted
)
192 return hex_chars
[((value
) >> ((halfbyte_wanted
) * 4)) & 0xf];
195 /****************************************************************************
196 This returns a binary integer value of the ascii hex char, offset by the
197 given number of half-bytes. See bin2ascii_hex().
198 example: ascii_hex2bin('a', 2) == 0xa00
199 This is only used in loading games, and it requires some error checking so
200 it's done as a function.
201 ****************************************************************************/
202 int ascii_hex2bin(char ch
, int halfbyte
)
207 /* Sane value. It is unknow if there are savegames out there which
208 * need this fix. Savegame.c doesn't write such savegames
209 * (anymore) since the inclusion into CVS (2000-08-25). */
213 pch
= strchr(hex_chars
, ch
);
215 sg_failure_ret_val(NULL
!= pch
&& '\0' != ch
, 0,
216 "Unknown hex value: '%c' %d", ch
, ch
);
217 return (pch
- hex_chars
) << (halfbyte
* 4);
220 /****************************************************************************
221 Return the special with the given name, or S_LAST.
222 ****************************************************************************/
223 enum tile_special_type
special_by_rule_name(const char *name
)
227 for (i
= 0; special_names
[i
] != NULL
; i
++) {
228 if (!strcmp(name
, special_names
[i
])) {
236 /****************************************************************************
237 Return the untranslated name of the given special.
238 ****************************************************************************/
239 const char *special_rule_name(enum tile_special_type type
)
241 fc_assert(type
>= 0 && type
< S_LAST
);
243 return special_names
[type
];
246 /****************************************************************************
247 Get extra of the given special
248 ****************************************************************************/
249 struct extra_type
*special_extra_get(int spe
)
251 struct extra_type_list
*elist
= extra_type_list_by_cause(EC_SPECIAL
);
253 if (spe
< extra_type_list_size(elist
)) {
254 return extra_type_list_get(elist
, spe
);
260 /****************************************************************************
261 Return the resource type matching the identifier, or NULL when none matches.
262 ****************************************************************************/
263 struct extra_type
*resource_by_identifier(const char identifier
)
265 extra_type_by_cause_iterate(EC_RESOURCE
, presource
) {
266 if (presource
->data
.resource
->id_old_save
== identifier
) {
269 } extra_type_by_cause_iterate_end
;
274 /* =======================================================================
275 * Compatibility functions for loading a game.
276 * ======================================================================= */
278 /****************************************************************************
279 Translate savegame secfile data from 2.3.x to 2.4.0 format.
280 ****************************************************************************/
281 static void compat_load_020400(struct loaddata
*loading
,
282 enum sgf_version format_class
)
284 /* Check status and return if not OK (sg_success != TRUE). */
287 log_debug("Upgrading data from savegame to version 2.4.0");
289 /* Add the default player AI. */
290 player_slots_iterate(pslot
) {
291 int ncities
, i
, plrno
= player_slot_index(pslot
);
293 if (NULL
== secfile_section_lookup(loading
->file
, "player%d", plrno
)) {
297 secfile_insert_str(loading
->file
, default_ai_type_name(),
298 "player%d.ai_type", player_slot_index(pslot
));
300 /* Create dummy citizens informations. We do not know if citizens are
301 * activated due to the fact that this information
302 * (game.info.citizen_nationality) is not available, but adding the
303 * information does no harm. */
304 ncities
= secfile_lookup_int_default(loading
->file
, 0,
305 "player%d.ncities", plrno
);
307 for (i
= 0; i
< ncities
; i
++) {
308 int size
= secfile_lookup_int_default(loading
->file
, 0,
309 "player%d.c%d.size", plrno
, i
);
311 secfile_insert_int(loading
->file
, size
,
312 "player%d.c%d.citizen%d", plrno
, i
, plrno
);
317 } player_slots_iterate_end
;
319 /* Player colors are assigned at the end of player loading, as this
320 * needs information not available here. */
322 /* Deal with buggy known tiles information from 2.3.0/2.3.1 (and the
323 * workaround in later 2.3.x); see gna bug #19029.
324 * (The structure of this code is odd as it avoids relying on knowledge of
325 * xsize/ysize, which haven't been extracted from the savefile yet.) */
327 if (has_capability("knownv2",
328 secfile_lookup_str(loading
->file
, "savefile.options"))) {
329 /* This savefile contains known information in a sane format.
330 * Just move any entries to where 2.4.x+ expect to find them. */
331 struct section
*map
= secfile_section_by_name(loading
->file
, "map");
333 entry_list_iterate(section_entries(map
), pentry
) {
334 const char *name
= entry_name(pentry
);
335 if (strncmp(name
, "kvb", 3) == 0) {
336 /* Rename the "kvb..." entry to "k..." */
337 char *name2
= fc_strdup(name
), *newname
= name2
+ 2;
339 /* Savefile probably contains existing "k" entries, which are bogus
340 * so we trash them */
341 secfile_entry_delete(loading
->file
, "map.%s", newname
);
342 entry_set_name(pentry
, newname
);
345 } entry_list_iterate_end
;
347 /* Could remove "knownv2" from savefile.options, but it's doing
350 /* This savefile only contains known information in the broken
351 * format. Try to recover it to a sane format. */
352 /* MAX_NUM_PLAYER_SLOTS in 2.3.x was 128 */
353 /* MAP_MAX_LINEAR_SIZE in 2.3.x was 512 */
354 const int maxslots
= 128, maxmapsize
= 512;
355 const int lines
= maxslots
/32;
356 int xsize
= 0, y
, l
, j
, x
;
357 unsigned int known_row_old
[lines
* maxmapsize
],
358 known_row
[lines
* maxmapsize
];
359 /* Process a map row at a time */
360 for (y
= 0; y
< maxmapsize
; y
++) {
361 /* Look for broken info to convert */
363 memset(known_row_old
, 0, sizeof(known_row_old
));
364 for (l
= 0; l
< lines
; l
++) {
365 for (j
= 0; j
< 8; j
++) {
367 secfile_lookup_str_default(loading
->file
, NULL
,
368 "map.k%02d_%04d", l
* 8 + j
, y
);
374 sg_failure_ret(xsize
== strlen(s
),
375 "Inconsistent xsize in map.k%02d_%04d",
377 for (x
= 0; x
< xsize
; x
++) {
378 known_row_old
[l
* xsize
+ x
] |= ascii_hex2bin(s
[x
], j
);
384 /* At least one entry found for this row. Let's hope they were
386 /* Attempt to munge into sane format */
388 memset(known_row
, 0, sizeof(known_row
));
389 /* Iterate over possible player slots */
390 for (p
= 0; p
< maxslots
; p
++) {
392 for (x
= 0; x
< xsize
; x
++) {
393 /* This test causes bit-shifts of >=32 (undefined behaviour), but
394 * on common platforms, information happens not to be lost, just
396 if (known_row_old
[l
* xsize
+ x
] & (1u << (p
- l
* 8))) {
397 known_row
[l
* xsize
+ x
] |= (1u << (p
- l
* 32));
401 /* Save sane format back to memory representation of secfile for
402 * real loading code to pick up */
403 for (l
= 0; l
< lines
; l
++) {
404 for (j
= 0; j
< 8; j
++) {
405 /* Save info for all slots (not just used ones). It's only
406 * memory, after all. */
408 for (x
= 0; x
< xsize
; x
++) {
409 row
[x
] = bin2ascii_hex(known_row
[l
* xsize
+ x
], j
);
412 secfile_replace_str(loading
->file
, row
,
413 "map.k%02d_%04d", l
* 8 + j
, y
);
421 /* Server setting migration. */
424 if (secfile_lookup_int(loading
->file
, &set_count
, "settings.set_count")) {
425 int i
, new_opt
= set_count
;
427 = secfile_lookup_bool_default(loading
->file
, FALSE
,
428 "settings.gamestart_valid");
429 for (i
= 0; i
< set_count
; i
++) {
431 = secfile_lookup_str(loading
->file
, "settings.set%d.name", i
);
436 /* In 2.3.x and prior, saveturns=0 meant no turn-based saves.
437 * This is now controlled by the "autosaves" setting. */
438 if (!fc_strcasecmp("saveturns", name
)) {
439 /* XXX: hardcodes details from GAME_AUTOSAVES_DEFAULT
440 * and settings.c:autosaves_name() (but these defaults reflect
441 * 2.3's behaviour). */
442 const char *const nosave
= "GAMEOVER|QUITIDLE|INTERRUPT";
443 const char *const save
= "TURN|GAMEOVER|QUITIDLE|INTERRUPT";
446 if (secfile_lookup_int(loading
->file
, &nturns
,
447 "settings.set%d.value", i
)) {
449 /* Invent a new "autosaves" setting */
450 secfile_insert_str(loading
->file
, nosave
,
451 "settings.set%d.value", new_opt
);
452 /* Pick something valid for saveturns */
453 secfile_replace_int(loading
->file
, GAME_DEFAULT_SAVETURNS
,
454 "settings.set%d.value", i
);
456 secfile_insert_str(loading
->file
, save
,
457 "settings.set%d.value", new_opt
);
460 log_sg("Setting '%s': %s", name
, secfile_error());
462 if (gamestart_valid
) {
463 if (secfile_lookup_int(loading
->file
, &nturns
,
464 "settings.set%d.gamestart", i
)) {
466 /* Invent a new "autosaves" setting */
467 secfile_insert_str(loading
->file
, nosave
,
468 "settings.set%d.gamestart", new_opt
);
469 /* Pick something valid for saveturns */
470 secfile_replace_int(loading
->file
, GAME_DEFAULT_SAVETURNS
,
471 "settings.set%d.gamestart", i
);
473 secfile_insert_str(loading
->file
, save
,
474 "settings.set%d.gamestart", new_opt
);
477 log_sg("Setting '%s': %s", name
, secfile_error());
480 } else if (!fc_strcasecmp("autosaves", name
)) {
481 /* Sanity check. This won't trigger on an option we've just
482 * invented, as the loop won't include it. */
483 log_sg("Unexpected \"autosaves\" setting found in pre-2.4 "
484 "savefile. It may have been overridden.");
491 /****************************************************************************
492 Callback to get name of old killcitizen setting bit.
493 ****************************************************************************/
494 static const char *killcitizen_enum_str(secfile_data_t data
, int bit
)
508 /****************************************************************************
509 Translate savegame secfile data from 2.4.x to 2.5.0 format.
510 ****************************************************************************/
511 static void compat_load_020500(struct loaddata
*loading
,
512 enum sgf_version format_class
)
514 const char *modname
[] = { "Road", "Railroad" };
515 const char *old_activities_names
[] = {
539 /* Check status and return if not OK (sg_success != TRUE). */
542 log_debug("Upgrading data from savegame to version 2.5.0");
544 secfile_insert_int(loading
->file
, 2, "savefile.roads_size");
545 secfile_insert_int(loading
->file
, 0, "savefile.trait_size");
547 secfile_insert_str_vec(loading
->file
, modname
, 2,
548 "savefile.roads_vector");
550 secfile_insert_int(loading
->file
, 19, "savefile.activities_size");
551 secfile_insert_str_vec(loading
->file
, old_activities_names
, 19,
552 "savefile.activities_vector");
554 /* Server setting migration. */
558 if (secfile_lookup_int(loading
->file
, &set_count
, "settings.set_count")) {
561 = secfile_lookup_bool_default(loading
->file
, FALSE
,
562 "settings.gamestart_valid");
563 for (i
= 0; i
< set_count
; i
++) {
565 = secfile_lookup_str(loading
->file
, "settings.set%d.name", i
);
569 /* In 2.4.x and prior, "killcitizen" listed move types that
570 * killed citizens after succesfull attack. Now killcitizen
571 * is just boolean and classes affected are defined in ruleset. */
572 if (!fc_strcasecmp("killcitizen", name
)) {
575 if (secfile_lookup_enum_data(loading
->file
, &value
, TRUE
,
576 killcitizen_enum_str
, NULL
,
577 "settings.set%d.value", i
)) {
578 /* Lowest bit of old killcitizen value indicates if
579 * land units should kill citizens. We take that as
580 * new boolean killcitizen value. */
582 secfile_replace_bool(loading
->file
, TRUE
,
583 "settings.set%d.value", i
);
585 secfile_replace_bool(loading
->file
, FALSE
,
586 "settings.set%d.value", i
);
589 log_sg("Setting '%s': %s", name
, secfile_error());
591 if (gamestart_valid
) {
592 if (secfile_lookup_enum_data(loading
->file
, &value
, TRUE
,
593 killcitizen_enum_str
, NULL
,
594 "settings.set%d.gamestart", i
)) {
595 /* Lowest bit of old killcitizen value indicates if
596 * land units should kill citizens. We take that as
597 * new boolean killcitizen value. */
599 secfile_replace_bool(loading
->file
, TRUE
,
600 "settings.set%d.gamestart", i
);
602 secfile_replace_bool(loading
->file
, FALSE
,
603 "settings.set%d.gamestart", i
);
606 log_sg("Setting '%s': %s", name
, secfile_error());
615 /****************************************************************************
616 Return string representation of revolentype
617 ****************************************************************************/
618 static char *revolentype_str(enum revolen_type type
)
625 case REVOLEN_QUICKENING
:
627 case REVOLEN_RANDQUICK
:
634 /****************************************************************************
635 Translate savegame secfile data from 2.5.x to 2.6.0 format.
636 ****************************************************************************/
637 static void compat_load_020600(struct loaddata
*loading
,
638 enum sgf_version format_class
)
640 bool team_pooled_research
= GAME_DEFAULT_TEAM_POOLED_RESEARCH
;
645 /* Check status and return if not OK (sg_success != TRUE). */
648 log_debug("Upgrading data from savegame to version 2.6.0");
650 /* Terrain mapping table - use current ruleset as we have no way to know
651 * any other old values. */
653 terrain_type_iterate(pterr
) {
656 secfile_insert_str(loading
->file
, terrain_rule_name(pterr
), "savefile.terrident%d.name", ti
);
657 buf
[0] = terrain_identifier(pterr
);
659 secfile_insert_str(loading
->file
, buf
, "savefile.terrident%d.identifier", ti
++);
660 } terrain_type_iterate_end
;
662 /* Server setting migration. */
666 if (secfile_lookup_int(loading
->file
, &set_count
, "settings.set_count")) {
667 char value_buffer
[1024] = "";
668 char gamestart_buffer
[1024] = "";
672 enum revolen_type rlt
= GAME_DEFAULT_REVOLENTYPE
;
673 enum revolen_type gsrlt
= GAME_DEFAULT_REVOLENTYPE
;
675 = secfile_lookup_bool_default(loading
->file
, FALSE
,
676 "settings.gamestart_valid");
679 for (i
= 0; i
< set_count
; i
++) {
681 = secfile_lookup_str(loading
->file
, "settings.set%d.name", i
);
686 /* In 2.5.x and prior, "spacerace" boolean controlled if
687 * spacerace victory condition was active. */
688 if (!fc_strcasecmp("spacerace", name
)) {
691 if (secfile_lookup_bool(loading
->file
, &value
,
692 "settings.set%d.value", i
)) {
694 sz_strlcat(value_buffer
, "|SPACERACE");
697 log_sg("Setting '%s': %s", name
, secfile_error());
699 if (secfile_lookup_bool(loading
->file
, &value
,
700 "settings.set%d.gamestart", i
)) {
702 sz_strlcat(gamestart_buffer
, "|SPACERACE");
705 log_sg("Setting '%s': %s", name
, secfile_error());
708 /* We cannot delete old values from the secfile, or rather cannot
709 * change index of the later settings. Renumbering them is not easy as
710 * we don't know type of each setting we would encounter.
711 * So we keep old setting values and only add new "victories" setting. */
712 } else if (!fc_strcasecmp("alliedvictory", name
)) {
715 if (secfile_lookup_bool(loading
->file
, &value
,
716 "settings.set%d.value", i
)) {
718 sz_strlcat(value_buffer
, "|ALLIED");
721 log_sg("Setting '%s': %s", name
, secfile_error());
723 if (secfile_lookup_bool(loading
->file
, &value
,
724 "settings.set%d.gamestart", i
)) {
726 sz_strlcat(gamestart_buffer
, "|ALLIED");
729 log_sg("Setting '%s': %s", name
, secfile_error());
731 } else if (!fc_strcasecmp("revolen", name
)) {
734 if (secfile_lookup_int(loading
->file
, &value
,
735 "settings.set%d.value", i
)) {
736 /* 0 meant RANDOM 1-5 */
738 rlt
= REVOLEN_RANDOM
;
739 secfile_replace_int(loading
->file
, 5,
740 "settings.set%d.value", i
);
745 log_sg("Setting '%s': %s", name
, secfile_error());
747 if (secfile_lookup_int(loading
->file
, &value
,
748 "settings.set%d.gamestart", i
)) {
749 /* 0 meant RANDOM 1-5 */
751 gsrlt
= REVOLEN_RANDOM
;
752 secfile_replace_int(loading
->file
, 5,
753 "settings.set%d.gamestart", i
);
755 gsrlt
= REVOLEN_FIXED
;
758 log_sg("Setting '%s': %s", name
, secfile_error());
760 } else if (!fc_strcasecmp("happyborders", name
)) {
763 if (secfile_lookup_bool(loading
->file
, &value
,
764 "settings.set%d.value", i
)) {
765 secfile_entry_delete(loading
->file
, "settings.set%d.value", i
);
767 secfile_insert_str(loading
->file
, "NATIONAL",
768 "settings.set%d.value", i
);
770 secfile_insert_str(loading
->file
, "DISABLED",
771 "settings.set%d.value", i
);
774 log_sg("Setting '%s': %s", name
, secfile_error());
776 if (secfile_lookup_bool(loading
->file
, &value
,
777 "settings.set%d.gamestart", i
)) {
778 secfile_entry_delete(loading
->file
, "settings.set%d.gamestart", i
);
780 secfile_insert_str(loading
->file
, "NATIONAL",
781 "settings.set%d.gamestart", i
);
783 secfile_insert_str(loading
->file
, "DISABLED",
784 "settings.set%d.gamestart", i
);
787 log_sg("Setting '%s': %s", name
, secfile_error());
789 } else if (!fc_strcasecmp("team_pooled_research", name
)) {
790 sg_warn(secfile_lookup_bool(loading
->file
,
791 &team_pooled_research
,
792 "settings.set%d.value", i
),
793 "%s", secfile_error());
794 } else if (!fc_strcasecmp("diplcost", name
)) {
795 /* Old 'diplcost' split to 'diplbulbcost' and 'diplgoldcost' */
796 if (secfile_lookup_int(loading
->file
, &dcost
,
797 "settings.set%d.value", i
)) {
799 log_sg("Setting '%s': %s", name
, secfile_error());
802 if (secfile_lookup_int(loading
->file
, &dstartcost
,
803 "settings.set%d.gamestart", i
)) {
805 log_sg("Setting '%s': %s", name
, secfile_error());
807 } else if (!fc_strcasecmp("huts", name
)) {
808 /* Scale of 'huts' changed. */
811 if (secfile_lookup_int(loading
->file
, &hcount
,
812 "settings.set%d.value", i
)) {
814 log_sg("Setting '%s': %s", name
, secfile_error());
817 /* Store old-style absolute value. */
818 wld
.map
.server
.huts_absolute
= hcount
;
822 new_set_count
= set_count
+ 2; /* 'victories' and 'revolentype' */
828 secfile_replace_int(loading
->file
, new_set_count
, "settings.set_count");
830 secfile_insert_str(loading
->file
, "victories", "settings.set%d.name",
832 secfile_insert_str(loading
->file
, value_buffer
, "settings.set%d.value",
834 secfile_insert_str(loading
->file
, "revolentype", "settings.set%d.name",
836 secfile_insert_str(loading
->file
, revolentype_str(rlt
), "settings.set%d.value",
840 secfile_insert_str(loading
->file
, "diplbulbcost", "settings.set%d.name", set_count
+ 2);
841 secfile_insert_int(loading
->file
, dcost
, "settings.set%d.value", set_count
+ 2);
842 secfile_insert_str(loading
->file
, "diplgoldcost", "settings.set%d.name", set_count
+ 3);
843 secfile_insert_int(loading
->file
, dcost
, "settings.set%d.value", set_count
+ 3);
846 if (gamestart_valid
) {
847 secfile_insert_str(loading
->file
, gamestart_buffer
, "settings.set%d.gamestart",
849 secfile_insert_str(loading
->file
, revolentype_str(gsrlt
), "settings.set%d.gamestart",
853 secfile_insert_int(loading
->file
, dstartcost
, "settings.set%d.gamestart", set_count
+ 2);
854 secfile_insert_int(loading
->file
, dstartcost
, "settings.set%d.gamestart", set_count
+ 3);
860 sg_failure_ret(secfile_lookup_int(loading
->file
, &tsize
, "savefile.trait_size"),
861 "Trait size: %s", secfile_error());
863 turn
= secfile_lookup_int_default(loading
->file
, 0, "game.turn");
865 player_slots_iterate(pslot
) {
866 int plrno
= player_slot_index(pslot
);
869 enum barbarian_type new_barb_type
;
875 if (NULL
== secfile_section_lookup(loading
->file
, "player%d", plrno
)) {
879 /* Renamed 'capital' to 'got_first_city'. */
880 if (secfile_lookup_bool(loading
->file
, &got_first_city
,
881 "player%d.capital", plrno
)) {
882 secfile_insert_bool(loading
->file
, got_first_city
,
883 "player%d.got_first_city", plrno
);
886 /* Add 'anonymous' qualifiers for user names */
887 name
= secfile_lookup_str_default(loading
->file
, "", "player%d.username", plrno
);
888 secfile_insert_bool(loading
->file
, (!strcmp(name
, ANON_USER_NAME
)),
889 "player%d.unassigned_user", plrno
);
891 name
= secfile_lookup_str_default(loading
->file
, "", "player%d.ranked_username", plrno
);
892 secfile_insert_bool(loading
->file
, (!strcmp(name
, ANON_USER_NAME
)),
893 "player%d.unassigned_ranked", plrno
);
895 /* Convert numeric barbarian type to textual */
896 old_barb_type
= secfile_lookup_int_default(loading
->file
, 0,
897 "player%d.ai.is_barbarian", plrno
);
898 new_barb_type
= barb_type_convert(old_barb_type
);
899 secfile_insert_str(loading
->file
, barbarian_type_name(new_barb_type
),
900 "player%d.ai.barb_type", plrno
);
902 /* Pre-2.6 didn't record when a player was created or died, so we have
903 * to assume they lived from the start of the game until last turn */
904 secfile_insert_int(loading
->file
, turn
, "player%d.turns_alive", plrno
);
906 /* As if there never has been a war. */
907 secfile_insert_int(loading
->file
, -1, "player%d.last_war", plrno
);
909 /* Assume people were playing until current reload */
910 secfile_insert_int(loading
->file
, 0, "player%d.idle_turns", plrno
);
912 for (i
= 0; i
< tsize
; i
++) {
915 val
= secfile_lookup_int_default(loading
->file
, -1, "player%d.trait.val%d",
918 secfile_insert_int(loading
->file
, val
, "player%d.trait%d.val", plrno
, i
);
921 sg_failure_ret(secfile_lookup_int(loading
->file
, &val
,
922 "player%d.trait.mod%d", plrno
, i
),
923 "Trait mod: %s", secfile_error());
924 secfile_insert_int(loading
->file
, val
, "player%d.trait%d.mod", plrno
, i
);
927 score
= secfile_lookup_int_default(loading
->file
, -1,
928 "player%d.units_built", plrno
);
930 secfile_insert_int(loading
->file
, score
, "score%d.units_built", plrno
);
933 score
= secfile_lookup_int_default(loading
->file
, -1,
934 "player%d.units_killed", plrno
);
936 secfile_insert_int(loading
->file
, score
, "score%d.units_killed", plrno
);
939 score
= secfile_lookup_int_default(loading
->file
, -1,
940 "player%d.units_lost", plrno
);
942 secfile_insert_int(loading
->file
, score
, "score%d.units_lost", plrno
);
946 units_num
= secfile_lookup_int_default(loading
->file
, 0,
950 for (i
= 0; i
< units_num
; i
++) {
953 if (secfile_lookup_bool_default(loading
->file
, FALSE
,
954 "player%d.u%d.orders_last_move_safe",
959 len
= secfile_lookup_int_default(loading
->file
, 0,
960 "player%d.u%d.orders_length",
963 char orders_str
[len
+ 1];
966 sz_strlcpy(orders_str
,
967 secfile_lookup_str_default(loading
->file
, "",
968 "player%d.u%d.orders_list",
970 if ((p
= strrchr(orders_str
, 'm'))
971 || (p
= strrchr(orders_str
, 'M'))) {
972 *p
= 'x'; /* ORDER_MOVE -> ORDER_ACTION_MOVE */
973 secfile_replace_str(loading
->file
, orders_str
,
974 "player%d.u%d.orders_list", plrno
, i
);
978 } player_slots_iterate_end
;
980 /* Add specialist order - loading time order is ok here, as we will use
981 * that when we in later part of compatibility conversion use the specialist
983 secfile_insert_int(loading
->file
, specialist_count(),
984 "savefile.specialists_size");
986 const char **modname
;
989 modname
= fc_calloc(specialist_count(), sizeof(*modname
));
991 specialist_type_iterate(sp
) {
992 modname
[i
++] = specialist_rule_name(specialist_by_number(sp
));
993 } specialist_type_iterate_end
;
995 secfile_insert_str_vec(loading
->file
, modname
, specialist_count(),
996 "savefile.specialists_vector");
1001 /* Replace all city specialist count fields with correct names */
1002 player_slots_iterate(pslot
) {
1003 int plrno
= player_slot_index(pslot
);
1007 if (NULL
== secfile_section_lookup(loading
->file
, "player%d", plrno
)) {
1011 ncities
= secfile_lookup_int_default(loading
->file
, 0, "player%d.ncities", plrno
);
1013 for (i
= 0; i
< ncities
; i
++) {
1016 specialist_type_iterate(sp
) {
1017 struct specialist
*psp
= specialist_by_number(sp
);
1020 sg_failure_ret(secfile_lookup_int(loading
->file
, &count
,
1022 plrno
, i
, specialist_rule_name(psp
)),
1023 "specialist error: %s", secfile_error());
1024 secfile_entry_delete(loading
->file
, "player%d.c%d.n%s",
1025 plrno
, i
, specialist_rule_name(psp
));
1026 secfile_insert_int(loading
->file
, count
, "player%d.c%d.nspe%d",
1028 } specialist_type_iterate_end
;
1030 } player_slots_iterate_end
;
1032 /* Build [research]. */
1035 const char *entry_name
;
1036 enum entry_type entry_type
;
1038 { "goal_name", ENTRY_STR
},
1039 { "techs", ENTRY_INT
},
1040 { "futuretech", ENTRY_INT
},
1041 { "bulbs_before", ENTRY_INT
},
1042 { "saved_name", ENTRY_STR
},
1043 { "bulbs", ENTRY_INT
},
1044 { "now_name", ENTRY_STR
},
1045 { "got_tech", ENTRY_BOOL
},
1046 { "done", ENTRY_STR
}
1049 int researches
[MAX(player_slot_count(), team_slot_count())];
1053 for (i
= 0; i
< ARRAY_SIZE(researches
); i
++) {
1057 player_slots_iterate(pslot
) {
1058 int plrno
= player_slot_index(pslot
);
1064 if (secfile_section_lookup(loading
->file
, "player%d", plrno
) == NULL
) {
1068 /* Get the research number. */
1069 if (team_pooled_research
) {
1070 i
= secfile_lookup_int_default(loading
->file
, plrno
,
1071 "player%d.team_no", plrno
);
1076 sg_failure_ret(i
>= 0 && i
< ARRAY_SIZE(researches
),
1077 "Research out of bounds (%d)!", i
);
1079 /* Find the index in [research] section. */
1080 if (researches
[i
] == -1) {
1081 /* This is the first player for this research. */
1082 secfile_insert_int(loading
->file
, i
, "research.r%d.number", count
);
1083 researches
[i
] = count
;
1089 for (j
= 0; j
< ARRAY_SIZE(entries
); j
++) {
1090 switch (entries
[j
].entry_type
) {
1092 if (secfile_lookup_bool(loading
->file
, &bval
,
1093 "player%d.research.%s",
1094 plrno
, entries
[j
].entry_name
)) {
1095 secfile_insert_bool(loading
->file
, bval
, "research.r%d.%s",
1096 i
, entries
[j
].entry_name
);
1100 if (secfile_lookup_int(loading
->file
, &ival
,
1101 "player%d.research.%s",
1102 plrno
, entries
[j
].entry_name
)) {
1103 secfile_insert_int(loading
->file
, ival
, "research.r%d.%s",
1104 i
, entries
[j
].entry_name
);
1108 if ((sval
= secfile_lookup_str(loading
->file
,
1109 "player%d.research.%s",
1110 plrno
, entries
[j
].entry_name
))) {
1111 secfile_insert_str(loading
->file
, sval
, "research.r%d.%s",
1112 i
, entries
[j
].entry_name
);
1116 sg_failure_ret(entries
[j
].entry_type
!= ENTRY_FLOAT
,
1117 "Research related entry marked as float.");
1119 case ENTRY_FILEREFERENCE
:
1120 fc_assert(entries
[j
].entry_type
!= ENTRY_FILEREFERENCE
);
1124 } player_slots_iterate_end
;
1125 secfile_insert_int(loading
->file
, count
, "research.count");
1128 /* Add diplstate type order. */
1129 secfile_insert_int(loading
->file
, DS_LAST
,
1130 "savefile.diplstate_type_size");
1132 const char **modname
;
1137 modname
= fc_calloc(DS_LAST
, sizeof(*modname
));
1139 for (j
= 0; j
< DS_LAST
; j
++) {
1140 modname
[i
++] = diplstate_type_name(j
);
1143 secfile_insert_str_vec(loading
->file
, modname
,
1145 "savefile.diplstate_type_vector");
1149 /* Fix save games from Freeciv versions with a bug that made it view
1150 * "Never met" as closer than "Peace" or "Alliance". */
1151 player_slots_iterate(pslot
) {
1152 int plrno
= player_slot_index(pslot
);
1154 if (NULL
== secfile_section_lookup(loading
->file
, "player%d", plrno
)) {
1158 player_slots_iterate(pslot2
) {
1159 int i
= player_slot_index(pslot2
);
1164 if (NULL
== secfile_section_lookup(loading
->file
, "player%d", i
)) {
1168 fc_snprintf(buf
, sizeof(buf
), "player%d.diplstate%d", plrno
, i
);
1170 /* Read the current diplomatic state. */
1171 current
= secfile_lookup_int_default(loading
->file
, DS_NO_CONTACT
,
1175 /* Read the closest diplomatic state. */
1176 closest
= secfile_lookup_int_default(loading
->file
, DS_NO_CONTACT
,
1180 if (closest
== DS_NO_CONTACT
1181 && (current
== DS_PEACE
1182 || current
== DS_ALLIANCE
)) {
1183 const char *name1
= secfile_lookup_str_default(loading
->file
, "",
1184 "player%d.name", plrno
);
1185 const char *name2
= secfile_lookup_str_default(loading
->file
, "",
1186 "player%d.name", i
);
1187 /* The current relationship is closer than what the save game
1188 * claims is the closes relationship ever. */
1190 log_sg(_("The save game is wrong about what the closest"
1191 " relationship %s (player %d) and %s (player %d) have had is."
1193 name1
, plrno
, name2
, i
);
1195 secfile_replace_int(loading
->file
, current
, "%s.max_state", buf
);
1197 } player_slots_iterate_end
;
1198 } player_slots_iterate_end
;
1201 /****************************************************************************
1202 Increase turn value in secfile by one.
1203 ****************************************************************************/
1204 static int increase_secfile_turn_int(struct loaddata
*loading
, const char *key
,
1205 int old_def
, bool keep_default
)
1209 value
= secfile_lookup_int_default(loading
->file
, old_def
, "%s", key
);
1211 if (value
!= old_def
|| !keep_default
) {
1213 secfile_replace_int(loading
->file
, value
, "%s", key
);
1219 /****************************************************************************
1220 Translate savegame secfile data from 2.6.x to 3.0.0 format.
1221 Note that even after 2.6 savegame has gone through this compatibility
1222 function, it's still 2.6 savegame in the sense that savegame2.c, and not
1223 savegame3.c, handles it.
1224 ****************************************************************************/
1225 static void compat_load_030000(struct loaddata
*loading
,
1226 enum sgf_version format_class
)
1233 /* Check status and return if not OK (sg_success != TRUE). */
1236 log_debug("Upgrading data from savegame to version 3.0.0");
1238 /* Rename "random.save" as "random.saved" */
1239 if (secfile_lookup_bool(loading
->file
, &randsaved
, "random.save")) {
1240 secfile_insert_bool(loading
->file
, randsaved
, "random.saved");
1242 log_sg("random.save: %s", secfile_error());
1245 /* Already started games should have their turn counts increased by 1 */
1246 if (secfile_lookup_bool_default(loading
->file
, TRUE
, "game.save_players")) {
1249 old_turn
= increase_secfile_turn_int(loading
, "game.turn", 0, FALSE
) - 1;
1250 increase_secfile_turn_int(loading
, "game.scoreturn", old_turn
+ GAME_DEFAULT_SCORETURN
, FALSE
);
1251 increase_secfile_turn_int(loading
, "history.turn", -2, TRUE
);
1256 player_slots_iterate(pslot
) {
1257 int plrno
= player_slot_index(pslot
);
1258 const char *flag_names
[1];
1260 if (secfile_section_lookup(loading
->file
, "player%d", plrno
) == NULL
) {
1264 if (secfile_lookup_bool_default(loading
->file
, FALSE
, "player%d.ai.control",
1266 flag_names
[0] = plr_flag_id_name(PLRF_AI
);
1268 secfile_insert_str_vec(loading
->file
, flag_names
, 1,
1269 "player%d.flags", plrno
);
1273 int num
= secfile_lookup_int_default(loading
->file
, 0,
1278 for (i
= 0; i
< num
; i
++) {
1281 fc_snprintf(buf
, sizeof(buf
), "player%d.u%d.born", plrno
, i
);
1283 increase_secfile_turn_int(loading
, buf
, old_turn
, FALSE
);
1286 num
= secfile_lookup_int_default(loading
->file
, 0,
1287 "player%d.ncities", plrno
);
1289 for (i
= 0; i
< num
; i
++) {
1292 fc_snprintf(buf
, sizeof(buf
), "player%d.c%d.turn_founded", plrno
, i
);
1294 increase_secfile_turn_int(loading
, buf
, -2, TRUE
);
1297 } player_slots_iterate_end
;
1300 num_settings
= secfile_lookup_int_default(loading
->file
, 0,
1301 "settings.set_count");
1303 /* User meta server message is now a setting. */
1304 if (secfile_lookup_bool_default(loading
->file
, FALSE
,
1305 "game.meta_usermessage")) {
1306 const char *metamessage
;
1308 metamessage
= secfile_lookup_str_default(loading
->file
, "",
1309 "game.meta_message");
1311 /* Insert the meta message as a setting */
1312 secfile_insert_str(loading
->file
, "metamessage",
1313 "settings.set%d.name", num_settings
);
1314 secfile_insert_str(loading
->file
, metamessage
,
1315 "settings.set%d.value", num_settings
);
1316 secfile_insert_str(loading
->file
, "",
1317 "settings.set%d.gamestart", num_settings
);
1321 secfile_replace_int(loading
->file
, num_settings
, "settings.set_count");
1324 /****************************************************************************
1325 Translate savegame secfile data from 3.0.x to 3.1.0 format.
1326 Note that even after 2.6 savegame has gone through all the compatibility
1327 functions, it's still 2.6 savegame in the sense that savegame2.c, and not
1328 savegame3.c, handles it.
1329 ****************************************************************************/
1330 static void compat_load_030100(struct loaddata
*loading
,
1331 enum sgf_version format_class
)
1333 /* Check status and return if not OK (sg_success != TRUE). */
1336 log_debug("Upgrading data from savegame to version 3.1.0");
1339 #ifdef FREECIV_DEV_SAVE_COMPAT_3_0
1340 static const char num_chars
[] =
1341 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-+";
1343 /**************************************************************************
1344 Converts single character into numerical value. This is not hex
1346 **************************************************************************/
1347 static int char2num(char ch
)
1352 /* Not specified. */
1356 pch
= strchr(num_chars
, ch
);
1358 sg_failure_ret_val(NULL
!= pch
, 0,
1359 "Unknown ascii value for num: '%c' %d", ch
, ch
);
1361 return pch
- num_chars
;
1363 #endif /* FREECIV_DEV_SAVE_COMPAT_3_0 */
1365 /****************************************************************************
1366 Translate savegame secfile data from earlier development version format
1368 ****************************************************************************/
1369 #ifdef FREECIV_DEV_SAVE_COMPAT
1370 static void compat_load_dev(struct loaddata
*loading
)
1373 #ifdef FREECIV_DEV_SAVE_COMPAT_3_0
1375 size_t diplstate_type_size
;
1376 struct entry
*convert_entry
;
1378 #endif /* FREECIV_DEV_SAVE_COMPAT_3_0 */
1380 /* Check status and return if not OK (sg_success != TRUE). */
1383 log_debug("Upgrading data between development revisions");
1385 if (!secfile_lookup_int(loading
->file
, &game_version
, "scenario.game_version")) {
1386 /* Oldest development versions handled here had version info in "game.version" */
1387 if (secfile_lookup_int(loading
->file
, &game_version
, "game.version")) {
1388 /* Move it to scenario.game_version while here. */
1389 secfile_insert_int(loading
->file
, game_version
, "scenario.game_version");
1391 game_version
= 20600;
1395 if (game_version
< 1000000) {
1396 game_version
*= 100;
1399 #ifdef FREECIV_DEV_SAVE_COMPAT_3_0
1400 if (game_version
< 2910000) {
1401 /* Early 3.0 development version save. */
1403 /* Rename "random.save" as "random.saved", if not already saved by later name */
1404 if (secfile_lookup_bool(loading
->file
, &randsaved
, "random.save")) {
1405 secfile_insert_bool(loading
->file
, randsaved
, "random.saved");
1408 /* Convert ai.control to a player flag */
1409 player_slots_iterate(pslot
) {
1410 int plrno
= player_slot_index(pslot
);
1411 const char *flag_names
[1];
1413 if (secfile_section_lookup(loading
->file
, "player%d", plrno
) == NULL
) {
1417 if (secfile_lookup_bool_default(loading
->file
, FALSE
, "player%d.ai.control",
1419 flag_names
[0] = plr_flag_id_name(PLRF_AI
);
1421 secfile_insert_str_vec(loading
->file
, flag_names
, 1,
1422 "player%d.flags", plrno
);
1425 /* Add 'anonymous' qualifiers for user names */
1426 if (secfile_entry_lookup(loading
->file
, "player%d.unassigned_user", plrno
) == NULL
) {
1429 name
= secfile_lookup_str_default(loading
->file
, "", "player%d.username", plrno
);
1430 secfile_insert_bool(loading
->file
, (!strcmp(name
, ANON_USER_NAME
)),
1431 "player%d.unassigned_user", plrno
);
1434 if (secfile_entry_lookup(loading
->file
, "player%d.unassigned_ranked", plrno
) == NULL
) {
1437 name
= secfile_lookup_str_default(loading
->file
, "", "player%d.ranked_username", plrno
);
1438 secfile_insert_bool(loading
->file
, (!strcmp(name
, ANON_USER_NAME
)),
1439 "player%d.unassigned_ranked", plrno
);
1441 } player_slots_iterate_end
;
1443 /* Diplomatic state type by name. */
1445 = secfile_lookup_int_default(loading
->file
, 0,
1446 "savefile.diplstate_type_size");
1448 if (diplstate_type_size
) {
1449 const char **ds_t_name
;
1451 /* Read the names of the diplomatic states. */
1452 ds_t_name
= secfile_lookup_str_vec(loading
->file
,
1453 &diplstate_type_size
,
1454 "savefile.diplstate_type_vector");
1456 player_slots_iterate(pslot
) {
1457 int plrno
= player_slot_index(pslot
);
1459 if (secfile_section_lookup(loading
->file
, "player%d", plrno
) == NULL
) {
1463 player_slots_iterate(pslot2
) {
1464 int i
= player_slot_index(pslot2
);
1467 if (secfile_section_lookup(loading
->file
, "player%d", i
) == NULL
) {
1471 fc_snprintf(buf
, sizeof(buf
), "player%d.diplstate%d", plrno
, i
);
1473 if (!secfile_entry_lookup(loading
->file
, "%s.current", buf
)) {
1474 /* The current diplomatic state was called type when it was
1475 * stored as a number. */
1476 int current
= secfile_lookup_int_default(loading
->file
, DS_WAR
,
1480 secfile_insert_str(loading
->file
, ds_t_name
[current
],
1484 if (!secfile_entry_lookup(loading
->file
, "%s.closest", buf
)) {
1485 /* The closest diplomatic state was called max_state when it was
1486 * stored as a number. */
1487 int closest
= secfile_lookup_int_default(loading
->file
, DS_WAR
,
1491 secfile_insert_str(loading
->file
, ds_t_name
[closest
],
1494 } player_slots_iterate_end
;
1495 } player_slots_iterate_end
;
1500 /* Fix save games from Freeciv versions with a bug that made it view
1501 * "Never met" as closer than "Peace" or "Alliance". */
1502 player_slots_iterate(pslot
) {
1503 int plrno
= player_slot_index(pslot
);
1505 int tgt_vec
[MAX_LEN_ROUTE
+ 1];
1508 if (secfile_section_lookup(loading
->file
, "player%d", plrno
) == NULL
) {
1512 player_slots_iterate(pslot2
) {
1513 int i
= player_slot_index(pslot2
);
1518 if (secfile_section_lookup(loading
->file
, "player%d", i
) == NULL
) {
1522 fc_snprintf(buf
, sizeof(buf
), "player%d.diplstate%d", plrno
, i
);
1524 /* Read the current diplomatic state. */
1525 current
= secfile_lookup_enum_default(loading
->file
, DS_NO_CONTACT
,
1530 /* Read the closest diplomatic state. */
1531 closest
= secfile_lookup_enum_default(loading
->file
, DS_NO_CONTACT
,
1536 if (closest
== DS_NO_CONTACT
1537 && (current
== DS_PEACE
1538 || current
== DS_ALLIANCE
)) {
1539 /* The current relationship is closer than what the save game
1540 * claims is the closes relationship ever. */
1542 log_sg(_("The save game is wrong about what the closest"
1543 " relationship player %d and player %d have had is."
1547 secfile_replace_enum(loading
->file
, current
,
1548 diplstate_type
, "%s.closest", buf
);
1550 } player_slots_iterate_end
;
1553 units_num
= secfile_lookup_int_default(loading
->file
, 0,
1557 for (unit
= 0; unit
< units_num
; unit
++) {
1560 /* Load the old target list string. */
1561 const char *tgt_str
=
1562 secfile_lookup_str_default(loading
->file
, NULL
,
1563 "player%d.u%d.tgt_list",
1566 /* Load the order length */
1568 secfile_lookup_int_default(loading
->file
, 0,
1569 "player%d.u%d.orders_length",
1572 if (tgt_str
== NULL
) {
1573 /* Already upgraded */
1582 /* Convert the target of each order. */
1583 for (ord_num
= 0; ord_num
< len
; ord_num
++) {
1584 tgt_vec
[ord_num
] = char2num(tgt_str
[ord_num
]);
1587 /* Store the order target vector. */
1588 secfile_insert_int_vec(loading
->file
, tgt_vec
, len
,
1589 "player%d.u%d.tgt_vec",
1592 } player_slots_iterate_end
;
1595 if (game_version
< 2920000) {
1596 /* Since version number bump to 2.91.99 */
1599 /* Freeciv-web has replaced fcweb with classic. Only done for
1600 * Freeciv-web because a regular Freeciv server build that encounters a
1601 * fcweb savegame may have a ruleset named fcweb installed locally. */
1603 const char *ruleset
;
1605 ruleset
= secfile_lookup_str_default(loading
->file
,
1606 GAME_DEFAULT_RULESETDIR
,
1607 "savefile.rulesetdir");
1609 if (strcmp("fcweb", ruleset
) == 0) {
1610 secfile_replace_str(loading
->file
, "classic", "savefile.rulesetdir");
1612 #endif /* FREECIV_WEB */
1615 player_slots_iterate(pslot
) {
1616 int plrno
= player_slot_index(pslot
);
1621 if (secfile_section_lookup(loading
->file
, "player%d", plrno
) == NULL
) {
1625 idlet
= secfile_lookup_int_default(loading
->file
, -1,
1626 "player%d.idle_turns", plrno
);
1629 secfile_insert_int(loading
->file
, 0, "player%d.idle_turns", plrno
);
1632 if (secfile_entry_lookup(loading
->file
, "player%d.sex", plrno
) == NULL
) {
1633 if (secfile_lookup_bool_default(loading
->file
, TRUE
, "player%d.is_male", plrno
)) {
1634 secfile_insert_str(loading
->file
, "male", "player%d.sex", plrno
);
1636 secfile_insert_str(loading
->file
, "female", "player%d.sex", plrno
);
1640 ncities
= secfile_lookup_int_default(loading
->file
, 0, "player%d.ncities", plrno
);
1642 for (i
= 0; i
< ncities
; i
++) {
1643 struct entry
*did_buy
= secfile_entry_lookup(loading
->file
, "player%d.c%d.did_buy",
1646 /* If did buy is an integer value, make it boolean instead */
1647 if (did_buy
!= NULL
&& entry_type(did_buy
) == ENTRY_INT
) {
1650 entry_int_get(did_buy
, &val
);
1653 secfile_replace_bool(loading
->file
, TRUE
, "player%d.c%d.did_buy",
1656 secfile_replace_bool(loading
->file
, FALSE
, "player%d.c%d.did_buy",
1661 } player_slots_iterate_end
;
1664 num_settings
= secfile_lookup_int_default(loading
->file
, 0,
1665 "settings.set_count");
1667 /* User meta server message is now a setting. */
1668 if (secfile_lookup_bool_default(loading
->file
, FALSE
,
1669 "game.meta_usermessage")) {
1670 const char *metamessage
;
1672 metamessage
= secfile_lookup_str_default(loading
->file
, "",
1673 "game.meta_message");
1675 /* Insert the meta message as a setting */
1676 secfile_insert_str(loading
->file
, "metamessage",
1677 "settings.set%d.name", num_settings
);
1678 secfile_insert_str(loading
->file
, metamessage
,
1679 "settings.set%d.value", num_settings
);
1680 secfile_insert_str(loading
->file
, "",
1681 "settings.set%d.gamestart", num_settings
);
1685 convert_entry
= secfile_entry_lookup(loading
->file
, "game.phase_mode");
1686 if (convert_entry
!= NULL
&& entry_type(convert_entry
) == ENTRY_INT
) {
1689 entry_int_get(convert_entry
, &nval
);
1691 secfile_replace_str(loading
->file
, phase_mode_type_name(nval
),
1694 convert_entry
= secfile_entry_lookup(loading
->file
, "game.phase_mode_stored");
1695 if (convert_entry
!= NULL
&& entry_type(convert_entry
) == ENTRY_INT
) {
1698 entry_int_get(convert_entry
, &nval
);
1700 secfile_replace_str(loading
->file
, phase_mode_type_name(nval
),
1701 "game.phase_mode_stored");
1704 secfile_replace_int(loading
->file
, num_settings
, "settings.set_count");
1706 /* Unit action decision aren't text any more. */
1707 if (secfile_section_lookup(loading
->file
,
1708 "savefile.action_decision_vector") == NULL
) {
1711 /* Write action decision order. */
1712 secfile_insert_int(loading
->file
, ACT_DEC_COUNT
,
1713 "savefile.action_decision_size");
1714 if (ACT_DEC_COUNT
> 0) {
1715 const char **modname
;
1719 modname
= fc_calloc(ACT_DEC_COUNT
, sizeof(*modname
));
1721 for (j
= 0; j
< ACT_DEC_COUNT
; j
++) {
1722 modname
[i
++] = action_decision_name(j
);
1725 secfile_insert_str_vec(loading
->file
, modname
,
1727 "savefile.action_decision_vector");
1731 /* Upgrade each unit. */
1732 player_slots_iterate(pslot
) {
1735 int plrno
= player_slot_index(pslot
);
1737 if (secfile_section_lookup(loading
->file
, "player%d", plrno
)
1742 /* Number of units the player has. */
1743 units_num
= secfile_lookup_int_default(loading
->file
, 0,
1747 for (unit
= 0; unit
< units_num
; unit
++) {
1750 /* Load old enum action decision want. */
1751 want
= secfile_lookup_enum_default(loading
->file
,
1752 ACT_DEC_NOTHING
, action_decision
,
1753 "player%d.u%d.action_decision_want", plrno
, unit
);
1755 /* Store the action decision want. */
1756 secfile_insert_int(loading
->file
, want
,
1757 "player%d.u%d.action_decision",
1760 } player_slots_iterate_end
;
1764 if (game_version
< 2930000) {
1765 /* Since version number bump to 2.92.99 */
1766 player_slots_iterate(pslot
) {
1767 int plrno
= player_slot_index(pslot
);
1769 if (secfile_section_lookup(loading
->file
, "player%d", plrno
) == NULL
) {
1773 if (secfile_entry_lookup(loading
->file
, "player%d.kind", plrno
) == NULL
) {
1774 const char *kind
= secfile_lookup_str_default(loading
->file
, "male", "player%d.sex", plrno
);
1776 secfile_insert_str(loading
->file
, kind
, "player%d.kind", plrno
);
1778 } player_slots_iterate_end
;
1780 #endif /* FREECIV_DEV_SAVE_COMPAT_3_0 */
1782 #ifdef FREECIV_DEV_SAVE_COMPAT_3_1
1783 #endif /* FREECIV_DEV_SAVE_COMPAT_3_1 */
1785 #endif /* FREECIV_DEV_SAVE_COMPAT */
1787 /****************************************************************************
1788 Convert old ai level value to ai_level
1789 ****************************************************************************/
1790 enum ai_level
ai_level_convert(int old_level
)
1792 switch (old_level
) {
1794 return AI_LEVEL_AWAY
;
1796 return AI_LEVEL_NOVICE
;
1798 return AI_LEVEL_EASY
;
1800 return AI_LEVEL_NORMAL
;
1802 return AI_LEVEL_HARD
;
1804 return AI_LEVEL_CHEATING
;
1806 #ifdef FREECIV_DEBUG
1807 return AI_LEVEL_EXPERIMENTAL
;
1808 #else /* FREECIV_DEBUG */
1809 return AI_LEVEL_HARD
;
1810 #endif /* FREECIV_DEBUG */
1813 return ai_level_invalid();
1816 /****************************************************************************
1817 Convert old barbarian type value to barbarian_type
1818 ****************************************************************************/
1819 enum barbarian_type
barb_type_convert(int old_type
)
1823 return NOT_A_BARBARIAN
;
1825 return LAND_BARBARIAN
;
1827 return SEA_BARBARIAN
;
1830 return barbarian_type_invalid();
1833 /**************************************************************************
1834 Returns the action id corresponding to the specified order id. If no
1835 corresponding action is found ACTION_NONE is returned.
1837 Relevant tile content information must be loaded before this function is
1838 called. Tile content information is relevant if it determines what action
1839 an old order result in. Example: a 2.6 ORDER_BUILD_CITY would result in
1840 Join City inside a domestic city and in Found City on a tile without a
1841 city. That makes domestic cities relevant tile content information.
1843 Intended to be used while loading unit orders from pre Freeciv 3.0.0
1844 save games (savegame and savegame2). Should be deleted with savegame2.
1846 Temporarily used to provide development version internal save game
1847 compatibility for what will become Freeciv 3.0. This use should cease
1848 before Freeciv 3.0.0 is released.
1850 Should never be called from savegame3 after the 3.0 development version
1851 internal save game compatibility is removed.
1852 **************************************************************************/
1853 int sg_order_to_action(int order
, struct unit
*act_unit
,
1854 struct tile
*tgt_tile
)
1857 case ORDER_OLD_BUILD_CITY
:
1858 if (tile_city(tgt_tile
)
1859 && city_owner(tile_city(tgt_tile
)) == unit_owner(act_unit
)) {
1860 /* The player's cities are loaded right before his units. It wasn't
1861 * possible for rulesets to allow joining foreign cities before 3.0.
1862 * This means that a converted build city order only can be a Join
1863 * City order if it targets a domestic city. */
1864 return ACTION_JOIN_CITY
;
1866 /* Assume that the intention was to found a new city. */
1867 return ACTION_FOUND_CITY
;
1869 case ORDER_OLD_BUILD_WONDER
:
1870 /* Maps one to one with each other. */
1871 return ACTION_HELP_WONDER
;
1872 case ORDER_OLD_TRADE_ROUTE
:
1873 /* Maps one to one with each other. */
1874 return ACTION_TRADE_ROUTE
;
1875 case ORDER_OLD_DISBAND
:
1876 /* Added to the order system in the same commit as Help Wonder. Assume
1877 * that anyone that intended to order Help Wonder used Help Wonder. */
1878 /* Could in theory be intended as an order to disband in the field. Why
1879 * would the player give a unit an order to go to a non city location
1880 * and disband there? Assume the intention was to recycle the unit
1881 * until a non recycle disband order is found. */
1882 return ACTION_RECYCLE_UNIT
;
1883 case ORDER_OLD_HOMECITY
:
1884 return ACTION_HOME_CITY
;
1887 /* The order hasn't been replaced by an action. */