Freeciv-3.2: /fast/freeciv/nightly/S3_2/server/savegame/savecompat.c Source File

Freeciv-3.2

Loading...
Searching...
No Matches
savecompat.c
Go to the documentation of this file.
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)
6 any later version.
7
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***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18/* utility */
19#include "capability.h"
20#include "log.h"
21
22/* common */
23#include "map.h"
24#include "specialist.h"
25
26/* server */
27#include "aiiface.h"
28#include "setcompat.h"
29#include "settings.h"
30#include "unittools.h"
31
32#include "savecompat.h"
33
34 bool sg_success;
35
36 static char *special_names[] =
37 {
38 "Irrigation", "Mine", "Pollution", "Hut", "Farmland",
39 "Fallout", NULL
40 };
41
42/*
43 For each savefile format after 2.3.0, compatibility functions are defined
44 which translate secfile structures from previous version to that version;
45 all necessary compat functions are called in order to
46 translate between the file and current version. See sg_load_compat().
47
48 The integer version ID should be increased every time the format is changed.
49 If the change is not backwards compatible, please state the changes in the
50 following list and update the compat functions at the end of this file.
51
52 - what was added / removed
53 - when was it added / removed (date and version)
54 - when can additional capability checks be set to mandatory (version)
55 - which compatibility checks are needed and till when (version)
56
57 freeciv | what | date | id
58 --------+------------------------------------------------+------------+----
59 current | (mapped to current savegame format) | ----/--/-- | 0
60 | first version (svn17538) | 2010/07/05 | -
61 2.3.0 | 2.3.0 release | 2010/11/?? | 3
62 2.4.0 | 2.4.0 release | 201./../.. | 10
63 | * player ai type | |
64 | * delegation | |
65 | * citizens | |
66 | * save player color | |
67 | * "known" info format change | |
68 2.5.0 | 2.5.0 release | 201./../.. | 20
69 2.6.0 | 2.6.0 release | 201./../.. | 30
70 3.0.0 | 3.0.0 release | 201./../.. | 40
71 3.1.0 | 3.1.0 release | 201./../.. | 50
72 3.2.0 | 3.2.0 release (development) | 202./../.. | 60
73 | | |
74*/
75
76static void compat_load_020400(struct loaddata *loading, enum sgf_version format_class);
77static void compat_load_020500(struct loaddata *loading, enum sgf_version format_class);
78static void compat_load_020600(struct loaddata *loading, enum sgf_version format_class);
79static void compat_load_030000(struct loaddata *loading, enum sgf_version format_class);
80static void compat_load_030100(struct loaddata *loading, enum sgf_version format_class);
81static void compat_load_030200(struct loaddata *loading, enum sgf_version format_class);
82static void compat_post_load_030100(struct loaddata *loading,
83 enum sgf_version format_class);
84
85#ifdef FREECIV_DEV_SAVE_COMPAT
86static void compat_load_dev(struct loaddata *loading);
87static void compat_post_load_dev(struct loaddata *loading);
88#endif /* FREECIV_DEV_SAVE_COMPAT */
89
90 typedef void (*load_version_func_t) (struct loaddata *loading, enum sgf_version format_class);
91
92 struct compatibility {
93 int version;
94 const load_version_func_t load;
95 const load_version_func_t post_load;
96};
97
98/* The struct below contains the information about the savegame versions. It
99 * is identified by the version number (first element), which should be
100 * steadily increasing. It is saved as 'savefile.version'. The support
101 * string (first element of 'name') is not saved in the savegame; it is
102 * saved in settings files (so, once assigned, cannot be changed). The
103 * 'pretty' string (second element of 'name') can be changed if necessary
104 * For changes in the development version, edit the definitions above and
105 * add the needed code to load the old version below. Thus, old
106 * savegames can still be loaded while the main definition
107 * represents the current state of the art. */
108/* While developing freeciv 3.2.0, add the compatibility functions to
109 * - compat_load_030200 to load old savegame. */
110 static struct compatibility compat[] = {
111 /* dummy; equal to the current version (last element) */
112 { 0, NULL, NULL },
113 /* version 1 and 2 is not used */
114 /* version 3: first savegame2 format, so no compat functions for translation
115 * from previous format */
116 { 3, NULL, NULL },
117 /* version 4 to 9 are reserved for possible changes in 2.3.x */
118 { 10, compat_load_020400, NULL },
119 /* version 11 to 19 are reserved for possible changes in 2.4.x */
120 { 20, compat_load_020500, NULL },
121 /* version 21 to 29 are reserved for possible changes in 2.5.x */
122 { 30, compat_load_020600, NULL },
123 /* version 31 to 39 are reserved for possible changes in 2.6.x */
124 { 40, compat_load_030000, NULL },
125 /* version 41 to 49 are reserved for possible changes in 3.0.x */
126 { 50, compat_load_030100, compat_post_load_030100 },
127 /* version 51 to 59 are reserved for possible changes in 3.1.x */
128 { 60, compat_load_030200, NULL },
129 /* Current savefile version is listed above this line; it corresponds to
130 the definitions in this file. */
131};
132
133 static const int compat_num = ARRAY_SIZE(compat);
134#define compat_current (compat_num - 1)
135
136/************************************************************************/
143 void sg_load_compat(struct loaddata *loading, enum sgf_version format_class)
144{
145 int i;
146
147 /* Check status and return if not OK (sg_success FALSE). */
148 sg_check_ret();
149
150 loading->version = secfile_lookup_int_default(loading->file, -1,
151 "savefile.version");
152#ifdef FREECIV_DEBUG
153 sg_failure_ret(0 < loading->version, "Invalid savefile format version (%d).",
154 loading->version);
155 if (loading->version > compat[compat_current].version) {
156 /* Debug build can (TRY TO!) load newer versions but ... */
157 log_error("Savegame version newer than this build found (%d > %d). "
158 "Trying to load the game nevertheless ...", loading->version,
159 compat[compat_current].version);
160 }
161#else /* FREECIV_DEBUG */
162 sg_failure_ret(0 < loading->version
163 && loading->version <= compat[compat_current].version,
164 "Unknown savefile format version (%d).", loading->version);
165#endif /* FREECIV_DEBUG */
166
167
168 for (i = 0; i < compat_num; i++) {
169 if (loading->version < compat[i].version && compat[i].load != NULL) {
170 log_normal(_("Run compatibility function for version: <%d "
171 "(save file: %d; server: %d)."), compat[i].version,
172 loading->version, compat[compat_current].version);
173 compat[i].load(loading, format_class);
174 }
175 }
176
177#ifdef FREECIV_DEV_SAVE_COMPAT
178 if (loading->version == compat[compat_current].version) {
179 compat_load_dev(loading);
180 }
181#endif /* FREECIV_DEV_SAVE_COMPAT */
182}
183
184/************************************************************************/
194 void sg_load_post_load_compat(struct loaddata *loading,
195 enum sgf_version format_class)
196{
197 int i;
198
199 /* Check status and return if not OK (sg_success FALSE). */
200 sg_check_ret();
201
202 for (i = 0; i < compat_num; i++) {
203 if (loading->version < compat[i].version
204 && compat[i].post_load != NULL) {
205 log_normal(_("Run post load compatibility function for version: <%d "
206 "(save file: %d; server: %d)."), compat[i].version,
207 loading->version, compat[compat_current].version);
208 compat[i].post_load(loading, format_class);
209 }
210 }
211
212#ifdef FREECIV_DEV_SAVE_COMPAT
213 if (loading->version == compat[compat_current].version) {
214 compat_post_load_dev(loading);
215 }
216#endif /* FREECIV_DEV_SAVE_COMPAT */
217}
218
219/************************************************************************/
222 int current_compat_ver(void)
223{
224 return compat[compat_current].version;
225}
226
227/************************************************************************/
232 char bin2ascii_hex(int value, int halfbyte_wanted)
233{
234 return hex_chars[((value) >> ((halfbyte_wanted) * 4)) & 0xf];
235}
236
237/************************************************************************/
244 int ascii_hex2bin(char ch, int halfbyte)
245{
246 const char *pch;
247
248 if (ch == ' ') {
249 /* Sane value. It is unknow if there are savegames out there which
250 * need this fix. Savegame.c doesn't write such savegames
251 * (anymore) since the inclusion into CVS (2000-08-25). */
252 return 0;
253 }
254
255 pch = strchr(hex_chars, ch);
256
257 sg_failure_ret_val(NULL != pch && '\0' != ch, 0,
258 "Unknown hex value: '%c' %d", ch, ch);
259 return (pch - hex_chars) << (halfbyte * 4);
260}
261
262 static const char num_chars[] =
263 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-+";
264
265/************************************************************************/
268 int char2num(char ch)
269{
270 const char *pch;
271
272 pch = strchr(num_chars, ch);
273
274 sg_failure_ret_val(NULL != pch, 0,
275 "Unknown ascii value for num: '%c' %d", ch, ch);
276
277 return pch - num_chars;
278}
279
280/************************************************************************/
283 enum tile_special_type special_by_rule_name(const char *name)
284{
285 int i;
286
287 for (i = 0; special_names[i] != NULL; i++) {
288 if (!strcmp(name, special_names[i])) {
289 return i;
290 }
291 }
292
293 return S_LAST;
294}
295
296/************************************************************************/
299 const char *special_rule_name(enum tile_special_type type)
300{
301 fc_assert(type >= 0 && type < S_LAST);
302
303 return special_names[type];
304}
305
306/************************************************************************/
309 struct extra_type *special_extra_get(int spe)
310{
311 struct extra_type_list *elist = extra_type_list_by_cause(EC_SPECIAL);
312
313 if (spe < extra_type_list_size(elist)) {
314 return extra_type_list_get(elist, spe);
315 }
316
317 return NULL;
318}
319
320/************************************************************************/
323 struct extra_type *resource_by_identifier(const char identifier)
324{
325 extra_type_by_cause_iterate(EC_RESOURCE, presource) {
326 if (presource->data.resource->id_old_save == identifier) {
327 return presource;
328 }
329 } extra_type_by_cause_iterate_end;
330
331 return NULL;
332}
333
334/* =======================================================================
335 * Compatibility functions for loading a game.
336 * ======================================================================= */
337
338/************************************************************************/
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 FALSE). */
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 int ncities, i, plrno = player_slot_index(pslot);
352
353 if (NULL == secfile_section_lookup(loading->file, "player%d", plrno)) {
354 continue;
355 }
356
357 secfile_insert_str(loading->file, default_ai_type_name(),
358 "player%d.ai_type", player_slot_index(pslot));
359
360 /* Create dummy citizens informations. We do not know if citizens are
361 * activated due to the fact that this information
362 * (game.info.citizen_nationality) is not available, but adding the
363 * information does no harm. */
364 ncities = secfile_lookup_int_default(loading->file, 0,
365 "player%d.ncities", plrno);
366 if (ncities > 0) {
367 for (i = 0; i < ncities; i++) {
368 int size = secfile_lookup_int_default(loading->file, 0,
369 "player%d.c%d.size", plrno, i);
370 if (size > 0) {
371 secfile_insert_int(loading->file, size,
372 "player%d.c%d.citizen%d", plrno, i, plrno);
373 }
374 }
375 }
376
377 } player_slots_iterate_end;
378
379 /* Player colors are assigned at the end of player loading, as this
380 * needs information not available here. */
381
382 /* Deal with buggy known tiles information from 2.3.0/2.3.1 (and the
383 * workaround in later 2.3.x); see gna bug #19029.
384 * (The structure of this code is odd as it avoids relying on knowledge of
385 * xsize/ysize, which haven't been extracted from the savefile yet.) */
386 {
387 if (has_capability("knownv2",
388 secfile_lookup_str(loading->file, "savefile.options"))) {
389 /* This savefile contains known information in a sane format.
390 * Just move any entries to where 2.4.x+ expect to find them. */
391 struct section *map = secfile_section_by_name(loading->file, "map");
392
393 if (map != NULL) {
394 entry_list_iterate(section_entries(map), pentry) {
395 const char *name = entry_name(pentry);
396
397 if (!fc_strncmp(name, "kvb", 3)) {
398 /* Rename the "kvb..." entry to "k..." */
399 char *name2 = fc_strdup(name), *newname = name2 + 2;
400
401 *newname = 'k';
402 /* Savefile probably contains existing "k" entries, which are bogus
403 * so we trash them. */
404 secfile_entry_delete(loading->file, "map.%s", newname);
405 entry_set_name(pentry, newname);
406 FC_FREE(name2);
407 }
408 } entry_list_iterate_end;
409 }
410 /* Could remove "knownv2" from savefile.options, but it's doing
411 * no harm there. */
412 } else {
413 /* This savefile only contains known information in the broken
414 * format. Try to recover it to a sane format. */
415 /* MAX_NUM_PLAYER_SLOTS in 2.3.x was 128 */
416 /* MAP_MAX_LINEAR_SIZE in 2.3.x was 512 */
417 const int maxslots = 128, maxmapsize = 512;
418 const int lines = maxslots/32;
419 int xsize = 0, y, l, j, x;
420 unsigned int known_row_old[lines * maxmapsize],
421 known_row[lines * maxmapsize];
422 /* Process a map row at a time */
423 for (y = 0; y < maxmapsize; y++) {
424 /* Look for broken info to convert */
425 bool found = FALSE;
426 memset(known_row_old, 0, sizeof(known_row_old));
427 for (l = 0; l < lines; l++) {
428 for (j = 0; j < 8; j++) {
429 const char *s =
430 secfile_lookup_str_default(loading->file, NULL,
431 "map.k%02d_%04d", l * 8 + j, y);
432 if (s) {
433 found = TRUE;
434 if (xsize == 0) {
435 xsize = strlen(s);
436 }
437 sg_failure_ret(xsize == strlen(s),
438 "Inconsistent xsize in map.k%02d_%04d",
439 l * 8 + j, y);
440 for (x = 0; x < xsize; x++) {
441 known_row_old[l * xsize + x] |= ascii_hex2bin(s[x], j);
442 }
443 }
444 }
445 }
446 if (found) {
447 /* At least one entry found for this row. Let's hope they were
448 * all there. */
449 /* Attempt to munge into sane format */
450 int p;
451 memset(known_row, 0, sizeof(known_row));
452 /* Iterate over possible player slots */
453 for (p = 0; p < maxslots; p++) {
454 l = p / 32;
455 for (x = 0; x < xsize; x++) {
456 /* This test causes bit-shifts of >=32 (undefined behaviour), but
457 * on common platforms, information happens not to be lost, just
458 * oddly arranged. */
459 if (known_row_old[l * xsize + x] & (1u << (p - l * 8))) {
460 known_row[l * xsize + x] |= (1u << (p - l * 32));
461 }
462 }
463 }
464 /* Save sane format back to memory representation of secfile for
465 * real loading code to pick up */
466 for (l = 0; l < lines; l++) {
467 for (j = 0; j < 8; j++) {
468 /* Save info for all slots (not just used ones). It's only
469 * memory, after all. */
470 char row[xsize+1];
471 for (x = 0; x < xsize; x++) {
472 row[x] = bin2ascii_hex(known_row[l * xsize + x], j);
473 }
474 row[xsize] = '\0';
475 secfile_replace_str(loading->file, row,
476 "map.k%02d_%04d", l * 8 + j, y);
477 }
478 }
479 }
480 }
481 }
482 }
483
484 /* Server setting migration. */
485 {
486 int set_count;
487
488 if (secfile_lookup_int(loading->file, &set_count, "settings.set_count")) {
489 int i, new_opt = set_count;
490 bool gamestart_valid
491 = secfile_lookup_bool_default(loading->file, FALSE,
492 "settings.gamestart_valid");
493
494 for (i = 0; i < set_count; i++) {
495 const char *name
496 = secfile_lookup_str(loading->file, "settings.set%d.name", i);
497
498 if (!name) {
499 continue;
500 }
501
502 /* In 2.3.x and prior, saveturns=0 meant no turn-based saves.
503 * This is now controlled by the "autosaves" setting. */
504 if (!fc_strcasecmp("saveturns", name)) {
505 /* XXX: hardcodes details from GAME_AUTOSAVES_DEFAULT
506 * and settings.c:autosaves_name() (but these defaults reflect
507 * 2.3's behaviour). */
508 const char *const nosave = "GAMEOVER|QUITIDLE|INTERRUPT";
509 const char *const save = "TURN|GAMEOVER|QUITIDLE|INTERRUPT";
510 int nturns;
511
512 if (secfile_lookup_int(loading->file, &nturns,
513 "settings.set%d.value", i)) {
514 if (nturns == 0) {
515 /* Invent a new "autosaves" setting */
516 secfile_insert_str(loading->file, nosave,
517 "settings.set%d.value", new_opt);
518 /* Pick something valid for saveturns */
519 secfile_replace_int(loading->file, GAME_DEFAULT_SAVETURNS,
520 "settings.set%d.value", i);
521 } else {
522 secfile_insert_str(loading->file, save,
523 "settings.set%d.value", new_opt);
524 }
525 } else {
526 log_sg("Setting '%s': %s", name, secfile_error());
527 }
528 if (gamestart_valid) {
529 if (secfile_lookup_int(loading->file, &nturns,
530 "settings.set%d.gamestart", i)) {
531 if (nturns == 0) {
532 /* Invent a new "autosaves" setting */
533 secfile_insert_str(loading->file, nosave,
534 "settings.set%d.gamestart", new_opt);
535 /* Pick something valid for saveturns */
536 secfile_replace_int(loading->file, GAME_DEFAULT_SAVETURNS,
537 "settings.set%d.gamestart", i);
538 } else {
539 secfile_insert_str(loading->file, save,
540 "settings.set%d.gamestart", new_opt);
541 }
542 } else {
543 log_sg("Setting '%s': %s", name, secfile_error());
544 }
545 }
546 } else if (!fc_strcasecmp("autosaves", name)) {
547 /* Sanity check. This won't trigger on an option we've just
548 * invented, as the loop won't include it. */
549 log_sg("Unexpected \"autosaves\" setting found in pre-2.4 "
550 "savefile. It may have been overridden.");
551 }
552 }
553 }
554 }
555}
556
557/************************************************************************/
560 static const char *killcitizen_enum_str(secfile_data_t data, int bit)
561{
562 switch (bit) {
563 case UMT_LAND:
564 return "LAND";
565 case UMT_SEA:
566 return "SEA";
567 case UMT_BOTH:
568 return "BOTH";
569 }
570
571 return NULL;
572}
573
574/************************************************************************/
577 static void compat_load_020500(struct loaddata *loading,
578 enum sgf_version format_class)
579{
580 const char *modname[] = { "Road", "Railroad" };
581 const char *old_activities_names[] = {
582 "Idle",
583 "Pollution",
584 "Unused Road",
585 "Mine",
586 "Irrigate",
587 "Mine",
588 "Irrigate",
589 "Fortified",
590 "Fortress",
591 "Sentry",
592 "Unused Railroad",
593 "Pillage",
594 "Goto",
595 "Explore",
596 "Transform",
597 "Unused",
598 "Unused Airbase",
599 "Fortifying",
600 "Fallout",
601 "Unused Patrol",
602 "Base"
603 };
604
605 /* Check status and return if not OK (sg_success FALSE). */
606 sg_check_ret();
607
608 log_debug("Upgrading data from savegame to version 2.5.0");
609
610 secfile_insert_int(loading->file, 2, "savefile.roads_size");
611 secfile_insert_int(loading->file, 0, "savefile.trait_size");
612
613 secfile_insert_str_vec(loading->file, modname, 2,
614 "savefile.roads_vector");
615
616 secfile_insert_int(loading->file, 19, "savefile.activities_size");
617 secfile_insert_str_vec(loading->file, old_activities_names, 19,
618 "savefile.activities_vector");
619
620 /* Server setting migration. */
621 {
622 int set_count;
623
624 if (secfile_lookup_int(loading->file, &set_count, "settings.set_count")) {
625 int i;
626 bool gamestart_valid
627 = secfile_lookup_bool_default(loading->file, FALSE,
628 "settings.gamestart_valid");
629 for (i = 0; i < set_count; i++) {
630 const char *name
631 = secfile_lookup_str(loading->file, "settings.set%d.name", i);
632 if (!name) {
633 continue;
634 }
635 /* In 2.4.x and prior, "killcitizen" listed move types that
636 * killed citizens after successful attack. Now killcitizen
637 * is just boolean and classes affected are defined in ruleset. */
638 if (!fc_strcasecmp("killcitizen", name)) {
639 int value;
640
641 if (secfile_lookup_enum_data(loading->file, &value, TRUE,
642 killcitizen_enum_str, NULL,
643 "settings.set%d.value", i)) {
644 /* Lowest bit of old killcitizen value indicates if
645 * land units should kill citizens. We take that as
646 * new boolean killcitizen value. */
647 if (value & 0x1) {
648 secfile_replace_bool(loading->file, TRUE,
649 "settings.set%d.value", i);
650 } else {
651 secfile_replace_bool(loading->file, FALSE,
652 "settings.set%d.value", i);
653 }
654 } else {
655 log_sg("Setting '%s': %s", name, secfile_error());
656 }
657 if (gamestart_valid) {
658 if (secfile_lookup_enum_data(loading->file, &value, TRUE,
659 killcitizen_enum_str, NULL,
660 "settings.set%d.gamestart", i)) {
661 /* Lowest bit of old killcitizen value indicates if
662 * land units should kill citizens. We take that as
663 * new boolean killcitizen value. */
664 if (value & 0x1) {
665 secfile_replace_bool(loading->file, TRUE,
666 "settings.set%d.gamestart", i);
667 } else {
668 secfile_replace_bool(loading->file, FALSE,
669 "settings.set%d.gamestart", i);
670 }
671 } else {
672 log_sg("Setting '%s': %s", name, secfile_error());
673 }
674 }
675 }
676 }
677 }
678 }
679}
680
681/************************************************************************/
684 static char *revolentype_str(enum revolen_type type)
685{
686 switch (type) {
687 case REVOLEN_FIXED:
688 return "FIXED";
689 case REVOLEN_RANDOM:
690 return "RANDOM";
691 case REVOLEN_QUICKENING:
692 return "QUICKENING";
693 case REVOLEN_RANDQUICK:
694 return "RANDQUICK";
695 }
696
697 return "";
698}
699
700/************************************************************************/
703 static void compat_load_020600(struct loaddata *loading,
704 enum sgf_version format_class)
705{
706 bool team_pooled_research = GAME_DEFAULT_TEAM_POOLED_RESEARCH;
707 int tsize;
708 int ti;
709 int turn;
710
711 /* Check status and return if not OK (sg_success FALSE). */
712 sg_check_ret();
713
714 log_debug("Upgrading data from savegame to version 2.6.0");
715
716 /* Terrain mapping table - use current ruleset as we have no way to know
717 * any other old values. */
718 ti = 0;
719 terrain_type_iterate(pterr) {
720 char buf[2];
721
722 secfile_insert_str(loading->file, terrain_rule_name(pterr), "savefile.terrident%d.name", ti);
723 buf[0] = terrain_identifier(pterr);
724 buf[1] = '\0';
725 secfile_insert_str(loading->file, buf, "savefile.terrident%d.identifier", ti++);
726 } terrain_type_iterate_end;
727
728 /* Server setting migration. */
729 {
730 int set_count;
731
732 if (secfile_lookup_int(loading->file, &set_count, "settings.set_count")) {
733 char value_buffer[1024] = "";
734 char gamestart_buffer[1024] = "";
735 int i;
736 int dcost = -1;
737 int dstartcost = -1;
738 enum revolen_type rlt = GAME_DEFAULT_REVOLENTYPE;
739 enum revolen_type gsrlt = GAME_DEFAULT_REVOLENTYPE;
740 bool gamestart_valid
741 = secfile_lookup_bool_default(loading->file, FALSE,
742 "settings.gamestart_valid");
743 int new_set_count;
744
745 for (i = 0; i < set_count; i++) {
746 const char *name
747 = secfile_lookup_str(loading->file, "settings.set%d.name", i);
748 if (!name) {
749 continue;
750 }
751
752 /* In 2.5.x and prior, "spacerace" boolean controlled if
753 * spacerace victory condition was active. */
754 if (!fc_strcasecmp("spacerace", name)) {
755 bool value;
756
757 if (secfile_lookup_bool(loading->file, &value,
758 "settings.set%d.value", i)) {
759 if (value) {
760 if (value_buffer[0] != '\0') {
761 sz_strlcat(value_buffer, "|");
762 }
763 sz_strlcat(value_buffer, "SPACERACE");
764 }
765 } else {
766 log_sg("Setting '%s': %s", name, secfile_error());
767 }
768 if (secfile_lookup_bool(loading->file, &value,
769 "settings.set%d.gamestart", i)) {
770 if (value) {
771 if (gamestart_buffer[0] != '\0') {
772 sz_strlcat(gamestart_buffer, "|");
773 }
774 sz_strlcat(gamestart_buffer, "SPACERACE");
775 }
776 } else {
777 log_sg("Setting '%s': %s", name, secfile_error());
778 }
779
780 /* We cannot delete old values from the secfile, or rather cannot
781 * change index of the later settings. Renumbering them is not easy as
782 * we don't know type of each setting we would encounter.
783 * So we keep old setting values and only add new "victories" setting. */
784 } else if (!fc_strcasecmp("alliedvictory", name)) {
785 bool value;
786
787 if (secfile_lookup_bool(loading->file, &value,
788 "settings.set%d.value", i)) {
789 if (value) {
790 if (value_buffer[0] != '\0') {
791 sz_strlcat(value_buffer, "|");
792 }
793 sz_strlcat(value_buffer, "ALLIED");
794 }
795 } else {
796 log_sg("Setting '%s': %s", name, secfile_error());
797 }
798 if (secfile_lookup_bool(loading->file, &value,
799 "settings.set%d.gamestart", i)) {
800 if (value) {
801 if (gamestart_buffer[0] != '\0') {
802 sz_strlcat(gamestart_buffer, "|");
803 }
804 sz_strlcat(gamestart_buffer, "ALLIED");
805 }
806 } else {
807 log_sg("Setting '%s': %s", name, secfile_error());
808 }
809 } else if (!fc_strcasecmp("revolen", name)) {
810 int value;
811
812 if (secfile_lookup_int(loading->file, &value,
813 "settings.set%d.value", i)) {
814 /* 0 meant RANDOM 1-5 */
815 if (value == 0) {
816 rlt = REVOLEN_RANDOM;
817 secfile_replace_int(loading->file, 5,
818 "settings.set%d.value", i);
819 } else {
820 rlt = REVOLEN_FIXED;
821 }
822 } else {
823 log_sg("Setting '%s': %s", name, secfile_error());
824 }
825 if (secfile_lookup_int(loading->file, &value,
826 "settings.set%d.gamestart", i)) {
827 /* 0 meant RANDOM 1-5 */
828 if (value == 0) {
829 gsrlt = REVOLEN_RANDOM;
830 secfile_replace_int(loading->file, 5,
831 "settings.set%d.gamestart", i);
832 } else {
833 gsrlt = REVOLEN_FIXED;
834 }
835 } else {
836 log_sg("Setting '%s': %s", name, secfile_error());
837 }
838 } else if (!fc_strcasecmp("happyborders", name)) {
839 bool value;
840
841 if (secfile_lookup_bool(loading->file, &value,
842 "settings.set%d.value", i)) {
843 secfile_entry_delete(loading->file, "settings.set%d.value", i);
844 if (value) {
845 secfile_insert_str(loading->file, "NATIONAL",
846 "settings.set%d.value", i);
847 } else {
848 secfile_insert_str(loading->file, "DISABLED",
849 "settings.set%d.value", i);
850 }
851 } else {
852 log_sg("Setting '%s': %s", name, secfile_error());
853 }
854 if (secfile_lookup_bool(loading->file, &value,
855 "settings.set%d.gamestart", i)) {
856 secfile_entry_delete(loading->file, "settings.set%d.gamestart", i);
857 if (value) {
858 secfile_insert_str(loading->file, "NATIONAL",
859 "settings.set%d.gamestart", i);
860 } else {
861 secfile_insert_str(loading->file, "DISABLED",
862 "settings.set%d.gamestart", i);
863 }
864 } else {
865 log_sg("Setting '%s': %s", name, secfile_error());
866 }
867 } else if (!fc_strcasecmp("team_pooled_research", name)) {
868 sg_warn(secfile_lookup_bool(loading->file,
869 &team_pooled_research,
870 "settings.set%d.value", i),
871 "%s", secfile_error());
872 } else if (!fc_strcasecmp("diplcost", name)) {
873 /* Old 'diplcost' split to 'diplbulbcost' and 'diplgoldcost' */
874 if (secfile_lookup_int(loading->file, &dcost,
875 "settings.set%d.value", i)) {
876 } else {
877 log_sg("Setting '%s': %s", name, secfile_error());
878 }
879
880 if (secfile_lookup_int(loading->file, &dstartcost,
881 "settings.set%d.gamestart", i)) {
882 } else {
883 log_sg("Setting '%s': %s", name, secfile_error());
884 }
885 } else if (!fc_strcasecmp("huts", name)) {
886 /* Scale of 'huts' changed. */
887 int hcount;
888
889 if (secfile_lookup_int(loading->file, &hcount,
890 "settings.set%d.value", i)) {
891 } else {
892 log_sg("Setting '%s': %s", name, secfile_error());
893 }
894
895 /* Store old-style absolute value. */
896 wld.map.server.huts_absolute = hcount;
897 }
898 }
899
900 new_set_count = set_count + 2; /* 'victories' and 'revolentype' */
901
902 if (dcost >= 0) {
903 new_set_count += 2;
904 }
905
906 secfile_replace_int(loading->file, new_set_count, "settings.set_count");
907
908 secfile_insert_str(loading->file, "victories", "settings.set%d.name",
909 set_count);
910 secfile_insert_str(loading->file, value_buffer, "settings.set%d.value",
911 set_count);
912 secfile_insert_str(loading->file, "revolentype", "settings.set%d.name",
913 set_count + 1);
914 secfile_insert_str(loading->file, revolentype_str(rlt), "settings.set%d.value",
915 set_count + 1);
916
917 if (dcost >= 0) {
918 secfile_insert_str(loading->file, "diplbulbcost", "settings.set%d.name", set_count + 2);
919 secfile_insert_int(loading->file, dcost, "settings.set%d.value", set_count + 2);
920 secfile_insert_str(loading->file, "diplgoldcost", "settings.set%d.name", set_count + 3);
921 secfile_insert_int(loading->file, dcost, "settings.set%d.value", set_count + 3);
922 }
923
924 if (gamestart_valid) {
925 secfile_insert_str(loading->file, gamestart_buffer, "settings.set%d.gamestart",
926 set_count);
927 secfile_insert_str(loading->file, revolentype_str(gsrlt), "settings.set%d.gamestart",
928 set_count + 1);
929
930 if (dcost >= 0) {
931 secfile_insert_int(loading->file, dstartcost, "settings.set%d.gamestart", set_count + 2);
932 secfile_insert_int(loading->file, dstartcost, "settings.set%d.gamestart", set_count + 3);
933 }
934 }
935 }
936 }
937
938 sg_failure_ret(secfile_lookup_int(loading->file, &tsize, "savefile.trait_size"),
939 "Trait size: %s", secfile_error());
940
941 turn = secfile_lookup_int_default(loading->file, 0, "game.turn");
942
943 player_slots_iterate(pslot) {
944 int plrno = player_slot_index(pslot);
945 bool got_first_city;
946 int old_barb_type;
947 enum barbarian_type new_barb_type;
948 int i;
949 const char *name;
950 int score;
951 int units_num;
952
953 if (NULL == secfile_section_lookup(loading->file, "player%d", plrno)) {
954 continue;
955 }
956
957 /* Renamed 'capital' to 'got_first_city'. */
958 if (secfile_lookup_bool(loading->file, &got_first_city,
959 "player%d.capital", plrno)) {
960 secfile_insert_bool(loading->file, got_first_city,
961 "player%d.got_first_city", plrno);
962 }
963
964 /* Add 'anonymous' qualifiers for user names */
965 name = secfile_lookup_str_default(loading->file, "", "player%d.username", plrno);
966 secfile_insert_bool(loading->file, (!strcmp(name, ANON_USER_NAME)),
967 "player%d.unassigned_user", plrno);
968
969 name = secfile_lookup_str_default(loading->file, "", "player%d.ranked_username", plrno);
970 secfile_insert_bool(loading->file, (!strcmp(name, ANON_USER_NAME)),
971 "player%d.unassigned_ranked", plrno);
972
973 /* Convert numeric barbarian type to textual */
974 old_barb_type = secfile_lookup_int_default(loading->file, 0,
975 "player%d.ai.is_barbarian", plrno);
976 new_barb_type = barb_type_convert(old_barb_type);
977 secfile_insert_str(loading->file, barbarian_type_name(new_barb_type),
978 "player%d.ai.barb_type", plrno);
979
980 /* Pre-2.6 didn't record when a player was created or died, so we have
981 * to assume they lived from the start of the game until last turn */
982 secfile_insert_int(loading->file, turn, "player%d.turns_alive", plrno);
983
984 /* As if there never has been a war. */
985 secfile_insert_int(loading->file, -1, "player%d.last_war", plrno);
986
987 /* Assume people were playing until current reload */
988 secfile_insert_int(loading->file, 0, "player%d.idle_turns", plrno);
989
990 for (i = 0; i < tsize; i++) {
991 int val;
992
993 val = secfile_lookup_int_default(loading->file, -1, "player%d.trait.val%d",
994 plrno, i);
995 if (val != -1) {
996 secfile_insert_int(loading->file, val, "player%d.trait%d.val", plrno, 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, i);
1003 }
1004
1005 score = secfile_lookup_int_default(loading->file, -1,
1006 "player%d.units_built", plrno);
1007 if (score >= 0) {
1008 secfile_insert_int(loading->file, score, "score%d.units_built", plrno);
1009 }
1010
1011 score = secfile_lookup_int_default(loading->file, -1,
1012 "player%d.units_killed", plrno);
1013 if (score >= 0) {
1014 secfile_insert_int(loading->file, score, "score%d.units_killed", plrno);
1015 }
1016
1017 score = secfile_lookup_int_default(loading->file, -1,
1018 "player%d.units_lost", plrno);
1019 if (score >= 0) {
1020 secfile_insert_int(loading->file, score, "score%d.units_lost", plrno);
1021 }
1022
1023 /* Units orders. */
1024 units_num = secfile_lookup_int_default(loading->file, 0,
1025 "player%d.nunits",
1026 plrno);
1027
1028 for (i = 0; i < units_num; i++) {
1029 int len;
1030
1031 if (secfile_lookup_bool_default(loading->file, FALSE,
1032 "player%d.u%d.orders_last_move_safe",
1033 plrno, i)) {
1034 continue;
1035 }
1036
1037 len = secfile_lookup_int_default(loading->file, 0,
1038 "player%d.u%d.orders_length",
1039 plrno, i);
1040 if (len > 0) {
1041 char orders_str[len + 1];
1042 char *p;
1043
1044 sz_strlcpy(orders_str,
1045 secfile_lookup_str_default(loading->file, "",
1046 "player%d.u%d.orders_list",
1047 plrno, i));
1048 if ((p = strrchr(orders_str, 'm'))
1049 || (p = strrchr(orders_str, 'M'))) {
1050 *p = 'x'; /* ORDER_MOVE -> ORDER_ACTION_MOVE */
1051 secfile_replace_str(loading->file, orders_str,
1052 "player%d.u%d.orders_list", plrno, i);
1053 }
1054 }
1055 }
1056 } player_slots_iterate_end;
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 specialist
1060 * values */
1061 secfile_insert_int(loading->file, specialist_count(),
1062 "savefile.specialists_size");
1063 {
1064 const char **modname;
1065 int i = 0;
1066
1067 modname = fc_calloc(specialist_count(), sizeof(*modname));
1068
1069 specialist_type_iterate(sp) {
1070 modname[i++] = specialist_rule_name(specialist_by_number(sp));
1071 } specialist_type_iterate_end;
1072
1073 secfile_insert_str_vec(loading->file, modname, specialist_count(),
1074 "savefile.specialists_vector");
1075
1076 free(modname);
1077 }
1078
1079 /* Replace all city specialist count fields with correct names */
1080 player_slots_iterate(pslot) {
1081 int plrno = player_slot_index(pslot);
1082 int ncities;
1083 int i;
1084
1085 if (NULL == secfile_section_lookup(loading->file, "player%d", plrno)) {
1086 continue;
1087 }
1088
1089 ncities = secfile_lookup_int_default(loading->file, 0, "player%d.ncities", plrno);
1090
1091 for (i = 0; i < ncities; i++) {
1092 int k = 0;
1093
1094 specialist_type_iterate(sp) {
1095 struct specialist *psp = specialist_by_number(sp);
1096 int count;
1097
1098 sg_failure_ret(secfile_lookup_int(loading->file, &count,
1099 "player%d.c%d.n%s",
1100 plrno, i, specialist_rule_name(psp)),
1101 "specialist error: %s", secfile_error());
1102 secfile_entry_delete(loading->file, "player%d.c%d.n%s",
1103 plrno, i, specialist_rule_name(psp));
1104 secfile_insert_int(loading->file, count, "player%d.c%d.nspe%d",
1105 plrno, i, k++);
1106 } specialist_type_iterate_end;
1107 }
1108 } player_slots_iterate_end;
1109
1110 /* Build [research]. */
1111 {
1112 const struct {
1113 const char *name;
1114 enum entry_type type;
1115 } entries[] = {
1116 { "goal_name", ENTRY_STR },
1117 { "techs", ENTRY_INT },
1118 { "futuretech", ENTRY_INT },
1119 { "bulbs_before", ENTRY_INT },
1120 { "saved_name", ENTRY_STR },
1121 { "bulbs", ENTRY_INT },
1122 { "now_name", ENTRY_STR },
1123 { "got_tech", ENTRY_BOOL },
1124 { "done", ENTRY_STR }
1125 };
1126
1127 int researches[MAX(player_slot_count(), team_slot_count())];
1128 int count = 0;
1129 int i;
1130
1131 for (i = 0; i < ARRAY_SIZE(researches); i++) {
1132 researches[i] = -1;
1133 }
1134
1135 player_slots_iterate(pslot) {
1136 int plrno = player_slot_index(pslot);
1137 int ival;
1138 bool bval;
1139 const char *sval;
1140 int j;
1141
1142 if (secfile_section_lookup(loading->file, "player%d", plrno) == NULL) {
1143 continue;
1144 }
1145
1146 /* Get the research number. */
1147 if (team_pooled_research) {
1148 i = secfile_lookup_int_default(loading->file, plrno,
1149 "player%d.team_no", plrno);
1150 } else {
1151 i = plrno;
1152 }
1153
1154 sg_failure_ret(i >= 0 && i < ARRAY_SIZE(researches),
1155 "Research out of bounds (%d)!", i);
1156
1157 /* Find the index in [research] section. */
1158 if (researches[i] == -1) {
1159 /* This is the first player for this research. */
1160 secfile_insert_int(loading->file, i, "research.r%d.number", count);
1161 researches[i] = count;
1162 count++;
1163 }
1164 i = researches[i];
1165
1166 /* Move entries. */
1167 for (j = 0; j < ARRAY_SIZE(entries); j++) {
1168 switch (entries[j].type) {
1169 case ENTRY_BOOL:
1170 if (secfile_lookup_bool(loading->file, &bval,
1171 "player%d.research.%s",
1172 plrno, entries[j].name)) {
1173 secfile_insert_bool(loading->file, bval, "research.r%d.%s",
1174 i, entries[j].name);
1175 }
1176 break;
1177 case ENTRY_INT:
1178 if (secfile_lookup_int(loading->file, &ival,
1179 "player%d.research.%s",
1180 plrno, entries[j].name)) {
1181 secfile_insert_int(loading->file, ival, "research.r%d.%s",
1182 i, entries[j].name);
1183 }
1184 break;
1185 case ENTRY_STR:
1186 if ((sval = secfile_lookup_str(loading->file,
1187 "player%d.research.%s",
1188 plrno, entries[j].name))) {
1189 secfile_insert_str(loading->file, sval, "research.r%d.%s",
1190 i, entries[j].name);
1191 }
1192 break;
1193 case ENTRY_FLOAT:
1194 sg_failure_ret(entries[j].type != ENTRY_FLOAT,
1195 "Research related entry marked as float.");
1196 break;
1197 case ENTRY_FILEREFERENCE:
1198 fc_assert(entries[j].type != ENTRY_FILEREFERENCE);
1199 break;
1200 case ENTRY_LONG_COMMENT:
1201 fc_assert(entries[j].type != ENTRY_LONG_COMMENT);
1202 break;
1203 case ENTRY_ILLEGAL:
1204 fc_assert(entries[j].type != ENTRY_ILLEGAL);
1205 break;
1206 }
1207 }
1208 } player_slots_iterate_end;
1209 secfile_insert_int(loading->file, count, "research.count");
1210 }
1211
1212 /* Add diplstate type order. */
1213 secfile_insert_int(loading->file, DS_LAST,
1214 "savefile.diplstate_type_size");
1215 if (DS_LAST > 0) {
1216 const char **modname;
1217 int i;
1218 int j;
1219
1220 i = 0;
1221 modname = fc_calloc(DS_LAST, sizeof(*modname));
1222
1223 for (j = 0; j < DS_LAST; j++) {
1224 modname[i++] = diplstate_type_name(j);
1225 }
1226
1227 secfile_insert_str_vec(loading->file, modname,
1228 DS_LAST,
1229 "savefile.diplstate_type_vector");
1230 free(modname);
1231 }
1232
1233 /* Fix save games from Freeciv versions with a bug that made it view
1234 * "Never met" as closer than "Peace" or "Alliance". */
1235 player_slots_iterate(pslot) {
1236 int plrno = player_slot_index(pslot);
1237
1238 if (NULL == secfile_section_lookup(loading->file, "player%d", plrno)) {
1239 continue;
1240 }
1241
1242 player_slots_iterate(pslot2) {
1243 int i = player_slot_index(pslot2);
1244 char buf[32];
1245 int current;
1246 int closest;
1247
1248 if (NULL == secfile_section_lookup(loading->file, "player%d", i)) {
1249 continue;
1250 }
1251
1252 fc_snprintf(buf, sizeof(buf), "player%d.diplstate%d", plrno, i);
1253
1254 /* Read the current diplomatic state. */
1255 current = secfile_lookup_int_default(loading->file, DS_NO_CONTACT,
1256 "%s.type",
1257 buf);
1258
1259 /* Read the closest diplomatic state. */
1260 closest = secfile_lookup_int_default(loading->file, DS_NO_CONTACT,
1261 "%s.max_state",
1262 buf);
1263
1264 if (closest == DS_NO_CONTACT
1265 && (current == DS_PEACE
1266 || current == DS_ALLIANCE)) {
1267 const char *name1 = secfile_lookup_str_default(loading->file, "",
1268 "player%d.name", plrno);
1269 const char *name2 = secfile_lookup_str_default(loading->file, "",
1270 "player%d.name", i);
1271 /* The current relationship is closer than what the save game
1272 * claims is the closes relationship ever. */
1273
1274 log_sg(_("The save game is wrong about what the closest"
1275 " relationship %s (player %d) and %s (player %d) have had is."
1276 " Fixing it..."),
1277 name1, plrno, name2, i);
1278
1279 secfile_replace_int(loading->file, current, "%s.max_state", buf);
1280 }
1281 } player_slots_iterate_end;
1282 } player_slots_iterate_end;
1283}
1284
1285/************************************************************************/
1288 static int increase_secfile_turn_int(struct loaddata *loading, const char *key,
1289 int old_def, bool keep_default)
1290{
1291 int value;
1292
1293 value = secfile_lookup_int_default(loading->file, old_def, "%s", key);
1294
1295 if (value != old_def || !keep_default) {
1296 value++;
1297 secfile_replace_int(loading->file, value, "%s", key);
1298 }
1299
1300 return value;
1301}
1302
1303/************************************************************************/
1309 static void compat_load_030000(struct loaddata *loading,
1310 enum sgf_version format_class)
1311{
1312 bool randsaved;
1313 int num_settings;
1314 bool started;
1315 int old_turn;
1316 int event_count;
1317 int i;
1318
1319 /* Check status and return if not OK (sg_success FALSE). */
1320 sg_check_ret();
1321
1322 log_debug("Upgrading data from savegame to version 3.0.0");
1323
1324 /* Rename "random.save" as "random.saved"
1325 * Note that it's not an error if a scenario does not have [random] at all. */
1326 if (secfile_lookup_bool(loading->file, &randsaved, "random.save")) {
1327 secfile_insert_bool(loading->file, randsaved, "random.saved");
1328 }
1329
1330 /* Already started games should have their turn counts increased by 1 */
1331 if (secfile_lookup_bool_default(loading->file, TRUE, "game.save_players")) {
1332 started = TRUE;
1333
1334 old_turn = increase_secfile_turn_int(loading, "game.turn", 0, FALSE) - 1;
1335 increase_secfile_turn_int(loading, "game.scoreturn", old_turn + GAME_DEFAULT_SCORETURN, FALSE);
1336 increase_secfile_turn_int(loading, "history.turn", -2, TRUE);
1337 } else {
1338 started = FALSE;
1339 }
1340
1341 player_slots_iterate(pslot) {
1342 int plrno = player_slot_index(pslot);
1343 const char *flag_names[1];
1344
1345 if (secfile_section_lookup(loading->file, "player%d", plrno) == NULL) {
1346 continue;
1347 }
1348
1349 if (secfile_lookup_bool_default(loading->file, FALSE, "player%d.ai.control",
1350 plrno)) {
1351 flag_names[0] = plr_flag_id_name(PLRF_AI);
1352
1353 secfile_insert_str_vec(loading->file, flag_names, 1,
1354 "player%d.flags", plrno);
1355 }
1356
1357 if (started) {
1358 int num = secfile_lookup_int_default(loading->file, 0,
1359 "player%d.nunits",
1360 plrno);
1361
1362 for (i = 0; i < num; i++) {
1363 char buf[64];
1364
1365 fc_snprintf(buf, sizeof(buf), "player%d.u%d.born", plrno, i);
1366
1367 increase_secfile_turn_int(loading, buf, old_turn, FALSE);
1368 }
1369
1370 num = secfile_lookup_int_default(loading->file, 0,
1371 "player%d.ncities", plrno);
1372
1373 for (i = 0; i < num; i++) {
1374 char buf[64];
1375
1376 fc_snprintf(buf, sizeof(buf), "player%d.c%d.turn_founded", plrno, i);
1377
1378 increase_secfile_turn_int(loading, buf, -2, TRUE);
1379 }
1380 }
1381 } player_slots_iterate_end;
1382
1383 /* Settings */
1384 num_settings = secfile_lookup_int_default(loading->file, 0,
1385 "settings.set_count");
1386
1387 /* User meta server message is now a setting. */
1388 if (secfile_lookup_bool_default(loading->file, FALSE,
1389 "game.meta_usermessage")) {
1390 const char *metamessage;
1391
1392 metamessage = secfile_lookup_str_default(loading->file, "",
1393 "game.meta_message");
1394
1395 /* Insert the meta message as a setting */
1396 secfile_insert_str(loading->file, "metamessage",
1397 "settings.set%d.name", num_settings);
1398 secfile_insert_str(loading->file, metamessage,
1399 "settings.set%d.value", num_settings);
1400 secfile_insert_str(loading->file, "",
1401 "settings.set%d.gamestart", num_settings);
1402 num_settings++;
1403 }
1404
1405 secfile_replace_int(loading->file, num_settings, "settings.set_count");
1406
1407 event_count = secfile_lookup_int_default(loading->file, 0, "event_cache.count");
1408
1409 for (i = 0; i < event_count; i++) {
1410 const char *etype;
1411
1412 etype = secfile_lookup_str(loading->file, "event_cache.events%d.event", i);
1413
1414 if (etype != NULL && !fc_strcasecmp("E_UNIT_WIN", etype)) {
1415 secfile_replace_str(loading->file, "E_UNIT_WIN_DEF",
1416 "event_cache.events%d.event", i);
1417 }
1418 }
1419}
1420
1421/************************************************************************/
1424 static void insert_server_side_agent(struct loaddata *loading,
1425 enum sgf_version format_class)
1426{
1427 int ssa_size;
1428
1429 if (format_class == SAVEGAME_2) {
1430 /* Handled in savegame2 */
1431 return;
1432 }
1433
1434 ssa_size = secfile_lookup_int_default(loading->file, 0,
1435 "savefile.server_side_agent_size");
1436
1437 if (ssa_size != 0) {
1438 /* Already inserted. */
1439 return;
1440 }
1441
1442 /* Add server side agent order. */
1443 secfile_insert_int(loading->file, SSA_COUNT,
1444 "savefile.server_side_agent_size");
1445 if (SSA_COUNT > 0) {
1446 const char **modname;
1447 int i;
1448 int j;
1449
1450 i = 0;
1451 modname = fc_calloc(SSA_COUNT, sizeof(*modname));
1452
1453 for (j = 0; j < SSA_COUNT; j++) {
1454 modname[i++] = server_side_agent_name(j);
1455 }
1456
1457 secfile_insert_str_vec(loading->file, modname,
1458 SSA_COUNT,
1459 "savefile.server_side_agent_list");
1460 free(modname);
1461 }
1462
1463 /* Insert server_side_agent unit field. */
1464 player_slots_iterate(pslot) {
1465 int unit;
1466 int units_num;
1467 int plrno = player_slot_index(pslot);
1468
1469 if (secfile_section_lookup(loading->file, "player%d", plrno)
1470 == NULL) {
1471 continue;
1472 }
1473
1474 /* Number of units the player has. */
1475 units_num = secfile_lookup_int_default(loading->file, 0,
1476 "player%d.nunits",
1477 plrno);
1478
1479 for (unit = 0; unit < units_num; unit++) {
1480 bool ai;
1481
1482 if (secfile_section_lookup(loading->file,
1483 "player%d.u%d.server_side_agent",
1484 plrno, unit)
1485 != NULL) {
1486 /* Already updated? */
1487 continue;
1488 }
1489
1490 ai = secfile_lookup_bool_default(loading->file, FALSE,
1491 "player%d.u%d.ai",
1492 plrno, unit);
1493
1494 if (ai) {
1495 /* Autosettler and Autoexplore are separated by
1496 * compat_post_load_030100() when set to SSA_AUTOSETTLER */
1497 secfile_insert_int(loading->file, SSA_AUTOSETTLER,
1498 "player%d.u%d.server_side_agent",
1499 plrno, unit);
1500 } else {
1501 secfile_insert_int(loading->file, SSA_NONE,
1502 "player%d.u%d.server_side_agent",
1503 plrno, unit);
1504 }
1505 }
1506 } player_slots_iterate_end;
1507}
1508
1509/************************************************************************/
1515 static void compat_load_030100(struct loaddata *loading,
1516 enum sgf_version format_class)
1517{
1518 /* Check status and return if not OK (sg_success FALSE). */
1519 sg_check_ret();
1520
1521 log_debug("Upgrading data from savegame to version 3.1.0");
1522
1523 /* Actions are now stored by number. */
1524 player_slots_iterate(pslot) {
1525 int unit;
1526 int units_num;
1527 int plrno = player_slot_index(pslot);
1528
1529 if (secfile_section_lookup(loading->file, "player%d", plrno)
1530 == NULL) {
1531 continue;
1532 }
1533
1534 /* Number of units the player has. */
1535 units_num = secfile_lookup_int_default(loading->file, 0,
1536 "player%d.nunits",
1537 plrno);
1538
1539 for (unit = 0; unit < units_num; unit++) {
1540 const char *action_unitstr;
1541 int order_len;
1542
1543 order_len = secfile_lookup_int_default(loading->file, 0,
1544 "player%d.u%d.orders_length",
1545 plrno, unit);
1546
1547 if ((action_unitstr = secfile_lookup_str_default(loading->file, "",
1548 "player%d.u%d.action_list",
1549 plrno, unit))) {
1550 int order_num;
1551
1552 if (order_len > strlen(action_unitstr)) {
1553 order_len = strlen(action_unitstr);
1554 }
1555
1556 for (order_num = 0; order_num < order_len; order_num++) {
1557 int unconverted_action_id;
1558
1559 if (action_unitstr[order_num] == '?') {
1560 unconverted_action_id = -1;
1561 } else {
1562 unconverted_action_id = char2num(action_unitstr[order_num]);
1563 }
1564
1565 if (order_num == 0) {
1566 /* The start of a vector has no number. */
1567 secfile_insert_int(loading->file, unconverted_action_id,
1568 "player%d.u%d.action_vec",
1569 plrno, unit);
1570 } else {
1571 secfile_insert_int(loading->file, unconverted_action_id,
1572 "player%d.u%d.action_vec,%d",
1573 plrno, unit, order_num);
1574 }
1575 }
1576 }
1577 }
1578 } player_slots_iterate_end;
1579
1580 {
1581 int action_count;
1582
1583 action_count = secfile_lookup_int_default(loading->file, 0,
1584 "savefile.action_size");
1585
1586 if (action_count > 0) {
1587 const char **modname;
1588 const char **savemod;
1589 int j;
1590 const char *dur_name = "Disband Unit Recover";
1591
1592 modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
1593 "savefile.action_vector");
1594
1595 savemod = fc_calloc(action_count, sizeof(*savemod));
1596
1597 for (j = 0; j < action_count; j++) {
1598 if (!fc_strcasecmp("Recycle Unit", modname[j])) {
1599 savemod[j] = dur_name;
1600 } else {
1601 savemod[j] = modname[j];
1602 }
1603 }
1604
1605 secfile_replace_str_vec(loading->file, savemod, action_count,
1606 "savefile.action_vector");
1607
1608 free(savemod);
1609 }
1610 }
1611
1612 /* Server setting migration. */
1613 {
1614 int set_count;
1615
1616 if (secfile_lookup_int(loading->file, &set_count, "settings.set_count")) {
1617 int i;
1618 bool gamestart_valid
1619 = secfile_lookup_bool_default(loading->file, FALSE,
1620 "settings.gamestart_valid");
1621
1622 /* Only add gamesetdef if gamestart is valid at all */
1623 if (gamestart_valid) {
1624 for (i = 0; i < set_count; i++) {
1625 const char *name
1626 = secfile_lookup_str(loading->file, "settings.set%d.name", i);
1627
1628 if (!name) {
1629 continue;
1630 }
1631
1632 secfile_insert_str(loading->file, setting_default_level_name(SETDEF_CHANGED),
1633 "settings.set%d.gamesetdef", i);
1634 }
1635 }
1636 }
1637 }
1638
1639 /* Explicit server side agent was new in 3.1 */
1640 insert_server_side_agent(loading, format_class);
1641}
1642
1643/************************************************************************/
1646 static void unit_order_activity_to_action(struct unit *act_unit)
1647{
1648 int i;
1649
1650 for (i = 0; i < act_unit->orders.length; i++) {
1651 struct unit_order *order = &act_unit->orders.list[i];
1652
1653 if (order->order != ORDER_ACTIVITY) {
1654 continue;
1655 }
1656
1657 switch (order->activity) {
1658 case ACTIVITY_CLEAN:
1659 case ACTIVITY_MINE:
1660 case ACTIVITY_IRRIGATE:
1661 case ACTIVITY_PLANT:
1662 case ACTIVITY_CULTIVATE:
1663 case ACTIVITY_TRANSFORM:
1664 case ACTIVITY_CONVERT:
1665 case ACTIVITY_FORTIFYING:
1666 case ACTIVITY_BASE:
1667 case ACTIVITY_GEN_ROAD:
1668 case ACTIVITY_PILLAGE:
1669 action_iterate(act_id) {
1670 struct action *paction = action_by_number(act_id);
1671
1672 if (action_get_activity(paction) == order->activity) {
1673 order->order = ORDER_PERFORM_ACTION;
1674 order->action = action_number(paction);
1675 order->activity = ACTIVITY_LAST;
1676 break;
1677 }
1678 } action_iterate_end;
1679 break;
1680 case ACTIVITY_SENTRY:
1681 /* Not an action */
1682 break;
1683 case ACTIVITY_EXPLORE:
1684 case ACTIVITY_IDLE:
1685 case ACTIVITY_GOTO:
1686 case ACTIVITY_FORTIFIED:
1687 case ACTIVITY_LAST:
1688 log_error("Activity %d is not supposed to appear in unit orders",
1689 order->activity);
1690 break;
1691 }
1692 }
1693}
1694
1695/************************************************************************/
1698 static enum direction8 dir_opposite(enum direction8 dir)
1699{
1700 switch (dir) {
1701 case DIR8_NORTH:
1702 return DIR8_SOUTH;
1703 case DIR8_NORTHEAST:
1704 return DIR8_SOUTHWEST;
1705 case DIR8_EAST:
1706 return DIR8_WEST;
1707 case DIR8_SOUTHEAST:
1708 return DIR8_NORTHWEST;
1709 case DIR8_SOUTH:
1710 return DIR8_NORTH;
1711 case DIR8_SOUTHWEST:
1712 return DIR8_NORTHEAST;
1713 case DIR8_WEST:
1714 return DIR8_EAST;
1715 case DIR8_NORTHWEST:
1716 return DIR8_SOUTHEAST;
1717 }
1718
1719 return DIR8_ORIGIN;
1720}
1721
1722/************************************************************************/
1725 static void upgrade_unit_order_targets(struct unit *act_unit)
1726{
1727 int i;
1728 struct tile *current_tile;
1729 struct tile *tgt_tile;
1730
1731 if (!unit_has_orders(act_unit)) {
1732 return;
1733 }
1734
1735 /* The order index is for the unit at its current tile. */
1736 current_tile = unit_tile(act_unit);
1737
1738 /* Rewind to the beginning of the orders */
1739 for (i = act_unit->orders.index; i > 0 && current_tile != NULL; i--) {
1740 struct unit_order *prev_order = &act_unit->orders.list[i - 1];
1741
1742 if (!(prev_order->order == ORDER_PERFORM_ACTION
1743 && utype_is_unmoved_by_action(action_by_number(prev_order->action),
1744 unit_type_get(act_unit)))
1745 && direction8_is_valid(prev_order->dir)) {
1746 current_tile = mapstep(&(wld.map), current_tile,
1747 dir_opposite(prev_order->dir));
1748 }
1749 }
1750
1751 /* Upgrade to explicit target tile */
1752 for (i = 0; i < act_unit->orders.length && current_tile != NULL; i++) {
1753 struct unit_order *order = &act_unit->orders.list[i];
1754
1755 if (order->order == ORDER_PERFORM_ACTION
1756 && order->target != NO_TARGET) {
1757 /* The target is already specified in the new format. */
1758
1759 /* The index_to_tile() call has no side-effects that we
1760 * would want also in NDEBUG builds. */
1761 fc_assert(index_to_tile(&(wld.map), order->target) != NULL);
1762 return;
1763 }
1764
1765 if (!direction8_is_valid(order->dir)) {
1766 /* The target of the action is on the actor's tile. */
1767 tgt_tile = current_tile;
1768 } else {
1769 /* The target of the action is on a tile next to the actor. */
1770 tgt_tile = mapstep(&(wld.map), current_tile, order->dir);
1771 }
1772
1773 if (order->order == ORDER_PERFORM_ACTION) {
1774 if (tgt_tile != NULL) {
1775 struct action *paction = action_by_number(order->action);
1776
1777 order->target = tgt_tile->index;
1778 /* Leave no traces. */
1779 order->dir = DIR8_ORIGIN;
1780
1781 if (!utype_is_unmoved_by_action(paction, unit_type_get(act_unit))) {
1782 /* The action moves the unit to the target tile (unless this is the
1783 * final order) */
1784 fc_assert(utype_is_moved_to_tgt_by_action(paction,
1785 unit_type_get(act_unit))
1786 || i == act_unit->orders.length - 1);
1787 current_tile = tgt_tile;
1788 }
1789 } else {
1790 current_tile = NULL;
1791 }
1792 } else {
1793 current_tile = tgt_tile;
1794 }
1795 }
1796
1797 if (current_tile == NULL) {
1798 log_sg("Illegal orders for %s. Cancelling.", unit_rule_name(act_unit));
1799 free_unit_orders(act_unit);
1800 }
1801}
1802
1803/************************************************************************/
1806 static void upgrade_server_side_agent(struct loaddata *loading)
1807{
1808 players_iterate_alive(pplayer) {
1809 unit_list_iterate(pplayer->units, punit) {
1810 if (punit->activity == ACTIVITY_EXPLORE) {
1811 punit->ssa_controller = SSA_AUTOEXPLORE;
1812 }
1813 } unit_list_iterate_end;
1814 } players_iterate_alive_end;
1815}
1816
1817/************************************************************************/
1820 static void compat_post_load_030100(struct loaddata *loading,
1821 enum sgf_version format_class)
1822{
1823 /* Check status and return if not OK (sg_success FALSE). */
1824 sg_check_ret();
1825
1826 /* Action orders were new in 3.0 */
1827 if (format_class == SAVEGAME_3) {
1828 /* Only 3.0 savegames may have "Attack" action orders. */
1829 players_iterate_alive(pplayer) {
1830 unit_list_iterate(pplayer->units, punit) {
1831 int i;
1832
1833 if (!punit->has_orders) {
1834 continue;
1835 }
1836
1837 fc_assert_action(punit->orders.length == 0
1838 || punit->orders.list != NULL, continue);
1839
1840 for (i = 0; i < punit->orders.length; i++) {
1841 /* "Attack" was split in "Suicide Attack" and "Attack" in 3.1. */
1842 if (punit->orders.list[i].order == ORDER_PERFORM_ACTION
1843 && punit->orders.list[i].action == ACTION_ATTACK
1844 && !unit_can_do_action(punit, ACTION_ATTACK)
1845 && unit_can_do_action(punit, ACTION_SUICIDE_ATTACK)) {
1846 punit->orders.list[i].action = ACTION_SUICIDE_ATTACK;
1847 }
1848
1849 /* Production targeted actions were split from building targeted
1850 * actions in 3.1. The building sub target encoding changed. */
1851 if (punit->orders.list[i].order == ORDER_PERFORM_ACTION
1852 && ((punit->orders.list[i].action
1853 == ACTION_SPY_TARGETED_SABOTAGE_CITY)
1854 || (punit->orders.list[i].action
1855 == ACTION_SPY_TARGETED_SABOTAGE_CITY_ESC))) {
1856 punit->orders.list[i].sub_target -= 1;
1857 }
1858 if (punit->orders.list[i].order == ORDER_PERFORM_ACTION
1859 && (punit->orders.list[i].action
1860 == ACTION_SPY_TARGETED_SABOTAGE_CITY)
1861 && punit->orders.list[i].sub_target == -1) {
1862 punit->orders.list[i].action
1863 = ACTION_SPY_SABOTAGE_CITY_PRODUCTION;
1864 }
1865 if (punit->orders.list[i].order == ORDER_PERFORM_ACTION
1866 && (punit->orders.list[i].action
1867 == ACTION_SPY_TARGETED_SABOTAGE_CITY_ESC)
1868 && punit->orders.list[i].sub_target == -1) {
1869 punit->orders.list[i].action
1870 = ACTION_SPY_SABOTAGE_CITY_PRODUCTION_ESC;
1871 }
1872 }
1873 } unit_list_iterate_end;
1874 } players_iterate_alive_end;
1875 }
1876
1877 /* Explicit server side agent was new in 3.1 */
1878 upgrade_server_side_agent(loading);
1879
1880 /* Some activities should only be ordered in action orders. */
1881 players_iterate_alive(pplayer) {
1882 unit_list_iterate(pplayer->units, punit) {
1883 unit_order_activity_to_action(punit);
1884 } unit_list_iterate_end;
1885 } players_iterate_alive_end;
1886
1887 /* Unit order action target isn't dir anymore */
1888 players_iterate_alive(pplayer) {
1889 unit_list_iterate(pplayer->units, punit) {
1890 upgrade_unit_order_targets(punit);
1891 } unit_list_iterate_end;
1892 } players_iterate_alive_end;
1893
1894 /* Backward compatibility: if we had any open-ended orders (pillage)
1895 * in the savegame, assign specific targets now */
1896 players_iterate_alive(pplayer) {
1897 unit_list_iterate(pplayer->units, punit) {
1898 unit_assign_specific_activity_target(punit,
1899 &punit->activity,
1900 &punit->activity_target);
1901 } unit_list_iterate_end;
1902 } players_iterate_alive_end;
1903}
1904
1905/************************************************************************/
1911 static void compat_load_030200(struct loaddata *loading,
1912 enum sgf_version format_class)
1913{
1914 int i;
1915 int count;
1916 int set_count;
1917 bool gamestart_valid = FALSE;
1918
1919 /* Check status and return if not OK (sg_success FALSE). */
1920 sg_check_ret();
1921
1922 log_debug("Upgrading data from savegame to version 3.2.0");
1923
1924 {
1925 const char *str = secfile_lookup_str_default(loading->file, NULL,
1926 "savefile.orig_version");
1927
1928 if (str == NULL) {
1929 /* Make sure CURRENTLY running version does not
1930 * end as orig_version when we resave. */
1931 if (format_class == SAVEGAME_3) {
1932 secfile_insert_str(loading->file, "old savegame3, or older",
1933 "savefile.orig_version");
1934 } else {
1935 fc_assert(format_class == SAVEGAME_2);
1936
1937 secfile_insert_str(loading->file, "savegame2, or older",
1938 "savefile.orig_version");
1939 }
1940 }
1941 }
1942
1943 {
1944 int action_count;
1945
1946 action_count = secfile_lookup_int_default(loading->file, 0,
1947 "savefile.action_size");
1948
1949 if (action_count > 0) {
1950 const char **modname;
1951 const char **savemod;
1952 int j;
1953 const char *dur_name = "Transport Deboard";
1954 const char *clean_name = "Clean";
1955
1956 modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
1957 "savefile.action_vector");
1958
1959 savemod = fc_calloc(action_count, sizeof(*savemod));
1960
1961 for (j = 0; j < action_count; j++) {
1962 if (!fc_strcasecmp("Transport Alight", modname[j])) {
1963 savemod[j] = dur_name;
1964 } else if (!fc_strcasecmp("Clean Pollution", modname[j])
1965 || !fc_strcasecmp("Clean Fallout", modname[j])) {
1966 savemod[j] = clean_name;
1967 } else {
1968 savemod[j] = modname[j];
1969 }
1970 }
1971
1972 secfile_replace_str_vec(loading->file, savemod, action_count,
1973 "savefile.action_vector");
1974
1975 free(savemod);
1976 }
1977 }
1978
1979 {
1980 int activities_count;
1981
1982 activities_count = secfile_lookup_int_default(loading->file, 0,
1983 "savefile.activities_size");
1984
1985 if (activities_count > 0) {
1986 const char **modname;
1987 const char **savemod;
1988 int j;
1989 const char *clean_name = "Clean";
1990
1991 modname = secfile_lookup_str_vec(loading->file, &loading->activities.size,
1992 "savefile.activities_vector");
1993
1994 savemod = fc_calloc(activities_count, sizeof(*savemod));
1995
1996 for (j = 0; j < activities_count; j++) {
1997 if (!fc_strcasecmp("Pollution", modname[j])
1998 || !fc_strcasecmp("Fallout", modname[j])) {
1999 savemod[j] = clean_name;
2000 } else {
2001 savemod[j] = modname[j];
2002 }
2003 }
2004
2005 secfile_replace_str_vec(loading->file, savemod, activities_count,
2006 "savefile.activities_vector");
2007
2008 free(savemod);
2009 }
2010 }
2011
2012 /* Server setting migration. */
2013 {
2014 if (secfile_lookup_int(loading->file, &set_count, "settings.set_count")) {
2015 int alltemperate_idx = -1, singlepole_idx = -1;
2016 bool count_changed = FALSE;
2017
2018 gamestart_valid
2019 = secfile_lookup_bool_default(loading->file, FALSE,
2020 "settings.gamestart_valid");
2021
2022 for (i = 0; i < set_count; i++) {
2023 const char *old_name
2024 = secfile_lookup_str(loading->file, "settings.set%d.name", i);
2025 const char *name;
2026
2027 if (!old_name) {
2028 continue;
2029 }
2030
2031 name = setcompat_S3_2_name_from_S3_1(old_name);
2032
2033 if (fc_strcasecmp(old_name, name)) {
2034 /* Setting's name changed */
2035 secfile_replace_str(loading->file, name, "settings.set%d.name", i);
2036 }
2037
2038 if (!gamestart_valid) {
2039 /* Older savegames saved these values even when they were not valid.
2040 * Silence warnings caused by them. */
2041 (void) secfile_entry_lookup(loading->file, "settings.set%d.gamestart", i);
2042 (void) secfile_entry_lookup(loading->file, "settings.set%d.gamesetdef", i);
2043 }
2044
2045 if (!fc_strcasecmp("compresstype", name)) {
2046 const char *val = secfile_lookup_str(loading->file,
2047 "settings.set%d.value", i);
2048 if (!fc_strcasecmp(val, "BZIP2")) {
2049#ifdef FREECIV_HAVE_LIBZSTD
2050 secfile_replace_str(loading->file, "ZSTD",
2051 "settings.set%d.value", i);
2052#elif FREECIV_HAVE_LIBLZMA
2053 secfile_replace_str(loading->file, "XZ",
2054 "settings.set%d.value", i);
2055#elif FREECIV_HAVE_LIBZ
2056 secfile_replace_str(loading->file, "LIBZ",
2057 "settings.set%d.value", i);
2058#else
2059 secfile_replace_str(loading->file, "PLAIN",
2060 "settings.set%d.value", i);
2061#endif
2062 }
2063
2064 if (gamestart_valid) {
2065 val = secfile_lookup_str(loading->file,
2066 "settings.set%d.gamestart", i);
2067 if (!fc_strcasecmp(val, "BZIP2")) {
2068#ifdef FREECIV_HAVE_LIBZSTD
2069 secfile_replace_str(loading->file, "ZSTD",
2070 "settings.set%d.gamestart", i);
2071#elif FREECIV_HAVE_LIBLZMA
2072 secfile_replace_str(loading->file, "XZ",
2073 "settings.set%d.gamestart", i);
2074#elif FREECIV_HAVE_LIBZ
2075 secfile_replace_str(loading->file, "LIBZ",
2076 "settings.set%d.gamestart", i);
2077#else
2078 secfile_replace_str(loading->file, "PLAIN",
2079 "settings.set%d.gamestart", i);
2080#endif
2081 }
2082 }
2083 } else if (!fc_strcasecmp("topology", name)) {
2084 struct setting *pset = setting_by_name(name);
2085 struct sf_cb_data info = { pset, TRUE };
2086 int val;
2087
2088 if (secfile_lookup_enum_data(loading->file, &val, TRUE,
2089 setting_bitwise_secfile_str, &info,
2090 "settings.set%d.value", i)) {
2091 char wrap[100];
2092 char buf[100];
2093
2094 if (val & TF_OLD_WRAPX) {
2095 if (val & TF_OLD_WRAPY) {
2096 fc_strlcpy(wrap, "WrapX|WrapY", sizeof(wrap));
2097 } else {
2098 fc_strlcpy(wrap, "WrapX", sizeof(wrap));
2099 }
2100 } else if (val & TF_OLD_WRAPY) {
2101 fc_strlcpy(wrap, "WrapY", sizeof(wrap));
2102 } else {
2103 fc_strlcpy(wrap, "", sizeof(wrap));
2104 }
2105
2106 if (val & TF_ISO) {
2107 if (val & TF_HEX) {
2108 setting_bitwise_set(pset, "ISO|HEX", NULL, NULL, 0);
2109 } else {
2110 setting_bitwise_set(pset, "ISO", NULL, NULL, 0);
2111 }
2112 } else if (val & TF_HEX) {
2113 setting_bitwise_set(pset, "HEX", NULL, NULL, 0);
2114 } else {
2115 setting_bitwise_set(pset, "", NULL, NULL, 0);
2116 }
2117
2118 setting_value_name(pset, FALSE, buf, sizeof(buf));
2119 secfile_replace_str(loading->file, buf,
2120 "settings.set%d.value", i);
2121
2122 secfile_insert_str(loading->file,
2123 "wrap", "settings.set%d.name", set_count);
2124 secfile_insert_str(loading->file,
2125 wrap, "settings.set%d.value", set_count);
2126
2127 if (gamestart_valid) {
2128 if (secfile_lookup_enum_data(loading->file, &val, TRUE,
2129 setting_bitwise_secfile_str, &info,
2130 "settings.set%d.gamestart", i)) {
2131 if (val & TF_OLD_WRAPX) {
2132 if (val & TF_OLD_WRAPY) {
2133 fc_strlcpy(wrap, "WrapX|WrapY", sizeof(wrap));
2134 } else {
2135 fc_strlcpy(wrap, "WrapX", sizeof(wrap));
2136 }
2137 } else if (val & TF_OLD_WRAPY) {
2138 fc_strlcpy(wrap, "WrapY", sizeof(wrap));
2139 } else {
2140 fc_strlcpy(wrap, "", sizeof(wrap));
2141 }
2142
2143 if (val & TF_ISO) {
2144 if (val & TF_HEX) {
2145 setting_bitwise_set(pset, "ISO|HEX", NULL, NULL, 0);
2146 } else {
2147 setting_bitwise_set(pset, "ISO", NULL, NULL, 0);
2148 }
2149 } else if (val & TF_HEX) {
2150 setting_bitwise_set(pset, "HEX", NULL, NULL, 0);
2151 } else {
2152 setting_bitwise_set(pset, "", NULL, NULL, 0);
2153 }
2154
2155 setting_value_name(pset, FALSE, buf, sizeof(buf));
2156 secfile_replace_str(loading->file, buf,
2157 "settings.set%d.gamestart", i);
2158
2159 secfile_insert_str(loading->file,
2160 wrap, "settings.set%d.gamestart", set_count);
2161 }
2162 }
2163
2164 set_count++;
2165 count_changed = TRUE;
2166 }
2167 } else if (!fc_strcasecmp("alltemperate", name)) {
2168 alltemperate_idx = i;
2169 } else if (!fc_strcasecmp("singlepole", name)) {
2170 singlepole_idx = i;
2171 }
2172 }
2173
2174 if (alltemperate_idx >= 0 || singlepole_idx >= 0) {
2175 int north_latitude, south_latitude;
2176 int north_idx, south_idx;
2177 bool alltemperate, singlepole;
2178
2179 if (alltemperate_idx < 0
2180 || !secfile_lookup_bool(loading->file, &alltemperate,
2181 "settings.set%d.value",
2182 alltemperate_idx)) {
2183 /* Infer what would've been the ruleset default */
2184 alltemperate = (wld.map.north_latitude == wld.map.south_latitude);
2185 }
2186
2187 if (singlepole_idx < 0
2188 || !secfile_lookup_bool(loading->file, &singlepole,
2189 "settings.set%d.value",
2190 singlepole_idx)) {
2191 /* Infer what would've been the ruleset default */
2192 singlepole = (wld.map.south_latitude >= 0);
2193 }
2194
2195 /* Note: hard-coding 1000-based latitudes here; if MAX_LATITUDE ever
2196 * changes, that'll have to be handled in later migrations anyway */
2197 north_latitude = alltemperate ? 500 : 1000;
2198 south_latitude = alltemperate ? 500 : (singlepole ? 0 : -1000);
2199
2200 /* Replace alltemperate with northlatitude, and singlepole with
2201 * southlatitude. If only one of the two was given, add the other
2202 * at the end. */
2203 north_idx = (alltemperate_idx < 0) ? set_count : alltemperate_idx;
2204 south_idx = (singlepole_idx < 0) ? set_count : singlepole_idx;
2205
2206 secfile_replace_str(loading->file, "northlatitude",
2207 "settings.set%d.name", north_idx);
2208 secfile_replace_int(loading->file, north_latitude,
2209 "settings.set%d.value", north_idx);
2210
2211 secfile_replace_str(loading->file, "southlatitude",
2212 "settings.set%d.name", south_idx);
2213 secfile_replace_int(loading->file, south_latitude,
2214 "settings.set%d.value", south_idx);
2215
2216 if (gamestart_valid) {
2217 if (alltemperate_idx < 0
2218 || !secfile_lookup_bool(loading->file, &alltemperate,
2219 "settings.set%d.gamestart",
2220 alltemperate_idx)) {
2221 alltemperate =
2222 (wld.map.north_latitude == wld.map.south_latitude);
2223 }
2224
2225 if (singlepole_idx < 0
2226 || !secfile_lookup_bool(loading->file, &singlepole,
2227 "settings.set%d.gamestart",
2228 singlepole_idx)) {
2229 singlepole = (wld.map.south_latitude >= 0);
2230 }
2231
2232 north_latitude = alltemperate ? 500 : 1000;
2233 south_latitude = alltemperate ? 500 : (singlepole ? 0 : -1000);
2234
2235 secfile_replace_int(loading->file, north_latitude,
2236 "settings.set%d.gamestart", north_idx);
2237 secfile_replace_int(loading->file, south_latitude,
2238 "settings.set%d.gamestart", south_idx);
2239 }
2240
2241 if (alltemperate_idx < 0 || singlepole_idx < 0) {
2242 /* only one was given and replaced ~> we added one new entry */
2243 set_count++;
2244 count_changed = TRUE;
2245 }
2246 }
2247
2248 if (count_changed) {
2249 secfile_replace_int(loading->file, set_count,
2250 "settings.set_count");
2251 }
2252 }
2253 }
2254
2255 {
2256 /* Turn old AI level field to a setting. */
2257 const char *level;
2258 enum ai_level lvl;
2259
2260 level = secfile_lookup_str_default(loading->file, NULL, "game.level");
2261 if (level != NULL && !fc_strcasecmp("Handicapped", level)) {
2262 /* Up to freeciv-3.1 Restricted AI level was known as Handicapped */
2263 lvl = AI_LEVEL_RESTRICTED;
2264 } else {
2265 lvl = ai_level_by_name(level, fc_strcasecmp);
2266 }
2267
2268 if (!ai_level_is_valid(lvl)) {
2269 log_sg("Invalid AI level \"%s\". "
2270 "Changed to \"%s\".", level,
2271 ai_level_name(GAME_HARDCODED_DEFAULT_SKILL_LEVEL));
2272 lvl = GAME_HARDCODED_DEFAULT_SKILL_LEVEL;
2273 }
2274
2275 secfile_insert_str(loading->file, "ailevel", "settings.set%d.name", set_count);
2276 secfile_insert_enum(loading->file, lvl, ai_level, "settings.set%d.value", set_count);
2277
2278 if (gamestart_valid) {
2279 secfile_insert_enum(loading->file, lvl, ai_level, "settings.set%d.gamestart",
2280 set_count);
2281 }
2282
2283 set_count++;
2284 secfile_replace_int(loading->file, set_count, "settings.set_count");
2285 }
2286
2287 if (format_class != SAVEGAME_2) {
2288 /* Replace got_tech[_multi] bools on free_bulbs integers. */
2289 /* Older savegames had a bug that got_tech_multi was not saved. */
2290 count = secfile_lookup_int_default(loading->file, 0, "research.count");
2291 for (i = 0; i < count; i++) {
2292 bool got_tech = FALSE;
2293 int bulbs = 0;
2294 bool got_tech_multi
2295 = secfile_lookup_bool_default(loading->file, FALSE,
2296 "research.r%d.got_tech_multi", i);
2297
2298 if (secfile_lookup_bool(loading->file, &got_tech,
2299 "research.r%d.got_tech", i)
2300 && secfile_lookup_int(loading->file, &bulbs,
2301 "research.r%d.bulbs", i)) {
2302 secfile_insert_int(loading->file,
2303 got_tech || got_tech_multi ? bulbs : 0,
2304 "research.r%d.free_bulbs", i);
2305 }
2306 }
2307 }
2308
2309 /* Older savegames unnecessarily saved diplstate type order.
2310 * Silence "unused entry" warnings about those. */
2311 {
2312 int dscount = secfile_lookup_int_default(loading->file, 0,
2313 "savefile.diplstate_type_size");
2314
2315 for (i = 0; i < dscount; i++) {
2316 (void) secfile_entry_lookup(loading->file,
2317 "savefile.diplstate_type_vector,%d", i);
2318 }
2319 }
2320
2321 /* Add wl_max_length entries for players */
2322 {
2323 player_slots_iterate(pslot) {
2324 int plrno = player_slot_index(pslot);
2325 int ncities;
2326 int cnro;
2327 size_t wlist_max_length = 0;
2328 bool first_city;
2329
2330 if (secfile_section_lookup(loading->file, "player%d", plrno) == NULL) {
2331 continue;
2332 }
2333
2334 first_city = secfile_lookup_bool_default(loading->file, FALSE,
2335 "player%d.got_first_city",
2336 plrno);
2337 if (first_city) {
2338 const char **flag_names = fc_calloc(PLRF_COUNT, sizeof(char *));
2339 int flagcount = 0;
2340 const char **flags_sg;
2341 size_t nval;
2342
2343 flag_names[flagcount++] = plr_flag_id_name(PLRF_FIRST_CITY);
2344
2345 flags_sg = secfile_lookup_str_vec(loading->file, &nval,
2346 "player%d.flags", plrno);
2347
2348 for (i = 0; i < nval; i++) {
2349 enum plr_flag_id fid = plr_flag_id_by_name(flags_sg[i],
2350 fc_strcasecmp);
2351
2352 flag_names[flagcount++] = plr_flag_id_name(fid);
2353 }
2354
2355 secfile_replace_str_vec(loading->file, flag_names, flagcount,
2356 "player%d.flags", plrno);
2357
2358 free(flag_names);
2359 }
2360
2361 ncities = secfile_lookup_int_default(loading->file, 0,
2362 "player%d.ncities", plrno);
2363
2364 for (cnro = 0; cnro < ncities; cnro++) {
2365 int wl_length = secfile_lookup_int_default(loading->file, 0,
2366 "player%d.c%d.wl_length",
2367 plrno, cnro);
2368
2369 wlist_max_length = MAX(wlist_max_length, wl_length);
2370
2371 if (format_class == SAVEGAME_3) {
2372 if (secfile_lookup_int_default(loading->file, plrno,
2373 "player%d.c%d.original",
2374 plrno, cnro) != plrno) {
2375 secfile_insert_int(loading->file, CACQ_CONQUEST,
2376 "player%d.c%d.acquire_t",
2377 plrno, cnro);
2378 } else {
2379 secfile_insert_int(loading->file, CACQ_FOUNDED,
2380 "player%d.c%d.acquire_t",
2381 plrno, cnro);
2382 }
2383
2384 secfile_insert_int(loading->file, WLCB_SMART,
2385 "player%d.c%d.wlcb",
2386 plrno, cnro);
2387 }
2388 }
2389
2390 secfile_insert_int(loading->file, wlist_max_length,
2391 "player%d.wl_max_length", plrno);
2392
2393 if (format_class == SAVEGAME_3) {
2394 int nunits;
2395 int unro;
2396 size_t olist_max_length = 0;
2397
2398 nunits = secfile_lookup_int_default(loading->file, 0,
2399 "player%d.nunits", plrno);
2400
2401 for (unro = 0; unro < nunits; unro++) {
2402 int ol_length = secfile_lookup_int_default(loading->file, 0,
2403 "player%d.u%d.orders_length",
2404 plrno, unro);
2405
2406 olist_max_length = MAX(olist_max_length, ol_length);
2407 }
2408
2409 secfile_insert_int(loading->file, olist_max_length,
2410 "player%d.orders_max_length", plrno);
2411
2412 secfile_insert_int(loading->file, MAX_TRADE_ROUTES_OLD,
2413 "player%d.routes_max_length", plrno);
2414 }
2415
2416 } player_slots_iterate_end;
2417 }
2418}
2419
2420/************************************************************************/
2424#ifdef FREECIV_DEV_SAVE_COMPAT
2425static void compat_load_dev(struct loaddata *loading)
2426{
2427 int game_version;
2428
2429 /* Check status and return if not OK (sg_success FALSE). */
2430 sg_check_ret();
2431
2432 log_debug("Upgrading data between development revisions");
2433
2434 if (!secfile_lookup_int(loading->file, &game_version, "scenario.game_version")) {
2435 game_version = 2060000;
2436 }
2437
2438#ifdef FREECIV_DEV_SAVE_COMPAT_3_2
2439
2440 if (game_version < 3019100) {
2441 /* Before version number bump to 3.1.91 */
2442 int i;
2443 int count;
2444
2445 /* Older savegames had a bug that got_tech_multi was not saved.
2446 * Insert the entry to such savegames */
2447
2448 /* May be unsaved (e.g. scenario case). */
2449 count = secfile_lookup_int_default(loading->file, 0, "research.count");
2450 for (i = 0; i < count; i++) {
2451 if (secfile_entry_lookup(loading->file,
2452 "research.r%d.got_tech_multi", i) == NULL) {
2453 /* Default to FALSE */
2454 secfile_insert_bool(loading->file, FALSE,
2455 "research.r%d.got_tech_multi", i);
2456 }
2457 }
2458 } /* Version < 3.1.91 */
2459
2460 if (game_version < 3019200) {
2461 /* Before version number bump to 3.1.92, August 2022 */
2462 int set_count;
2463 bool gamestart_valid = FALSE;
2464 bool al_set_already = FALSE;
2465 bool wrap_set_already = FALSE;
2466 const char *level;
2467 bool count_changed = FALSE;
2468 bool topo_defined = FALSE;
2469 char wrap[100];
2470 char wrap_gs[100];
2471
2472 if (secfile_lookup_int(loading->file, &set_count, "settings.set_count")) {
2473 int i;
2474 gamestart_valid
2475 = secfile_lookup_bool_default(loading->file, FALSE,
2476 "settings.gamestart_valid");
2477
2478 for (i = 0; i < set_count; i++) {
2479 const char *old_name
2480 = secfile_lookup_str(loading->file, "settings.set%d.name", i);
2481 const char *name;
2482
2483 if (!old_name) {
2484 continue;
2485 }
2486
2487 name = setcompat_S3_2_name_from_S3_1(old_name);
2488
2489 if (fc_strcasecmp(old_name, name)) {
2490 /* Setting's name changed */
2491 secfile_replace_str(loading->file, name, "settings.set%d.name", i);
2492 }
2493
2494 if (!fc_strcasecmp("compresstype", name)) {
2495 const char *val = secfile_lookup_str(loading->file,
2496 "settings.set%d.value", i);
2497
2498 if (!fc_strcasecmp(val, "BZIP2")) {
2499#ifdef FREECIV_HAVE_LIBZSTD
2500 secfile_replace_str(loading->file, "ZSTD",
2501 "settings.set%d.value", i);
2502#elif FREECIV_HAVE_LIBLZMA
2503 secfile_replace_str(loading->file, "XZ",
2504 "settings.set%d.value", i);
2505#elif FREECIV_HAVE_LIBZ
2506 secfile_replace_str(loading->file, "LIBZ",
2507 "settings.set%d.value", i);
2508#else
2509 secfile_replace_str(loading->file, "PLAIN",
2510 "settings.set%d.value", i);
2511#endif
2512 }
2513
2514 if (gamestart_valid) {
2515 val = secfile_lookup_str(loading->file,
2516 "settings.set%d.gamestart", i);
2517 if (!fc_strcasecmp(val, "BZIP2")) {
2518#ifdef FREECIV_HAVE_LIBZSTD
2519 secfile_replace_str(loading->file, "ZSTD",
2520 "settings.set%d.gamestart", i);
2521#elif FREECIV_HAVE_LIBLZMA
2522 secfile_replace_str(loading->file, "XZ",
2523 "settings.set%d.gamestart", i);
2524#elif FREECIV_HAVE_LIBZ
2525 secfile_replace_str(loading->file, "LIBZ",
2526 "settings.set%d.gamestart", i);
2527#else
2528 secfile_replace_str(loading->file, "PLAIN",
2529 "settings.set%d.gamestart", i);
2530#endif
2531 }
2532 }
2533 } else if (!fc_strcasecmp("ailevel", name)) {
2534 al_set_already = TRUE;
2535 } else if (!fc_strcasecmp("topology", name)) {
2536 struct setting *pset = setting_by_name(name);
2537 struct sf_cb_data info = { pset, TRUE };
2538 int val;
2539
2540 if (secfile_lookup_enum_data(loading->file, &val, TRUE,
2541 setting_bitwise_secfile_str, &info,
2542 "settings.set%d.value", i)) {
2543 bool topo_changed = TRUE;
2544
2545 if (val & TF_OLD_WRAPX) {
2546 if (val & TF_OLD_WRAPY) {
2547 fc_strlcpy(wrap, "WrapX|WrapY", sizeof(wrap));
2548 } else {
2549 fc_strlcpy(wrap, "WrapX", sizeof(wrap));
2550 }
2551 } else if (val & TF_OLD_WRAPY) {
2552 fc_strlcpy(wrap, "WrapY", sizeof(wrap));
2553 } else {
2554 fc_strlcpy(wrap, "", sizeof(wrap));
2555 topo_changed = FALSE;
2556 }
2557
2558 if (topo_changed) {
2559 char buf[100];
2560
2561 if (val & TF_ISO) {
2562 if (val & TF_HEX) {
2563 setting_bitwise_set(pset, "ISO|HEX", NULL, NULL, 0);
2564 } else {
2565 setting_bitwise_set(pset, "ISO", NULL, NULL, 0);
2566 }
2567 } else if (val & TF_HEX) {
2568 setting_bitwise_set(pset, "HEX", NULL, NULL, 0);
2569 } else {
2570 setting_bitwise_set(pset, "", NULL, NULL, 0);
2571 }
2572
2573 setting_value_name(pset, FALSE, buf, sizeof(buf));
2574 secfile_replace_str(loading->file, buf,
2575 "settings.set%d.value", i);
2576 }
2577
2578 if (gamestart_valid) {
2579 if (secfile_lookup_enum_data(loading->file, &val, TRUE,
2580 setting_bitwise_secfile_str, &info,
2581 "settings.set%d.gamestart", i)) {
2582 topo_changed = TRUE;
2583
2584 if (val & TF_OLD_WRAPX) {
2585 if (val & TF_OLD_WRAPY) {
2586 fc_strlcpy(wrap_gs, "WrapX|WrapY", sizeof(wrap));
2587 } else {
2588 fc_strlcpy(wrap_gs, "WrapX", sizeof(wrap));
2589 }
2590 } else if (val & TF_OLD_WRAPY) {
2591 fc_strlcpy(wrap_gs, "WrapY", sizeof(wrap));
2592 } else {
2593 fc_strlcpy(wrap_gs, "", sizeof(wrap));
2594 topo_changed = FALSE;
2595 }
2596
2597 if (topo_changed) {
2598 char buf[100];
2599
2600 if (val & TF_ISO) {
2601 if (val & TF_HEX) {
2602 setting_bitwise_set(pset, "ISO|HEX", NULL, NULL, 0);
2603 } else {
2604 setting_bitwise_set(pset, "ISO", NULL, NULL, 0);
2605 }
2606 } else if (val & TF_HEX) {
2607 setting_bitwise_set(pset, "HEX", NULL, NULL, 0);
2608 } else {
2609 setting_bitwise_set(pset, "", NULL, NULL, 0);
2610 }
2611
2612 setting_value_name(pset, FALSE, buf, sizeof(buf));
2613 secfile_replace_str(loading->file, buf,
2614 "settings.set%d.gamestart", i);
2615 }
2616 }
2617 }
2618
2619 topo_defined = TRUE;
2620 }
2621 } else if (!fc_strcasecmp("wrap", name)) {
2622 wrap_set_already = TRUE;
2623 }
2624 }
2625 }
2626
2627 if (!al_set_already) {
2628 level = secfile_lookup_str_default(loading->file, NULL, "game.level");
2629 if (level == NULL) {
2630 /* Assume that this was a new format savegame after all,
2631 * setting just has not been explicitly saved for containing default value. */
2632 al_set_already = TRUE;
2633 }
2634 }
2635
2636 if (!al_set_already) {
2637 /* Turn old AI level field to a setting. */
2638 enum ai_level lvl;
2639
2640 if (level != NULL && !fc_strcasecmp("Handicapped", level)) {
2641 /* Up to freeciv-3.1 Restricted AI level was known as Handicapped */
2642 lvl = AI_LEVEL_RESTRICTED;
2643 } else {
2644 lvl = ai_level_by_name(level, fc_strcasecmp);
2645 }
2646
2647 if (!ai_level_is_valid(lvl)) {
2648 log_sg("Invalid AI level \"%s\". "
2649 "Changed to \"%s\".", level,
2650 ai_level_name(GAME_HARDCODED_DEFAULT_SKILL_LEVEL));
2651 lvl = GAME_HARDCODED_DEFAULT_SKILL_LEVEL;
2652 }
2653
2654 secfile_insert_str(loading->file, "ailevel", "settings.set%d.name", set_count);
2655 secfile_insert_enum(loading->file, lvl, ai_level, "settings.set%d.value", set_count);
2656
2657 if (gamestart_valid) {
2658 secfile_insert_enum(loading->file, lvl, ai_level, "settings.set%d.gamestart",
2659 set_count);
2660 }
2661
2662 set_count++;
2663 count_changed = TRUE;
2664 }
2665
2666 if (!wrap_set_already && topo_defined) {
2667 secfile_insert_str(loading->file, "wrap", "settings.set%d.name", set_count);
2668 secfile_insert_str(loading->file, wrap, "settings.set%d.value", set_count);
2669
2670 if (gamestart_valid) {
2671 secfile_insert_str(loading->file, wrap_gs, "settings.set%d.value", set_count);
2672 }
2673
2674 set_count++;
2675 count_changed = TRUE;
2676 }
2677
2678 if (count_changed) {
2679 secfile_replace_int(loading->file, set_count, "settings.set_count");
2680 }
2681
2682 {
2683 int action_count;
2684
2685 action_count = secfile_lookup_int_default(loading->file, 0,
2686 "savefile.action_size");
2687
2688 if (action_count > 0) {
2689 const char **modname;
2690 const char **savemod;
2691 int j;
2692 const char *dur_name = "Disband Unit Recover";
2693
2694 modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
2695 "savefile.action_vector");
2696
2697 savemod = fc_calloc(action_count, sizeof(*savemod));
2698
2699 for (j = 0; j < action_count; j++) {
2700 if (!fc_strcasecmp("Recycle Unit", modname[j])) {
2701 savemod[j] = dur_name;
2702 } else {
2703 savemod[j] = modname[j];
2704 }
2705 }
2706
2707 secfile_replace_str_vec(loading->file, savemod, action_count,
2708 "savefile.action_vector");
2709
2710 free(savemod);
2711 }
2712 }
2713
2714 player_slots_iterate(pslot) {
2715 int plrno = player_slot_index(pslot);
2716 int wonder_city = secfile_lookup_int_default(loading->file, -1,
2717 "player%d.adv.wonder_city",
2718 plrno);
2719 if (wonder_city < 0) {
2720 /* No wonder_city saved with the new name. Check for the old name */
2721 wonder_city = secfile_lookup_int_default(loading->file, -1,
2722 "player%d.wonder_city",
2723 plrno);
2724 if (wonder_city >= 0) {
2725 secfile_replace_int(loading->file, wonder_city,
2726 "player%d.adv.wonder_city", plrno);
2727 }
2728 }
2729 } player_slots_iterate_end;
2730 } /* Version < 3.1.92 */
2731
2732 if (game_version < 3019300) {
2733 /* Before version number bump to 3.1.93 */
2734
2735 /* Older savegames unnecessarily saved diplstate type order.
2736 * Silence "unused entry" warnings about those. */
2737 {
2738 int dscount = secfile_lookup_int_default(loading->file, 0,
2739 "savefile.diplstate_type_size");
2740 int i;
2741
2742 for (i = 0; i < dscount; i++) {
2743 (void) secfile_entry_lookup(loading->file,
2744 "savefile.diplstate_type_vector,%d", i);
2745 }
2746 }
2747
2748 (void) secfile_entry_lookup(loading->file, "game.hardcoded_counters");
2749
2750 /* Add wl_max_length and orders_max_length entries for players */
2751 {
2752 player_slots_iterate(pslot) {
2753 int plrno = player_slot_index(pslot);
2754 int ncities, nunits;
2755 int cnro, unro;
2756 size_t wlist_max_length = 0;
2757 size_t olist_max_length = 0;
2758
2759 if (secfile_section_lookup(loading->file, "player%d", plrno) == NULL) {
2760 continue;
2761 }
2762
2763 ncities = secfile_lookup_int_default(loading->file, 0,
2764 "player%d.ncities", plrno);
2765
2766 for (cnro = 0; cnro < ncities; cnro++) {
2767 int wl_length = secfile_lookup_int_default(loading->file, 0,
2768 "player%d.c%d.wl_length",
2769 plrno, cnro);
2770
2771 wlist_max_length = MAX(wlist_max_length, wl_length);
2772
2773 if (secfile_entry_lookup(loading->file,
2774 "player%d.c%d.acquire_t",
2775 plrno, cnro) == NULL) {
2776 if (secfile_lookup_int_default(loading->file, plrno,
2777 "player%d.c%d.original",
2778 plrno, cnro) != plrno) {
2779 secfile_insert_int(loading->file, CACQ_CONQUEST,
2780 "player%d.c%d.acquire_t",
2781 plrno, cnro);
2782 } else {
2783 secfile_insert_int(loading->file, CACQ_FOUNDED,
2784 "player%d.c%d.acquire_t",
2785 plrno, cnro);
2786 }
2787 }
2788 if (secfile_entry_lookup(loading->file,
2789 "player%d.c%d.wlcb",
2790 plrno, cnro) == NULL) {
2791 secfile_insert_int(loading->file, WLCB_SMART,
2792 "player%d.c%d.wlcb",
2793 plrno, cnro);
2794 }
2795 }
2796
2797 secfile_insert_int(loading->file, wlist_max_length,
2798 "player%d.wl_max_length", plrno);
2799
2800 nunits = secfile_lookup_int_default(loading->file, 0,
2801 "player%d.nunits", plrno);
2802
2803 for (unro = 0; unro < nunits; unro++) {
2804 int ol_length
2805 = secfile_lookup_int_default(loading->file, 0,
2806 "player%d.u%d.orders_length",
2807 plrno, unro);
2808
2809 olist_max_length = MAX(olist_max_length, ol_length);
2810 }
2811
2812 secfile_insert_int(loading->file, olist_max_length,
2813 "player%d.orders_max_length", plrno);
2814
2815 secfile_insert_int(loading->file, MAX_TRADE_ROUTES_OLD,
2816 "player%d.routes_max_length", plrno);
2817 } player_slots_iterate_end;
2818 }
2819
2820 /* Replace got_tech[_multi] bools on free_bulbs integers. */
2821 {
2822 int count = secfile_lookup_int_default(loading->file, 0, "research.count");
2823
2824 for (int i = 0; i < count; i++) {
2825 bool got_tech = FALSE;
2826 int bulbs = 0;
2827 bool got_tech_multi
2828 = secfile_lookup_bool_default(loading->file, FALSE,
2829 "research.r%d.got_tech_multi", i);
2830
2831 if (secfile_lookup_bool(loading->file, &got_tech,
2832 "research.r%d.got_tech", i)
2833 && secfile_lookup_int(loading->file, &bulbs,
2834 "research.r%d.bulbs", i)) {
2835 secfile_insert_int(loading->file,
2836 got_tech || got_tech_multi ? bulbs : 0,
2837 "research.r%d.free_bulbs", i);
2838 }
2839 }
2840 }
2841
2842 /* Convert 'alltemperate' and 'singlepole' into 'northlatitude' and
2843 * 'southlatitude' server settings */
2844 {
2845 int i;
2846 int set_count = secfile_lookup_int_default(loading->file, 0,
2847 "settings.set_count");
2848 int alltemperate_idx = -1, singlepole_idx = -1;
2849
2850 for (i = 0; i < set_count; i++) {
2851 const char *name
2852 = secfile_lookup_str(loading->file, "settings.set%d.name", i);
2853
2854 if (!name) {
2855 continue;
2856 }
2857
2858 if (!fc_strcasecmp("northlatitude", name)
2859 || !fc_strcasecmp("southlatitude", name)) {
2860 /* this savegame is recent enough to already have latitude
2861 * settings ~> no change necessary */
2862 alltemperate_idx = singlepole_idx = -1;
2863 break;
2864 }
2865
2866 if (!fc_strcasecmp("alltemperate", name)) {
2867 alltemperate_idx = i;
2868 } else if (!fc_strcasecmp("singlepole", name)) {
2869 singlepole_idx = i;
2870 }
2871 }
2872
2873 if (alltemperate_idx >= 0 || singlepole_idx >= 0) {
2874 int north_latitude, south_latitude;
2875 int north_idx, south_idx;
2876 bool alltemperate, singlepole;
2877
2878 if (alltemperate_idx < 0
2879 || !secfile_lookup_bool(loading->file, &alltemperate,
2880 "settings.set%d.value",
2881 alltemperate_idx)) {
2882 /* infer what would've been the ruleset default */
2883 alltemperate = (wld.map.north_latitude == wld.map.south_latitude);
2884 }
2885
2886 if (singlepole_idx < 0
2887 || !secfile_lookup_bool(loading->file, &singlepole,
2888 "settings.set%d.value",
2889 singlepole_idx)) {
2890 /* infer what would've been the ruleset default */
2891 singlepole = (wld.map.south_latitude >= 0);
2892 }
2893
2894 /* Note: hard-coding 1000-based latitudes here; if MAX_LATITUDE ever
2895 * changes, that'll have to be handled in later migrations anyway */
2896 north_latitude = alltemperate ? 500 : 1000;
2897 south_latitude = alltemperate ? 500 : (singlepole ? 0 : -1000);
2898
2899 /* Replace alltemperate with northlatitude, and singlepole with
2900 * southlatitude. If only one of the two was given, add the other
2901 * at the end. */
2902 north_idx = (alltemperate_idx < 0) ? set_count : alltemperate_idx;
2903 south_idx = (singlepole_idx < 0) ? set_count : singlepole_idx;
2904
2905 secfile_replace_str(loading->file, "northlatitude",
2906 "settings.set%d.name", north_idx);
2907 secfile_replace_int(loading->file, north_latitude,
2908 "settings.set%d.value", north_idx);
2909
2910 secfile_replace_str(loading->file, "southlatitude",
2911 "settings.set%d.name", south_idx);
2912 secfile_replace_int(loading->file, south_latitude,
2913 "settings.set%d.value", south_idx);
2914
2915 if (secfile_lookup_bool_default(loading->file, FALSE,
2916 "settings.gamestart_valid")) {
2917 if (alltemperate_idx < 0
2918 || !secfile_lookup_bool(loading->file, &alltemperate,
2919 "settings.set%d.gamestart",
2920 alltemperate_idx)) {
2921 alltemperate =
2922 (wld.map.north_latitude == wld.map.south_latitude);
2923 }
2924
2925 if (singlepole_idx < 0
2926 || !secfile_lookup_bool(loading->file, &singlepole,
2927 "settings.set%d.gamestart",
2928 singlepole_idx)) {
2929 singlepole = (wld.map.south_latitude >= 0);
2930 }
2931
2932 north_latitude = alltemperate ? 500 : 1000;
2933 south_latitude = alltemperate ? 500 : (singlepole ? 0 : -1000);
2934
2935 secfile_replace_int(loading->file, north_latitude,
2936 "settings.set%d.gamestart", north_idx);
2937 secfile_replace_int(loading->file, south_latitude,
2938 "settings.set%d.gamestart", south_idx);
2939 }
2940
2941 if (alltemperate_idx < 0 || singlepole_idx < 0) {
2942 /* only one was given and replaced ~> we added one new entry */
2943 set_count++;
2944 secfile_replace_int(loading->file, set_count,
2945 "settings.set_count");
2946 }
2947 }
2948 }
2949
2950 {
2951 int action_count;
2952
2953 action_count = secfile_lookup_int_default(loading->file, 0,
2954 "savefile.action_size");
2955
2956 if (action_count > 0) {
2957 const char **modname;
2958 const char **savemod;
2959 int j;
2960 const char *dur_name = "Transport Deboard";
2961
2962 modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
2963 "savefile.action_vector");
2964
2965 savemod = fc_calloc(action_count, sizeof(*savemod));
2966
2967 for (j = 0; j < action_count; j++) {
2968 if (!fc_strcasecmp("Transport Alight", modname[j])) {
2969 savemod[j] = dur_name;
2970 } else {
2971 savemod[j] = modname[j];
2972 }
2973 }
2974
2975 secfile_replace_str_vec(loading->file, savemod, action_count,
2976 "savefile.action_vector");
2977
2978 free(savemod);
2979 }
2980 }
2981
2982 {
2983 const char *str = secfile_lookup_str_default(loading->file, NULL,
2984 "savefile.orig_version");
2985
2986 if (str == NULL) {
2987 /* Make sure CURRENTLY running version does not
2988 * end as orig_version when we resave. */
2989 secfile_insert_str(loading->file, "old savegame3, or older",
2990 "savefile.orig_version");
2991 }
2992 }
2993
2994 } /* Version < 3.1.93 */
2995
2996 if (game_version < 3019400) {
2997 /* Before version number bump to 3.1.94, January 2024 */
2998
2999 {
3000 int action_count;
3001
3002 action_count = secfile_lookup_int_default(loading->file, 0,
3003 "savefile.action_size");
3004
3005 if (action_count > 0) {
3006 const char **modname;
3007 const char **savemod;
3008 int j;
3009 const char *clean_name = "Clean";
3010
3011 modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
3012 "savefile.action_vector");
3013
3014 savemod = fc_calloc(action_count, sizeof(*savemod));
3015
3016 for (j = 0; j < action_count; j++) {
3017 if (!fc_strcasecmp("Clean Pollution", modname[j])
3018 || !fc_strcasecmp("Clean Fallout", modname[j])) {
3019 savemod[j] = clean_name;
3020 } else {
3021 savemod[j] = modname[j];
3022 }
3023 }
3024
3025 secfile_replace_str_vec(loading->file, savemod, action_count,
3026 "savefile.action_vector");
3027
3028 free(savemod);
3029 }
3030 }
3031
3032 {
3033 int activities_count;
3034
3035 activities_count = secfile_lookup_int_default(loading->file, 0,
3036 "savefile.activities_size");
3037
3038 if (activities_count > 0) {
3039 const char **modname;
3040 const char **savemod;
3041 int j;
3042 const char *clean_name = "Clean";
3043
3044 modname = secfile_lookup_str_vec(loading->file, &loading->activities.size,
3045 "savefile.activities_vector");
3046
3047 savemod = fc_calloc(activities_count, sizeof(*savemod));
3048
3049 for (j = 0; j < activities_count; j++) {
3050 if (!fc_strcasecmp("Pollution", modname[j])
3051 || !fc_strcasecmp("Fallout", modname[j])) {
3052 savemod[j] = clean_name;
3053 } else {
3054 savemod[j] = modname[j];
3055 }
3056 }
3057
3058 secfile_replace_str_vec(loading->file, savemod, activities_count,
3059 "savefile.activities_vector");
3060
3061 free(savemod);
3062 }
3063 }
3064
3065 /* Server setting migration. */
3066 {
3067 int set_count;
3068
3069 if (secfile_lookup_int(loading->file, &set_count, "settings.set_count")) {
3070 bool gamestart_valid = FALSE;
3071
3072 gamestart_valid
3073 = secfile_lookup_bool_default(loading->file, FALSE,
3074 "settings.gamestart_valid");
3075
3076 if (!gamestart_valid) {
3077 int i;
3078
3079 /* Older savegames saved gamestart values even when they were not valid.
3080 * Silence warnings caused by them. */
3081 for (i = 0; i < set_count; i++) {
3082 (void) secfile_entry_lookup(loading->file, "settings.set%d.gamestart", i);
3083 (void) secfile_entry_lookup(loading->file, "settings.set%d.gamesetdef", i);
3084 }
3085 }
3086 }
3087 }
3088
3089 {
3090 player_slots_iterate(pslot) {
3091 int plrno = player_slot_index(pslot);
3092 bool first_city;
3093
3094 if (secfile_section_lookup(loading->file, "player%d", plrno) == NULL) {
3095 continue;
3096 }
3097
3098 first_city = secfile_lookup_bool_default(loading->file, FALSE,
3099 "player%d.got_first_city",
3100 plrno);
3101
3102 if (first_city) {
3103 const char **flag_names = fc_calloc(PLRF_COUNT, sizeof(char *));
3104 int flagcount = 0;
3105 const char **flags_sg;
3106 size_t nval;
3107 int i;
3108
3109 flag_names[flagcount++] = plr_flag_id_name(PLRF_FIRST_CITY);
3110
3111 flags_sg = secfile_lookup_str_vec(loading->file, &nval,
3112 "player%d.flags", plrno);
3113
3114 for (i = 0; i < nval; i++) {
3115 enum plr_flag_id fid = plr_flag_id_by_name(flags_sg[i],
3116 fc_strcasecmp);
3117
3118 flag_names[flagcount++] = plr_flag_id_name(fid);
3119 }
3120
3121 secfile_replace_str_vec(loading->file, flag_names, flagcount,
3122 "player%d.flags", plrno);
3123
3124 free(flag_names);
3125 }
3126 } player_slots_iterate_end;
3127 }
3128
3129 } /* Version < 3.1.94 */
3130
3131 if (game_version < 3019500) {
3132 /* Before version number bump to 3.1.95 */
3133
3134 } /* Version < 3.1.95 */
3135
3136#endif /* FREECIV_DEV_SAVE_COMPAT_3_2 */
3137}
3138
3139/************************************************************************/
3143static void compat_post_load_dev(struct loaddata *loading)
3144{
3145 int game_version;
3146
3147 /* Check status and return if not OK (sg_success FALSE). */
3148 sg_check_ret();
3149
3150 if (!secfile_lookup_int(loading->file, &game_version, "scenario.game_version")) {
3151 game_version = 2060000;
3152 }
3153
3154#ifdef FREECIV_DEV_SAVE_COMPAT_3_2
3155
3156 if (game_version < 3019100) {
3157 /* Before version number bump to 3.1.91 */
3158
3159 } /* Version < 3.1.91 */
3160
3161#endif /* FREECIV_DEV_SAVE_COMPAT_3_2 */
3162}
3163#endif /* FREECIV_DEV_SAVE_COMPAT */
3164
3165/************************************************************************/
3168 enum ai_level ai_level_convert(int old_level)
3169{
3170 switch (old_level) {
3171 case 1:
3172 return AI_LEVEL_AWAY;
3173 case 2:
3174 return AI_LEVEL_NOVICE;
3175 case 3:
3176 return AI_LEVEL_EASY;
3177 case 5:
3178 return AI_LEVEL_NORMAL;
3179 case 7:
3180 return AI_LEVEL_HARD;
3181 case 8:
3182 return AI_LEVEL_CHEATING;
3183 case 10:
3184#ifdef FREECIV_DEBUG
3185 return AI_LEVEL_EXPERIMENTAL;
3186#else /* FREECIV_DEBUG */
3187 return AI_LEVEL_HARD;
3188#endif /* FREECIV_DEBUG */
3189 }
3190
3191 return ai_level_invalid();
3192}
3193
3194/************************************************************************/
3197 enum barbarian_type barb_type_convert(int old_type)
3198{
3199 switch (old_type) {
3200 case 0:
3201 return NOT_A_BARBARIAN;
3202 case 1:
3203 return LAND_BARBARIAN;
3204 case 2:
3205 return SEA_BARBARIAN;
3206 }
3207
3208 return barbarian_type_invalid();
3209}
action_number
int action_number(const struct action *action)
Definition actions.c:1960
action_by_number
static struct action * action_by_number(action_id act_id)
Definition actions.h:633
action_iterate_end
#define action_iterate_end
Definition actions.h:463
action_get_activity
#define action_get_activity(_pact_)
Definition actions.h:697
action_iterate
#define action_iterate(_act_)
Definition actions.h:459
entries
struct @126::my_agent entries[MAX_AGENTS]
default_ai_type_name
const char * default_ai_type_name(void)
Definition aiiface.c:266
aiiface.h
str
#define str
Definition astring.c:76
has_capability
bool has_capability(const char *cap, const char *capstr)
Definition capability.c:77
capability.h
incite_cost
char * incite_cost
Definition comments.c:74
punit
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit * punit
Definition dialogs_g.h:74
extra_type_list_by_cause
struct extra_type_list * extra_type_list_by_cause(enum extra_cause cause)
Definition extras.c:249
extra_type_by_cause_iterate_end
#define extra_type_by_cause_iterate_end
Definition extras.h:339
extra_type_by_cause_iterate
#define extra_type_by_cause_iterate(_cause, _extra)
Definition extras.h:333
NO_TARGET
#define NO_TARGET
Definition fc_types.h:357
EC_SPECIAL
#define EC_SPECIAL
Definition fc_types.h:1115
revolen_type
revolen_type
Definition fc_types.h:1283
REVOLEN_RANDOM
@ REVOLEN_RANDOM
Definition fc_types.h:1285
REVOLEN_RANDQUICK
@ REVOLEN_RANDQUICK
Definition fc_types.h:1287
REVOLEN_FIXED
@ REVOLEN_FIXED
Definition fc_types.h:1284
REVOLEN_QUICKENING
@ REVOLEN_QUICKENING
Definition fc_types.h:1286
DIR8_ORIGIN
#define DIR8_ORIGIN
Definition fc_types.h:460
_
#define _(String)
Definition fcintl.h:67
wld
struct world wld
Definition game.c:63
GAME_DEFAULT_REVOLENTYPE
#define GAME_DEFAULT_REVOLENTYPE
Definition game.h:734
GAME_DEFAULT_SCORETURN
#define GAME_DEFAULT_SCORETURN
Definition game.h:578
GAME_DEFAULT_SAVETURNS
#define GAME_DEFAULT_SAVETURNS
Definition game.h:676
GAME_DEFAULT_TEAM_POOLED_RESEARCH
#define GAME_DEFAULT_TEAM_POOLED_RESEARCH
Definition game.h:562
GAME_HARDCODED_DEFAULT_SKILL_LEVEL
#define GAME_HARDCODED_DEFAULT_SKILL_LEVEL
Definition game.h:694
type
GType type
Definition repodlgs.c:1313
name
const char * name
Definition inputfile.c:127
log.h
fc_assert
#define fc_assert(condition)
Definition log.h:176
fc_assert_action
#define fc_assert_action(condition, action)
Definition log.h:187
log_debug
#define log_debug(message,...)
Definition log.h:115
log_normal
#define log_normal(message,...)
Definition log.h:107
log_error
#define log_error(message,...)
Definition log.h:103
index_to_tile
struct tile * index_to_tile(const struct civ_map *imap, int mindex)
Definition map.c:456
mapstep
struct tile * mapstep(const struct civ_map *nmap, const struct tile *ptile, enum direction8 dir)
Definition map.c:371
map.h
fc_calloc
#define fc_calloc(n, esz)
Definition mem.h:38
FC_FREE
#define FC_FREE(ptr)
Definition mem.h:41
fc_strdup
#define fc_strdup(str)
Definition mem.h:43
lines
char * lines
Definition packhand.c:131
len
int len
Definition packhand.c:127
player_slot_count
int player_slot_count(void)
Definition player.c:418
player_slot_index
int player_slot_index(const struct player_slot *pslot)
Definition player.c:426
ANON_USER_NAME
#define ANON_USER_NAME
Definition player.h:48
player_slots_iterate
#define player_slots_iterate(_pslot)
Definition player.h:523
players_iterate_alive_end
#define players_iterate_alive_end
Definition player.h:547
player_slots_iterate_end
#define player_slots_iterate_end
Definition player.h:527
players_iterate_alive
#define players_iterate_alive(_pplayer)
Definition player.h:542
secfile_error
const char * secfile_error(void)
Definition section_file.c:36
secfile_lookup_int
bool secfile_lookup_int(const struct section_file *secfile, int *ival, const char *path,...)
Definition registry_ini.c:1975
secfile_entry_delete
bool secfile_entry_delete(struct section_file *secfile, const char *path,...)
Definition registry_ini.c:1831
entry_set_name
bool entry_set_name(struct entry *pentry, const char *name)
Definition registry_ini.c:3365
secfile_lookup_enum_data
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,...)
Definition registry_ini.c:2609
section_entries
const struct entry_list * section_entries(const struct section *psection)
Definition registry_ini.c:3073
secfile_lookup_str_vec
const char ** secfile_lookup_str_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
Definition registry_ini.c:2239
entry_name
const char * entry_name(const struct entry *pentry)
Definition registry_ini.c:3357
secfile_entry_lookup
struct entry * secfile_entry_lookup(const struct section_file *secfile, const char *path,...)
Definition registry_ini.c:1857
secfile_lookup_str
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
Definition registry_ini.c:2175
secfile_lookup_bool_default
bool secfile_lookup_bool_default(const struct section_file *secfile, bool def, const char *path,...)
Definition registry_ini.c:1900
secfile_lookup_int_default
int secfile_lookup_int_default(const struct section_file *secfile, int def, const char *path,...)
Definition registry_ini.c:2000
secfile_section_by_name
struct section * secfile_section_by_name(const struct section_file *secfile, const char *name)
Definition registry_ini.c:2823
secfile_section_lookup
struct section * secfile_section_lookup(const struct section_file *secfile, const char *path,...)
Definition registry_ini.c:2840
secfile_lookup_str_default
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
Definition registry_ini.c:2205
secfile_lookup_bool
bool secfile_lookup_bool(const struct section_file *secfile, bool *bval, const char *path,...)
Definition registry_ini.c:1875
secfile_replace_str_vec
#define secfile_replace_str_vec(secfile, strings, dim, path,...)
Definition registry_ini.h:215
secfile_insert_int
#define secfile_insert_int(secfile, value, path,...)
Definition registry_ini.h:116
secfile_insert_enum
#define secfile_insert_enum(secfile, enumerator, specenum_type, path,...)
Definition registry_ini.h:266
entry_type
entry_type
Definition registry_ini.h:631
ENTRY_FILEREFERENCE
@ ENTRY_FILEREFERENCE
Definition registry_ini.h:636
ENTRY_LONG_COMMENT
@ ENTRY_LONG_COMMENT
Definition registry_ini.h:637
ENTRY_INT
@ ENTRY_INT
Definition registry_ini.h:633
ENTRY_FLOAT
@ ENTRY_FLOAT
Definition registry_ini.h:634
ENTRY_STR
@ ENTRY_STR
Definition registry_ini.h:635
ENTRY_ILLEGAL
@ ENTRY_ILLEGAL
Definition registry_ini.h:638
ENTRY_BOOL
@ ENTRY_BOOL
Definition registry_ini.h:632
secfile_insert_str_vec
#define secfile_insert_str_vec(secfile, strings, dim, path,...)
Definition registry_ini.h:201
secfile_replace_int
#define secfile_replace_int(secfile, value, path,...)
Definition registry_ini.h:122
entry_list_iterate_end
#define entry_list_iterate_end
Definition registry_ini.h:57
secfile_insert_str
#define secfile_insert_str(secfile, string, path,...)
Definition registry_ini.h:170
secfile_insert_bool
#define secfile_insert_bool(secfile, value, path,...)
Definition registry_ini.h:79
secfile_replace_str
#define secfile_replace_str(secfile, string, path,...)
Definition registry_ini.h:183
entry_list_iterate
#define entry_list_iterate(entlist, pentry)
Definition registry_ini.h:55
secfile_replace_bool
#define secfile_replace_bool(secfile, value, path,...)
Definition registry_ini.h:85
secfile_data_t
const void * secfile_data_t
Definition registry_ini.h:30
compat_post_load_030100
static void compat_post_load_030100(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:1820
resource_by_identifier
struct extra_type * resource_by_identifier(const char identifier)
Definition savecompat.c:323
current_compat_ver
int current_compat_ver(void)
Definition savecompat.c:222
compat_load_030000
static void compat_load_030000(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:1309
num_chars
static const char num_chars[]
Definition savecompat.c:262
sg_success
bool sg_success
Definition savecompat.c:34
killcitizen_enum_str
static const char * killcitizen_enum_str(secfile_data_t data, int bit)
Definition savecompat.c:560
barb_type_convert
enum barbarian_type barb_type_convert(int old_type)
Definition savecompat.c:3197
special_names
static char * special_names[]
Definition savecompat.c:36
compat
static struct compatibility compat[]
Definition savecompat.c:110
compat_load_020400
static void compat_load_020400(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:341
upgrade_unit_order_targets
static void upgrade_unit_order_targets(struct unit *act_unit)
Definition savecompat.c:1725
bin2ascii_hex
char bin2ascii_hex(int value, int halfbyte_wanted)
Definition savecompat.c:232
compat_num
static const int compat_num
Definition savecompat.c:133
compat_load_020600
static void compat_load_020600(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:703
dir_opposite
static enum direction8 dir_opposite(enum direction8 dir)
Definition savecompat.c:1698
load_version_func_t
void(* load_version_func_t)(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:90
char2num
int char2num(char ch)
Definition savecompat.c:268
upgrade_server_side_agent
static void upgrade_server_side_agent(struct loaddata *loading)
Definition savecompat.c:1806
sg_load_compat
void sg_load_compat(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:143
unit_order_activity_to_action
static void unit_order_activity_to_action(struct unit *act_unit)
Definition savecompat.c:1646
revolentype_str
static char * revolentype_str(enum revolen_type type)
Definition savecompat.c:684
increase_secfile_turn_int
static int increase_secfile_turn_int(struct loaddata *loading, const char *key, int old_def, bool keep_default)
Definition savecompat.c:1288
ai_level_convert
enum ai_level ai_level_convert(int old_level)
Definition savecompat.c:3168
ascii_hex2bin
int ascii_hex2bin(char ch, int halfbyte)
Definition savecompat.c:244
special_extra_get
struct extra_type * special_extra_get(int spe)
Definition savecompat.c:309
compat_load_020500
static void compat_load_020500(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:577
compat_load_030200
static void compat_load_030200(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:1911
special_by_rule_name
enum tile_special_type special_by_rule_name(const char *name)
Definition savecompat.c:283
sg_load_post_load_compat
void sg_load_post_load_compat(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:194
special_rule_name
const char * special_rule_name(enum tile_special_type type)
Definition savecompat.c:299
compat_load_030100
static void compat_load_030100(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:1515
insert_server_side_agent
static void insert_server_side_agent(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:1424
compat_current
#define compat_current
Definition savecompat.c:134
savecompat.h
sg_check_ret
#define sg_check_ret(...)
Definition savecompat.h:150
sg_warn
#define sg_warn(condition, message,...)
Definition savecompat.h:160
tile_special_type
tile_special_type
Definition savecompat.h:29
S_LAST
@ S_LAST
Definition savecompat.h:38
hex_chars
#define hex_chars
Definition savecompat.h:205
sg_failure_ret_val
#define sg_failure_ret_val(condition, _val, message,...)
Definition savecompat.h:184
sg_failure_ret
#define sg_failure_ret(condition, message,...)
Definition savecompat.h:177
MAX_TRADE_ROUTES_OLD
#define MAX_TRADE_ROUTES_OLD
Definition savecompat.h:222
sgf_version
sgf_version
Definition savecompat.h:27
SAVEGAME_2
@ SAVEGAME_2
Definition savecompat.h:27
SAVEGAME_3
@ SAVEGAME_3
Definition savecompat.h:27
log_sg
#define log_sg
Definition savecompat.h:146
setcompat_S3_2_name_from_S3_1
const char * setcompat_S3_2_name_from_S3_1(const char *old_name)
Definition setcompat.c:62
setcompat.h
setting_by_name
struct setting * setting_by_name(const char *name)
Definition settings.c:3299
setting_value_name
const char * setting_value_name(const struct setting *pset, bool pretty, char *buf, size_t buf_len)
Definition settings.c:4257
setting_bitwise_set
bool setting_bitwise_set(struct setting *pset, const char *val, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:4213
level
struct setting_list * level[OLEVELS_NUM]
Definition settings.c:190
setting_bitwise_secfile_str
const char * setting_bitwise_secfile_str(secfile_data_t data, int bit)
Definition settings.c:4055
settings.h
ARRAY_SIZE
#define ARRAY_SIZE(x)
Definition shared.h:85
MAX
#define MAX(x, y)
Definition shared.h:54
specialist_by_number
struct specialist * specialist_by_number(const Specialist_type_id id)
Definition specialist.c:100
specialist_rule_name
const char * specialist_rule_name(const struct specialist *sp)
Definition specialist.c:146
specialist_count
Specialist_type_id specialist_count(void)
Definition specialist.c:71
specialist.h
specialist_type_iterate_end
#define specialist_type_iterate_end
Definition specialist.h:79
specialist_type_iterate
#define specialist_type_iterate(sp)
Definition specialist.h:73
size
size_t size
Definition specvec.h:72
y
struct sprite int int y
Definition sprite_g.h:31
x
struct sprite int x
Definition sprite_g.h:31
action
Definition actions.h:360
civ_map::north_latitude
int north_latitude
Definition map_types.h:79
civ_map::south_latitude
int south_latitude
Definition map_types.h:80
civ_map::server
struct civ_map::@42::@44 server
civ_map::huts_absolute
int huts_absolute
Definition map_types.h:95
compatibility
Definition savecompat.c:92
compatibility::post_load
const load_version_func_t post_load
Definition savecompat.c:95
compatibility::version
int version
Definition savecompat.c:93
compatibility::load
const load_version_func_t load
Definition savecompat.c:94
extra_type
Definition extras.h:88
loaddata
Definition savecompat.h:47
section
Definition section_file.h:28
setting
Definition settings.c:92
sf_cb_data
Definition settings.h:81
specialist
Definition specialist.h:29
specialist::name
struct name_translation name
Definition specialist.h:31
tile
Definition tile.h:50
unit_order
Definition unit.h:92
unit_order::activity
enum unit_activity activity
Definition unit.h:94
unit_order::order
enum unit_orders order
Definition unit.h:93
unit_order::action
int action
Definition unit.h:100
unit_order::dir
enum direction8 dir
Definition unit.h:102
unit_order::target
int target
Definition unit.h:97
unit_order::sub_target
int sub_target
Definition unit.h:98
unit
Definition unit.h:138
unit::length
int length
Definition unit.h:195
unit::has_orders
bool has_orders
Definition unit.h:193
unit::orders
struct unit::@80 orders
unit::activity
enum unit_activity activity
Definition unit.h:157
unit::activity_target
struct extra_type * activity_target
Definition unit.h:164
unit::list
struct unit_order * list
Definition unit.h:198
unit::ssa_controller
enum server_side_agent ssa_controller
Definition unit.h:172
world::map
struct civ_map map
Definition world_object.h:38
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:974
fc_strlcpy
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:791
fc_strcasecmp
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:189
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:189
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
sz_strlcat
#define sz_strlcat(dest, src)
Definition support.h:190
fc_strncmp
#define fc_strncmp(_s1_, _s2_, _len_)
Definition support.h:154
team_slot_count
int team_slot_count(void)
Definition team.c:112
terrain_identifier
char terrain_identifier(const struct terrain *pterrain)
Definition terrain.c:126
terrain_rule_name
const char * terrain_rule_name(const struct terrain *pterrain)
Definition terrain.c:247
terrain_type_iterate
#define terrain_type_iterate(_p)
Definition terrain.h:373
terrain_type_iterate_end
#define terrain_type_iterate_end
Definition terrain.h:379
free_unit_orders
void free_unit_orders(struct unit *punit)
Definition unit.c:1765
unit_can_do_action
bool unit_can_do_action(const struct unit *punit, const action_id act_id)
Definition unit.c:361
unit_has_orders
bool unit_has_orders(const struct unit *punit)
Definition unit.c:205
unit_tile
#define unit_tile(_pu)
Definition unit.h:390
ORDER_ACTIVITY
@ ORDER_ACTIVITY
Definition unit.h:41
ORDER_PERFORM_ACTION
@ ORDER_PERFORM_ACTION
Definition unit.h:47
unit_list_iterate
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
unit_list_iterate_end
#define unit_list_iterate_end
Definition unitlist.h:33
unit_assign_specific_activity_target
void unit_assign_specific_activity_target(struct unit *punit, enum unit_activity *activity, struct extra_type **target)
Definition unittools.c:1082
unittools.h
unit_type_get
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:123
utype_is_moved_to_tgt_by_action
bool utype_is_moved_to_tgt_by_action(const struct action *paction, const struct unit_type *utype)
Definition unittype.c:1249
unit_rule_name
const char * unit_rule_name(const struct unit *punit)
Definition unittype.c:1587
utype_is_unmoved_by_action
bool utype_is_unmoved_by_action(const struct action *paction, const struct unit_type *utype)
Definition unittype.c:1288