Freeciv-3.3: /fast/freeciv/nightly/main/server/savegame/savecompat.c Source File

Freeciv-3.3

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