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
35
36static 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
84static void compat_post_load_030100(struct loaddata *loading,
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
93
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. */
112static 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 */
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
137static const int compat_num = ARRAY_SIZE(compat);
138#define compat_current (compat_num - 1)
139
140/************************************************************************/
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,
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,
178 }
179 }
180
181#ifdef FREECIV_DEV_SAVE_COMPAT
182 if (loading->version == compat[compat_current].version) {
184 }
185#endif /* FREECIV_DEV_SAVE_COMPAT */
186}
187
188/************************************************************************/
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,
213 }
214 }
215
216#ifdef FREECIV_DEV_SAVE_COMPAT
217 if (loading->version == compat[compat_current].version) {
219 }
220#endif /* FREECIV_DEV_SAVE_COMPAT */
221}
222
223/************************************************************************/
227{
229}
230
231/************************************************************************/
236char bin2ascii_hex(int value, int halfbyte_wanted)
237{
238 return hex_chars[((value) >> ((halfbyte_wanted) * 4)) & 0xf];
239}
240
241/************************************************************************/
249{
250 const char *pch;
251
252 if (ch == ' ') {
253 /* Sane value. It is unknown 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
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
266static const char num_chars[] =
267 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-+";
268
269/************************************************************************/
272int char2num(char ch)
273{
274 const char *pch;
275
277
279 "Unknown ascii value for num: '%c' %d", ch, ch);
280
281 return pch - num_chars;
282}
283
284/************************************************************************/
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/************************************************************************/
304{
305 fc_assert(type >= 0 && type < S_LAST);
306
307 return special_names[type];
308}
309
310/************************************************************************/
314{
316
319 }
320
321 return NULL;
322}
323
324/************************************************************************/
327struct extra_type *resource_by_identifier(const char identifier)
328{
330 if (presource->data.resource->id_old_save == identifier) {
331 return presource;
332 }
334
335 return NULL;
336}
337
338/* =======================================================================
339 * Compatibility functions for loading a game.
340 * ======================================================================= */
341
342/************************************************************************/
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
362 "player%d.ai_type", player_slot_index(pslot));
363
364 /* Create dummy citizens information. 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. */
369 "player%d.ncities", plrno);
370 if (ncities > 0) {
371 for (i = 0; i < ncities; i++) {
373 "player%d.c%d.size", plrno, i);
374 if (size > 0) {
376 "player%d.c%d.citizen%d", plrno, i, plrno);
377 }
378 }
379 }
380
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) {
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);
410 FC_FREE(name2);
411 }
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],
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;
431 for (l = 0; l < lines; l++) {
432 for (j = 0; j < 8; j++) {
433 const char *s =
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';
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
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
517 "settings.set%d.value", i)) {
518 if (nturns == 0) {
519 /* Invent a new "autosaves" setting */
521 "settings.set%d.value", new_opt);
522 /* Pick something valid for saveturns */
524 "settings.set%d.value", i);
525 } else {
527 "settings.set%d.value", new_opt);
528 }
529 } else {
530 log_sg("Setting '%s': %s", name, secfile_error());
531 }
532 if (gamestart_valid) {
534 "settings.set%d.gamestart", i)) {
535 if (nturns == 0) {
536 /* Invent a new "autosaves" setting */
538 "settings.set%d.gamestart", new_opt);
539 /* Pick something valid for saveturns */
541 "settings.set%d.gamestart", i);
542 } else {
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/************************************************************************/
564static 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/************************************************************************/
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
618 "savefile.roads_vector");
619
620 secfile_insert_int(loading->file, 19, "savefile.activities_size");
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
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,
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) {
653 "settings.set%d.value", i);
654 } else {
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,
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) {
670 "settings.set%d.gamestart", i);
671 } else {
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/************************************************************************/
689{
690 switch (type) {
691 case REVOLEN_FIXED:
692 return "FIXED";
693 case REVOLEN_RANDOM:
694 return "RANDOM";
696 return "QUICKENING";
698 return "RANDQUICK";
699 }
700
701 return "";
702}
703
704/************************************************************************/
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;
724 char buf[2];
725
726 secfile_insert_str(loading->file, terrain_rule_name(pterr), "savefile.terrident%d.name", ti);
728 buf[1] = '\0';
729 secfile_insert_str(loading->file, buf, "savefile.terrident%d.identifier", ti++);
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;
744 bool gamestart_valid
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') {
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') {
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') {
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') {
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) {
822 "settings.set%d.value", i);
823 } else {
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) {
835 "settings.set%d.gamestart", i);
836 } else {
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)) {
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
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
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. */
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'. */
963 "player%d.capital", plrno)) {
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);
971 "player%d.unassigned_user", plrno);
972
973 name = secfile_lookup_str_default(loading->file, "", "player%d.ranked_username", plrno);
975 "player%d.unassigned_ranked", plrno);
976
977 /* Convert numeric barbarian type to textual */
979 "player%d.ai.is_barbarian", plrno);
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
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. */
1029 "player%d.nunits",
1030 plrno);
1031
1032 for (i = 0; i < units_num; i++) {
1033 int len;
1034
1036 "player%d.u%d.orders_last_move_safe",
1037 plrno, i)) {
1038 continue;
1039 }
1040
1042 "player%d.u%d.orders_length",
1043 plrno, i);
1044 if (len > 0) {
1045 char orders_str[len + 1];
1046 char *p;
1047
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 */
1056 "player%d.u%d.orders_list", plrno, i);
1057 }
1058 }
1059 }
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 */
1066 "savefile.specialists_size");
1067 {
1068 const char **modname;
1069 int i = 0;
1070
1072
1076
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
1099 struct specialist *psp = specialist_by_number(sp);
1100 int count;
1101
1103 "player%d.c%d.n%s",
1105 "specialist error: %s", secfile_error());
1106 secfile_entry_delete(loading->file, "player%d.c%d.n%s",
1108 secfile_insert_int(loading->file, count, "player%d.c%d.nspe%d",
1109 plrno, i, k++);
1111 }
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
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) {
1153 "player%d.team_no", plrno);
1154 } else {
1155 i = plrno;
1156 }
1157
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:
1199 "Research related entry marked as float.");
1200 break;
1203 break;
1204 case ENTRY_LONG_COMMENT:
1206 break;
1207 case ENTRY_ILLEGAL:
1209 break;
1210 }
1211 }
1213 secfile_insert_int(loading->file, count, "research.count");
1214 }
1215
1216 /* Add diplstate type order. */
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++) {
1229 }
1230
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
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. */
1260 "%s.type",
1261 buf);
1262
1263 /* Read the closest diplomatic state. */
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 }
1287}
1288
1289/************************************************************************/
1292static 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/************************************************************************/
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;
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)) {
1356
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
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
1383 }
1384 }
1386
1387 /* Settings */
1389 "settings.set_count");
1390
1391 /* User meta server message is now a setting. */
1393 "game.meta_usermessage")) {
1394 const char *metamessage;
1395
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);
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/************************************************************************/
1430{
1431 int ssa_size;
1432
1433 if (format_class == SAVEGAME_2) {
1434 /* Handled in savegame2 */
1435 return;
1436 }
1437
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. */
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++) {
1459 }
1460
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. */
1480 "player%d.nunits",
1481 plrno);
1482
1483 for (unit = 0; unit < units_num; unit++) {
1484 bool ai;
1485
1487 "player%d.u%d.server_side_agent",
1488 plrno, unit)
1489 != NULL) {
1490 /* Already updated? */
1491 continue;
1492 }
1493
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 */
1502 "player%d.u%d.server_side_agent",
1503 plrno, unit);
1504 } else {
1506 "player%d.u%d.server_side_agent",
1507 plrno, unit);
1508 }
1509 }
1511}
1512
1513/************************************************************************/
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. */
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
1548 "player%d.u%d.orders_length",
1549 plrno, unit);
1550
1552 "player%d.u%d.action_list",
1553 plrno, unit))) {
1554 int order_num;
1555
1558 }
1559
1560 for (order_num = 0; order_num < order_len; order_num++) {
1562
1563 if (action_unitstr[order_num] == '?') {
1565 } else {
1567 }
1568
1569 if (order_num == 0) {
1570 /* The start of a vector has no number. */
1572 "player%d.u%d.action_vec",
1573 plrno, unit);
1574 } else {
1576 "player%d.u%d.action_vec,%d",
1577 plrno, unit, order_num);
1578 }
1579 }
1580 }
1581 }
1583
1584 {
1585 int action_count;
1586
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
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
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
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
1637 "settings.set%d.gamesetdef", i);
1638 }
1639 }
1640 }
1641 }
1642
1643 /* Explicit server side agent was new in 3.1 */
1645}
1646
1647/************************************************************************/
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:
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 }
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/************************************************************************/
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/************************************************************************/
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
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
1786 /* The action moves the unit to the target tile (unless this is the
1787 * final order) */
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));
1804 }
1805}
1806
1807/************************************************************************/
1811{
1812 players_iterate_alive(pplayer) {
1813 unit_list_iterate(pplayer->units, punit) {
1816 }
1819}
1820
1821/************************************************************************/
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
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. */
1851 }
1852
1853 /* Production targeted actions were split from building targeted
1854 * actions in 3.1. The building sub target encoding changed. */
1856 && ((punit->orders.list[i].action
1858 || (punit->orders.list[i].action
1860 punit->orders.list[i].sub_target -= 1;
1861 }
1863 && (punit->orders.list[i].action
1865 && punit->orders.list[i].sub_target == -1) {
1868 }
1870 && (punit->orders.list[i].action
1872 && punit->orders.list[i].sub_target == -1) {
1875 }
1876 }
1879 }
1880
1881 /* Explicit server side agent was new in 3.1 */
1883
1884 /* Some activities should only be ordered in action orders. */
1885 players_iterate_alive(pplayer) {
1886 unit_list_iterate(pplayer->units, punit) {
1890
1891 /* Unit order action target isn't dir anymore */
1892 players_iterate_alive(pplayer) {
1893 unit_list_iterate(pplayer->units, punit) {
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) {
1903 &punit->activity,
1907}
1908
1909/************************************************************************/
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 {
1940
1941 secfile_insert_str(loading->file, "savegame2, or older",
1942 "savefile.orig_version");
1943 }
1944 }
1945 }
1946
1947 {
1948 int action_count;
1949
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
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
1977 "savefile.action_vector");
1978
1979 free(savemod);
1980 }
1981 }
1982
1983 {
1984 int activities_count;
1985
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
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
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
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
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,
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 {
2120 }
2121
2122 setting_value_name(pset, FALSE, buf, sizeof(buf));
2124 "settings.set%d.value", i);
2125
2127 "wrap", "settings.set%d.name", set_count);
2129 wrap, "settings.set%d.value", set_count);
2130
2131 if (gamestart_valid) {
2132 if (secfile_lookup_enum_data(loading->file, &val, TRUE,
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 {
2157 }
2158
2159 setting_value_name(pset, FALSE, buf, sizeof(buf));
2161 "settings.set%d.gamestart", i);
2162
2164 wrap, "settings.set%d.gamestart", set_count);
2165 }
2166 }
2167
2168 set_count++;
2170 }
2171 } else if (!fc_strcasecmp("alltemperate", name)) {
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;
2182
2183 if (alltemperate_idx < 0
2185 "settings.set%d.value",
2187 /* Infer what would've been the ruleset default */
2189 }
2190
2191 if (singlepole_idx < 0
2193 "settings.set%d.value",
2194 singlepole_idx)) {
2195 /* Infer what would've been the ruleset default */
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. */
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
2223 "settings.set%d.gamestart",
2225 alltemperate =
2227 }
2228
2229 if (singlepole_idx < 0
2231 "settings.set%d.gamestart",
2232 singlepole_idx)) {
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++;
2249 }
2250 }
2251
2252 if (count_changed) {
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 */
2268 } else {
2270 }
2271
2272 if (!ai_level_is_valid(lvl)) {
2273 log_sg("Invalid AI level \"%s\". "
2274 "Changed to \"%s\".", 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
2300 "research.r%d.got_tech_multi", i);
2301
2303 "research.r%d.got_tech", i)
2304 && secfile_lookup_int(loading->file, &bulbs,
2305 "research.r%d.bulbs", i)) {
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 {
2317 "savefile.diplstate_type_size");
2318
2319 for (i = 0; i < dscount; i++) {
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
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
2348
2350 "player%d.flags", plrno);
2351
2352 for (i = 0; i < nval; i++) {
2355
2357 }
2358
2360 "player%d.flags", plrno);
2361
2363 }
2364
2366 "player%d.ncities", plrno);
2367
2368 for (cnro = 0; cnro < ncities; cnro++) {
2370 "player%d.c%d.wl_length",
2371 plrno, cnro);
2372
2374
2375 if (format_class == SAVEGAME_3) {
2377 "player%d.c%d.original",
2378 plrno, cnro) != plrno) {
2380 "player%d.c%d.acquire_t",
2381 plrno, cnro);
2382 } else {
2384 "player%d.c%d.acquire_t",
2385 plrno, cnro);
2386 }
2387
2389 "player%d.c%d.wlcb",
2390 plrno, cnro);
2391 }
2392 }
2393
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
2403 "player%d.nunits", plrno);
2404
2405 for (unro = 0; unro < nunits; unro++) {
2407 "player%d.u%d.orders_length",
2408 plrno, unro);
2409
2411 }
2412
2414 "player%d.orders_max_length", plrno);
2415
2417 "player%d.routes_max_length", plrno);
2418 }
2419
2421 }
2422}
2423
2424/************************************************************************/
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 /* World Peace has never started in the old savegame. */
2439 game.info.turn = secfile_lookup_int_default(loading->file, 0, "game.turn");
2440
2441 if (format_class != SAVEGAME_2) {
2442 secfile_insert_int(loading->file, game.info.turn, "game.world_peace_start");
2443
2444 secfile_insert_bool(loading->file, FALSE, "map.altitude");
2445 }
2446
2447 /* Last turn change time as a float, not integer multiplied by 100 */
2448 {
2449 float tct = secfile_lookup_int_default(loading->file, 0,
2450 "game.last_turn_change_time") / 100.0;
2451
2452 secfile_replace_float(loading->file, tct, "game.last_turn_change_time");
2453 }
2454
2455 {
2456 int ssa_count;
2457
2459 "savefile.server_side_agent_size");
2460 if (ssa_count > 0) {
2461 const char **modname;
2462 const char **savemod;
2463 int j;
2464 const char *aw_name = "AutoWorker";
2465
2466 modname = secfile_lookup_str_vec(loading->file, &loading->ssa.size,
2467 "savefile.server_side_agent_list");
2468
2469 savemod = fc_calloc(ssa_count, sizeof(*savemod));
2470
2471 for (j = 0; j < ssa_count; j++) {
2472 if (!fc_strcasecmp("Autosettlers", modname[j])) {
2473 savemod[j] = aw_name;
2474 } else {
2475 savemod[j] = modname[j];
2476 }
2477 }
2478
2480 "savefile.server_side_agent_list");
2481
2482 free(savemod);
2483 }
2484 }
2485
2486 {
2487 int action_count;
2488
2490 "savefile.action_size");
2491
2492 if (action_count > 0) {
2493 const char **modname;
2494 const char **savemod;
2495 int j;
2496 const char *cc1_name = "Conquer City Shrink";
2497 const char *cc2_name = "Conquer City Shrink 2";
2498 const char *cc3_name = "Conquer City Shrink 3";
2499 const char *cc4_name = "Conquer City Shrink 4";
2500
2501 modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
2502 "savefile.action_vector");
2503
2505
2506 for (j = 0; j < action_count; j++) {
2507 if (!fc_strcasecmp("Conquer City", modname[j])) {
2508 savemod[j] = cc1_name;
2509 } else if (!fc_strcasecmp("Conquer City 2", modname[j])) {
2510 savemod[j] = cc2_name;
2511 } else if (!fc_strcasecmp("Conquer City 3", modname[j])) {
2512 savemod[j] = cc3_name;
2513 } else if (!fc_strcasecmp("Conquer City 4", modname[j])) {
2514 savemod[j] = cc4_name;
2515 } else {
2516 savemod[j] = modname[j];
2517 }
2518 }
2519
2521 "savefile.action_vector");
2522
2523 free(savemod);
2524 }
2525 }
2526
2527 /* Add actions for unit activities */
2528 if (format_class == SAVEGAME_3) {
2529 loading->activities.size
2531 "savefile.activities_size");
2532 if (loading->activities.size) {
2533 loading->activities.order
2534 = secfile_lookup_str_vec(loading->file, &loading->activities.size,
2535 "savefile.activities_vector");
2536 sg_failure_ret(loading->activities.size != 0,
2537 "Failed to load activity order: %s",
2538 secfile_error());
2539 }
2540
2541 loading->action.size = secfile_lookup_int_default(loading->file, 0,
2542 "savefile.action_size");
2543
2544 sg_failure_ret(loading->action.size > 0,
2545 "Failed to load action order: %s",
2546 secfile_error());
2547
2548 if (loading->action.size) {
2549 const char **modname;
2550 int j;
2551
2552 modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
2553 "savefile.action_vector");
2554
2555 loading->action.order = fc_calloc(loading->action.size,
2556 sizeof(*loading->action.order));
2557
2558 for (j = 0; j < loading->action.size; j++) {
2560
2561 if (real_action != nullptr) {
2562 loading->action.order[j] = real_action->id;
2563 } else {
2564 log_sg("Unknown action \'%s\'", modname[j]);
2565 loading->action.order[j] = ACTION_NONE;
2566 }
2567 }
2568
2569 free(modname);
2570 }
2571
2572 player_slots_iterate(pslot) {
2573 int plrno = player_slot_index(pslot);
2574 int nunits;
2575 int unro;
2576
2577 if (secfile_section_lookup(loading->file, "player%d", plrno) == nullptr) {
2578 continue;
2579 }
2580
2582 "player%d.nunits", plrno);
2583
2584 for (unro = 0; unro < nunits; unro++) {
2585 int ei;
2586 int i;
2587 enum unit_activity activity;
2588 enum gen_action act;
2589
2591 "player%d.u%d.activity", plrno, unro);
2592
2593 if (ei >= 0 && ei < loading->activities.size) {
2594 bool found = FALSE;
2595
2596 activity = unit_activity_by_name(loading->activities.order[ei],
2598
2599 act = activity_default_action(activity);
2600
2601 for (i = 0; i < loading->action.size; i++) {
2602 if (act == loading->action.order[i]) {
2603 secfile_insert_int(loading->file, i, "player%d.u%d.action",
2604 plrno, unro);
2605 found = TRUE;
2606 break;
2607 }
2608 }
2609
2610 if (!found) {
2611 secfile_insert_int(loading->file, -1, "player%d.u%d.action",
2612 plrno, unro);
2613 }
2614 }
2615 }
2617 }
2618
2619 /* Researches */
2620 {
2621 int count = secfile_lookup_int_default(loading->file, 0, "research.count");
2622 int i;
2623
2624 for (i = 0; i < count; i++) {
2625 /* It's ok for old savegames to have these entries. */
2626 secfile_entry_ignore(loading->file, "research.r%d.techs", i);
2627 }
2628 }
2629
2630 player_slots_iterate(pslot) {
2631 int plrno = player_slot_index(pslot);
2632 int ncities;
2633 int cnro;
2634
2635 if (secfile_section_lookup(loading->file, "player%d", plrno) == nullptr) {
2636 continue;
2637 }
2638
2640 "player%d.dc_total", plrno);
2641
2642 for (cnro = 0; cnro < ncities; cnro++) {
2643 secfile_insert_int(loading->file, -1, "player%d.dc%d.original",
2644 plrno, cnro);
2645 }
2647}
2648
2649/************************************************************************/
2653#ifdef FREECIV_DEV_SAVE_COMPAT
2654static void compat_load_dev(struct loaddata *loading)
2655{
2656 int game_version;
2657
2658 /* Check status and return if not OK (sg_success FALSE). */
2659 sg_check_ret();
2660
2661 log_verbose("Upgrading data between development revisions");
2662
2663 sg_failure_ret(secfile_lookup_int(loading->file, &game_version, "scenario.game_version"),
2664 "No save version found");
2665
2666#ifdef FREECIV_DEV_SAVE_COMPAT_3_3
2667
2668 if (game_version < 3029100) {
2669 /* Before version number bump to 3.2.91, September 2023 */
2670
2671 {
2672 const char *str = secfile_lookup_str_default(loading->file, NULL,
2673 "savefile.orig_version");
2674
2675 if (str == NULL) {
2676 /* Make sure CURRENTLY running version does not
2677 * end as orig_version when we resave. */
2678 secfile_insert_str(loading->file, "old savegame3, or older",
2679 "savefile.orig_version");
2680 }
2681 }
2682
2683 /* Add acquire_t entries for cities */
2684 {
2685 player_slots_iterate(pslot) {
2686 int plrno = player_slot_index(pslot);
2687 int ncities;
2688 int cnro;
2689 bool first_city;
2690
2691 if (secfile_section_lookup(loading->file, "player%d", plrno) == NULL) {
2692 continue;
2693 }
2694
2696 "player%d.got_first_city",
2697 plrno);
2698 if (first_city) {
2699 const char **flag_names = fc_calloc(PLRF_COUNT, sizeof(char *));
2700 int flagcount = 0;
2701 const char **flags_sg;
2702 size_t nval;
2703 int i;
2704
2706
2708 "player%d.flags", plrno);
2709
2710 for (i = 0; i < nval; i++) {
2713
2715 }
2716
2718 "player%d.flags", plrno);
2719
2721 }
2722
2724 "player%d.ncities", plrno);
2725
2726 for (cnro = 0; cnro < ncities; cnro++) {
2727 if (secfile_entry_lookup(loading->file,
2728 "player%d.c%d.acquire_t",
2729 plrno, cnro) == NULL) {
2731 "player%d.c%d.original",
2732 plrno, cnro) != plrno) {
2734 "player%d.c%d.acquire_t",
2735 plrno, cnro);
2736 } else {
2738 "player%d.c%d.acquire_t",
2739 plrno, cnro);
2740 }
2741 }
2742 if (secfile_entry_lookup(loading->file,
2743 "player%d.c%d.wlcb",
2744 plrno, cnro) == NULL) {
2746 "player%d.c%d.wlcb",
2747 plrno, cnro);
2748 }
2749 }
2751 }
2752
2753 /* Add orders_max_length entries for players */
2754 {
2755 player_slots_iterate(pslot) {
2756 int plrno = player_slot_index(pslot);
2757
2758 if (secfile_section_lookup(loading->file, "player%d", plrno) != NULL
2760 "player%d.orders_max_length", plrno)
2761 == NULL) {
2762 size_t nunits;
2763 int unro;
2764 size_t olist_max_length = 0;
2765
2767 "player%d.nunits", plrno);
2768
2769 for (unro = 0; unro < nunits; unro++) {
2770 int ol_length
2772 "player%d.u%d.orders_length",
2773 plrno, unro);
2774
2776 }
2777
2779 "player%d.orders_max_length", plrno);
2780 }
2782 }
2783
2784 {
2785 int action_count;
2786
2788 "savefile.action_size");
2789
2790 if (action_count > 0) {
2791 const char **modname;
2792 const char **savemod;
2793 int j;
2794 const char *clean_name = "Clean";
2795
2796 modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
2797 "savefile.action_vector");
2798
2800
2801 for (j = 0; j < action_count; j++) {
2802 if (!fc_strcasecmp("Clean Pollution", modname[j])
2803 || !fc_strcasecmp("Clean Fallout", modname[j])) {
2804 savemod[j] = clean_name;
2805 } else {
2806 savemod[j] = modname[j];
2807 }
2808 }
2809
2811 "savefile.action_vector");
2812
2813 free(savemod);
2814 }
2815 }
2816
2817 {
2818 int activities_count;
2819
2821 "savefile.activities_size");
2822
2823 if (activities_count > 0) {
2824 const char **modname;
2825 const char **savemod;
2826 int j;
2827 const char *clean_name = "Clean";
2828
2829 modname = secfile_lookup_str_vec(loading->file, &loading->activities.size,
2830 "savefile.activities_vector");
2831
2833
2834 for (j = 0; j < activities_count; j++) {
2835 if (!fc_strcasecmp("Pollution", modname[j])
2836 || !fc_strcasecmp("Fallout", modname[j])) {
2837 savemod[j] = clean_name;
2838 } else {
2839 savemod[j] = modname[j];
2840 }
2841 }
2842
2844 "savefile.activities_vector");
2845
2846 free(savemod);
2847 }
2848 }
2849
2850 /* Server setting migration. */
2851 {
2852 int set_count;
2853
2854 if (secfile_lookup_int(loading->file, &set_count, "settings.set_count")) {
2855 bool gamestart_valid = FALSE;
2856
2859 "settings.gamestart_valid");
2860
2861 if (!gamestart_valid) {
2862 int i;
2863
2864 /* Older savegames saved gamestart values even when they were not valid.
2865 * Silence warnings caused by them. */
2866 for (i = 0; i < set_count; i++) {
2867 (void) secfile_entry_lookup(loading->file, "settings.set%d.gamestart", i);
2868 (void) secfile_entry_lookup(loading->file, "settings.set%d.gamesetdef", i);
2869 }
2870 }
2871 }
2872 }
2873
2874 {
2875 int ssa_count;
2876
2878 "savefile.server_side_agent_size");
2879 if (ssa_count > 0) {
2880 const char **modname;
2881 const char **savemod;
2882 int j;
2883 const char *aw_name = "AutoWorker";
2884
2885 modname = secfile_lookup_str_vec(loading->file, &loading->ssa.size,
2886 "savefile.server_side_agent_list");
2887
2888 savemod = fc_calloc(ssa_count, sizeof(*savemod));
2889
2890 for (j = 0; j < ssa_count; j++) {
2891 if (!fc_strcasecmp("Autosettlers", modname[j])) {
2892 savemod[j] = aw_name;
2893 } else {
2894 savemod[j] = modname[j];
2895 }
2896 }
2897
2899 "savefile.server_side_agent_list");
2900
2901 free(savemod);
2902 }
2903 }
2904
2905 } /* Version < 3.2.91 */
2906
2907 if (game_version < 3029200) {
2908 /* Before version number bump to 3.2.92, June 2024 */
2909
2910 secfile_insert_bool(loading->file, FALSE, "map.altitude");
2911
2912 /* World Peace has never started in the old savegame. */
2913 game.info.turn
2914 = secfile_lookup_int_default(loading->file, 0, "game.turn");
2917 "game.world_peace_start");
2919 "game.world_peace_start");
2920
2921 /* Last turn change time as a float, not integer multiplied by 100 */
2922 {
2923 float tct = secfile_lookup_int_default(loading->file, 0,
2924 "game.last_turn_change_time") / 100.0;
2925
2926 secfile_replace_float(loading->file, tct, "game.last_turn_change_time");
2927 }
2928
2929 /* Add actions for unit activities */
2930 loading->activities.size
2932 "savefile.activities_size");
2933 if (loading->activities.size) {
2934 loading->activities.order
2935 = secfile_lookup_str_vec(loading->file, &loading->activities.size,
2936 "savefile.activities_vector");
2937 sg_failure_ret(loading->activities.size != 0,
2938 "Failed to load activity order: %s",
2939 secfile_error());
2940 }
2941
2942 loading->action.size = secfile_lookup_int_default(loading->file, 0,
2943 "savefile.action_size");
2944
2945 sg_failure_ret(loading->action.size > 0,
2946 "Failed to load action order: %s",
2947 secfile_error());
2948
2949 if (loading->action.size) {
2950 const char **modname;
2951 int j;
2952
2953 modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
2954 "savefile.action_vector");
2955
2956 loading->action.order = fc_calloc(loading->action.size,
2957 sizeof(*loading->action.order));
2958
2959 for (j = 0; j < loading->action.size; j++) {
2961
2962 if (real_action) {
2963 loading->action.order[j] = real_action->id;
2964 } else {
2965 log_sg("Unknown action \'%s\'", modname[j]);
2966 loading->action.order[j] = ACTION_NONE;
2967 }
2968 }
2969
2970 free(modname);
2971 }
2972
2973 player_slots_iterate(pslot) {
2974 int plrno = player_slot_index(pslot);
2975 int nunits;
2976 int unro;
2977
2978 if (secfile_section_lookup(loading->file, "player%d", plrno) == nullptr) {
2979 continue;
2980 }
2981
2983 "player%d.nunits", plrno);
2984
2985 for (unro = 0; unro < nunits; unro++) {
2986 int ei;
2987 int i;
2988 enum unit_activity activity;
2989 enum gen_action act;
2990
2992 "player%d.u%d.activity", plrno, unro);
2993
2994 if (ei >= 0 && ei < loading->activities.size) {
2995 bool found = FALSE;
2996
2997 activity = unit_activity_by_name(loading->activities.order[ei],
2999 act = activity_default_action(activity);
3000
3001 for (i = 0; i < loading->action.size; i++) {
3002 if (act == loading->action.order[i]) {
3003 secfile_insert_int(loading->file, i, "player%d.u%d.action",
3004 plrno, unro);
3005 found = TRUE;
3006 break;
3007 }
3008 }
3009
3010 if (!found) {
3011 secfile_insert_int(loading->file, -1, "player%d.u%d.action",
3012 plrno, unro);
3013 }
3014 }
3015 }
3017
3018 /* Researches */
3019 {
3020 int count = secfile_lookup_int_default(loading->file, 0, "research.count");
3021 int i;
3022
3023 for (i = 0; i < count; i++) {
3024 /* It's ok for old savegames to have these entries. */
3025 secfile_entry_ignore(loading->file, "research.r%d.techs", i);
3026 }
3027 }
3028
3029 } /* Version < 3.2.92 */
3030
3031 if (game_version < 3029300) {
3032 /* Before version number bump to 3.2.93 */
3033
3034 {
3035 int action_count;
3036
3038 "savefile.action_size");
3039
3040 if (action_count > 0) {
3041 const char **modname;
3042 const char **savemod;
3043 int j;
3044 const char *cc1_name = "Conquer City Shrink";
3045 const char *cc2_name = "Conquer City Shrink 2";
3046 const char *cc3_name = "Conquer City Shrink 3";
3047 const char *cc4_name = "Conquer City Shrink 4";
3048
3049 modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
3050 "savefile.action_vector");
3051
3053
3054 for (j = 0; j < action_count; j++) {
3055 if (!fc_strcasecmp("Conquer City", modname[j])) {
3056 savemod[j] = cc1_name;
3057 } else if (!fc_strcasecmp("Conquer City 2", modname[j])) {
3058 savemod[j] = cc2_name;
3059 } else if (!fc_strcasecmp("Conquer City 3", modname[j])) {
3060 savemod[j] = cc3_name;
3061 } else if (!fc_strcasecmp("Conquer City 4", modname[j])) {
3062 savemod[j] = cc4_name;
3063 } else {
3064 savemod[j] = modname[j];
3065 }
3066 }
3067
3069 "savefile.action_vector");
3070
3071 free(savemod);
3072 }
3073 }
3074
3075 player_slots_iterate(pslot) {
3076 int plrno = player_slot_index(pslot);
3077 int ncities;
3078 int cnro;
3079
3080 if (secfile_section_lookup(loading->file, "player%d", plrno) == nullptr) {
3081 continue;
3082 }
3083
3085 "player%d.dc_total", plrno);
3086
3087 for (cnro = 0; cnro < ncities; cnro++) {
3088 if (!secfile_entry_lookup(loading->file, "player%d.dc%d.original",
3089 plrno, cnro)) {
3090 secfile_insert_int(loading->file, -1, "player%d.dc%d.original",
3091 plrno, cnro);
3092 }
3093 }
3095 } /* Version < 3.2.93 */
3096
3097#endif /* FREECIV_DEV_SAVE_COMPAT_3_3 */
3098}
3099
3100/************************************************************************/
3104static void compat_post_load_dev(struct loaddata *loading)
3105{
3106 int game_version;
3107
3108 /* Check status and return if not OK (sg_success FALSE). */
3109 sg_check_ret();
3110
3111 if (!secfile_lookup_int(loading->file, &game_version, "scenario.game_version")) {
3112 game_version = 2060000;
3113 }
3114
3115#ifdef FREECIV_DEV_SAVE_COMPAT_3_3
3116
3117 if (game_version < 3029100) {
3118 /* Before version number bump to 3.2.91 */
3119
3120 } /* Version < 3.2.91 */
3121
3122#endif /* FREECIV_DEV_SAVE_COMPAT_3_3 */
3123}
3124#endif /* FREECIV_DEV_SAVE_COMPAT */
3125
3126/************************************************************************/
3129enum ai_level ai_level_convert(int old_level)
3130{
3131 switch (old_level) {
3132 case 1:
3133 return AI_LEVEL_AWAY;
3134 case 2:
3135 return AI_LEVEL_NOVICE;
3136 case 3:
3137 return AI_LEVEL_EASY;
3138 case 5:
3139 return AI_LEVEL_NORMAL;
3140 case 7:
3141 return AI_LEVEL_HARD;
3142 case 8:
3143 return AI_LEVEL_CHEATING;
3144 case 10:
3145#ifdef FREECIV_DEBUG
3146 return AI_LEVEL_EXPERIMENTAL;
3147#else /* FREECIV_DEBUG */
3148 return AI_LEVEL_HARD;
3149#endif /* FREECIV_DEBUG */
3150 }
3151
3152 return ai_level_invalid();
3153}
3154
3155/************************************************************************/
3158enum barbarian_type barb_type_convert(int old_type)
3159{
3160 switch (old_type) {
3161 case 0:
3162 return NOT_A_BARBARIAN;
3163 case 1:
3164 return LAND_BARBARIAN;
3165 case 2:
3166 return SEA_BARBARIAN;
3167 }
3168
3169 return barbarian_type_invalid();
3170}
struct action * action_by_rule_name(const char *name)
Definition actions.c:1079
int action_number(const struct action *action)
Definition actions.c:1208
static struct action * action_by_number(action_id act_id)
Definition actions.h:396
#define action_iterate_end
Definition actions.h:214
#define action_get_activity(_pact_)
Definition actions.h:460
#define action_iterate(_act_)
Definition actions.h:210
#define ACTION_NONE
Definition actions.h:55
struct @130::my_agent entries[MAX_AGENTS]
const char * default_ai_type_name(void)
Definition aiiface.c:264
#define str
Definition astring.c:76
bool has_capability(const char *cap, const char *capstr)
Definition capability.c:79
char * incite_cost
Definition comments.c:76
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
struct extra_type_list * extra_type_list_by_cause(enum extra_cause cause)
Definition extras.c:249
#define extra_type_by_cause_iterate_end
Definition extras.h:339
#define extra_type_by_cause_iterate(_cause, _extra)
Definition extras.h:333
#define NO_TARGET
Definition fc_types.h:213
#define EC_SPECIAL
Definition fc_types.h:822
revolen_type
Definition fc_types.h:991
@ REVOLEN_RANDOM
Definition fc_types.h:993
@ REVOLEN_RANDQUICK
Definition fc_types.h:995
@ REVOLEN_FIXED
Definition fc_types.h:992
@ REVOLEN_QUICKENING
Definition fc_types.h:994
#define DIR8_ORIGIN
Definition fc_types.h:314
#define _(String)
Definition fcintl.h:67
struct civ_game game
Definition game.c:61
struct world wld
Definition game.c:62
#define GAME_DEFAULT_REVOLENTYPE
Definition game.h:743
#define GAME_DEFAULT_SCORETURN
Definition game.h:587
#define GAME_DEFAULT_SAVETURNS
Definition game.h:685
#define GAME_DEFAULT_TEAM_POOLED_RESEARCH
Definition game.h:571
#define GAME_HARDCODED_DEFAULT_SKILL_LEVEL
Definition game.h:703
GType type
Definition repodlgs.c:1313
const char * name
Definition inputfile.c:127
#define log_verbose(message,...)
Definition log.h:110
#define fc_assert(condition)
Definition log.h:177
#define fc_assert_action(condition, action)
Definition log.h:188
#define log_debug(message,...)
Definition log.h:116
#define log_normal(message,...)
Definition log.h:108
#define log_error(message,...)
Definition log.h:104
struct tile * index_to_tile(const struct civ_map *imap, int mindex)
Definition map.c:471
struct tile * mapstep(const struct civ_map *nmap, const struct tile *ptile, enum direction8 dir)
Definition map.c:384
#define fc_calloc(n, esz)
Definition mem.h:38
#define FC_FREE(ptr)
Definition mem.h:41
#define fc_strdup(str)
Definition mem.h:43
char * lines
Definition packhand.c:131
int len
Definition packhand.c:127
int player_slot_count(void)
Definition player.c:418
int player_slot_index(const struct player_slot *pslot)
Definition player.c:426
#define ANON_USER_NAME
Definition player.h:48
#define player_slots_iterate(_pslot)
Definition player.h:528
#define players_iterate_alive_end
Definition player.h:552
#define player_slots_iterate_end
Definition player.h:532
#define players_iterate_alive(_pplayer)
Definition player.h:547
const char * secfile_error(void)
bool secfile_lookup_int(const struct section_file *secfile, int *ival, const char *path,...)
bool secfile_entry_delete(struct section_file *secfile, const char *path,...)
bool entry_set_name(struct entry *pentry, const char *name)
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,...)
const struct entry_list * section_entries(const struct section *psection)
const char ** secfile_lookup_str_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
const char * entry_name(const struct entry *pentry)
struct entry * secfile_entry_lookup(const struct section_file *secfile, const char *path,...)
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
bool secfile_lookup_bool_default(const struct section_file *secfile, bool def, const char *path,...)
int secfile_lookup_int_default(const struct section_file *secfile, int def, const char *path,...)
struct section * secfile_section_by_name(const struct section_file *secfile, const char *name)
struct section * secfile_section_lookup(const struct section_file *secfile, const char *path,...)
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
bool secfile_lookup_bool(const struct section_file *secfile, bool *bval, const char *path,...)
#define secfile_replace_str_vec(secfile, strings, dim, path,...)
#define secfile_insert_int(secfile, value, path,...)
#define secfile_insert_enum(secfile, enumerator, specenum_type, path,...)
entry_type
@ ENTRY_FILEREFERENCE
@ ENTRY_LONG_COMMENT
@ ENTRY_INT
@ ENTRY_FLOAT
@ ENTRY_STR
@ ENTRY_ILLEGAL
@ ENTRY_BOOL
#define secfile_insert_str_vec(secfile, strings, dim, path,...)
#define secfile_replace_int(secfile, value, path,...)
#define entry_list_iterate_end
#define secfile_entry_ignore(_sfile_, _fmt_,...)
#define secfile_insert_str(secfile, string, path,...)
#define secfile_insert_bool(secfile, value, path,...)
#define secfile_replace_str(secfile, string, path,...)
#define entry_list_iterate(entlist, pentry)
#define secfile_replace_float(secfile, value, path,...)
#define secfile_replace_bool(secfile, value, path,...)
const void * secfile_data_t
static void compat_post_load_030100(struct loaddata *loading, enum sgf_version format_class)
struct extra_type * resource_by_identifier(const char identifier)
Definition savecompat.c:327
int current_compat_ver(void)
Definition savecompat.c:226
static void compat_load_030000(struct loaddata *loading, enum sgf_version format_class)
static const char num_chars[]
Definition savecompat.c:266
bool sg_success
Definition savecompat.c:34
static const char * killcitizen_enum_str(secfile_data_t data, int bit)
Definition savecompat.c:564
enum barbarian_type barb_type_convert(int old_type)
static char * special_names[]
Definition savecompat.c:36
static struct compatibility compat[]
Definition savecompat.c:112
static void compat_load_020400(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:345
static void upgrade_unit_order_targets(struct unit *act_unit)
static void compat_load_030300(struct loaddata *loading, enum sgf_version format_class)
char bin2ascii_hex(int value, int halfbyte_wanted)
Definition savecompat.c:236
static const int compat_num
Definition savecompat.c:137
static void compat_load_020600(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:707
static enum direction8 dir_opposite(enum direction8 dir)
void(* load_version_func_t)(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:92
int char2num(char ch)
Definition savecompat.c:272
static void upgrade_server_side_agent(struct loaddata *loading)
void sg_load_compat(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:147
static void unit_order_activity_to_action(struct unit *act_unit)
static char * revolentype_str(enum revolen_type type)
Definition savecompat.c:688
static int increase_secfile_turn_int(struct loaddata *loading, const char *key, int old_def, bool keep_default)
enum ai_level ai_level_convert(int old_level)
int ascii_hex2bin(char ch, int halfbyte)
Definition savecompat.c:248
struct extra_type * special_extra_get(int spe)
Definition savecompat.c:313
static void compat_load_020500(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:581
static void compat_load_030200(struct loaddata *loading, enum sgf_version format_class)
enum tile_special_type special_by_rule_name(const char *name)
Definition savecompat.c:287
void sg_load_post_load_compat(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:198
const char * special_rule_name(enum tile_special_type type)
Definition savecompat.c:303
static void compat_load_030100(struct loaddata *loading, enum sgf_version format_class)
static void insert_server_side_agent(struct loaddata *loading, enum sgf_version format_class)
#define compat_current
Definition savecompat.c:138
#define sg_check_ret(...)
Definition savecompat.h:150
#define sg_warn(condition, message,...)
Definition savecompat.h:160
tile_special_type
Definition savecompat.h:29
@ S_LAST
Definition savecompat.h:38
#define hex_chars
Definition savecompat.h:205
#define sg_failure_ret_val(condition, _val, message,...)
Definition savecompat.h:184
#define sg_failure_ret(condition, message,...)
Definition savecompat.h:177
#define MAX_TRADE_ROUTES_OLD
Definition savecompat.h:222
sgf_version
Definition savecompat.h:27
@ SAVEGAME_2
Definition savecompat.h:27
@ SAVEGAME_3
Definition savecompat.h:27
#define log_sg
Definition savecompat.h:146
const char * setcompat_S3_2_name_from_S3_1(const char *old_name)
Definition setcompat.c:62
struct setting * setting_by_name(const char *name)
Definition settings.c:3309
const char * setting_value_name(const struct setting *pset, bool pretty, char *buf, size_t buf_len)
Definition settings.c:4267
bool setting_bitwise_set(struct setting *pset, const char *val, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:4223
struct setting_list * level[OLEVELS_NUM]
Definition settings.c:190
const char * setting_bitwise_secfile_str(secfile_data_t data, int bit)
Definition settings.c:4065
#define ARRAY_SIZE(x)
Definition shared.h:85
#define MAX(x, y)
Definition shared.h:54
struct specialist * specialist_by_number(const Specialist_type_id id)
Definition specialist.c:100
const char * specialist_rule_name(const struct specialist *sp)
Definition specialist.c:146
Specialist_type_id specialist_count(void)
Definition specialist.c:71
#define specialist_type_iterate_end
Definition specialist.h:79
#define specialist_type_iterate(sp)
Definition specialist.h:73
size_t size
Definition specvec.h:72
struct sprite int int y
Definition sprite_g.h:31
struct sprite int x
Definition sprite_g.h:31
int world_peace_start
Definition game.h:245
struct packet_game_info info
Definition game.h:89
struct civ_game::@32::@36 server
int north_latitude
Definition map_types.h:80
int south_latitude
Definition map_types.h:81
struct civ_map::@44::@46 server
int huts_absolute
Definition map_types.h:108
const load_version_func_t post_load
Definition savecompat.c:97
const load_version_func_t load
Definition savecompat.c:96
struct name_translation name
Definition specialist.h:31
Definition tile.h:50
enum unit_activity activity
Definition unit.h:95
enum unit_orders order
Definition unit.h:94
int action
Definition unit.h:102
enum direction8 dir
Definition unit.h:104
int target
Definition unit.h:98
int sub_target
Definition unit.h:99
Definition unit.h:140
int length
Definition unit.h:198
bool has_orders
Definition unit.h:196
enum unit_activity activity
Definition unit.h:159
struct unit::@83 orders
struct extra_type * activity_target
Definition unit.h:167
struct unit_order * list
Definition unit.h:201
enum server_side_agent ssa_controller
Definition unit.h:175
struct civ_map map
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:777
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:186
#define sz_strlcpy(dest, src)
Definition support.h:195
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define sz_strlcat(dest, src)
Definition support.h:196
#define fc_strncmp(_s1_, _s2_, _len_)
Definition support.h:160
int team_slot_count(void)
Definition team.c:112
char terrain_identifier(const struct terrain *pterrain)
Definition terrain.c:126
const char * terrain_rule_name(const struct terrain *pterrain)
Definition terrain.c:247
#define terrain_type_iterate(_p)
Definition terrain.h:266
#define terrain_type_iterate_end
Definition terrain.h:272
void free_unit_orders(struct unit *punit)
Definition unit.c:1806
bool unit_can_do_action(const struct unit *punit, const action_id act_id)
Definition unit.c:383
enum gen_action activity_default_action(enum unit_activity act)
Definition unit.c:2930
bool unit_has_orders(const struct unit *punit)
Definition unit.c:202
#define unit_tile(_pu)
Definition unit.h:404
@ ORDER_ACTIVITY
Definition unit.h:42
@ ORDER_PERFORM_ACTION
Definition unit.h:48
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
#define unit_list_iterate_end
Definition unitlist.h:33
void unit_assign_specific_activity_target(struct unit *punit, enum unit_activity *activity, struct extra_type **target)
Definition unittools.c:1082
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:123
bool utype_is_moved_to_tgt_by_action(const struct action *paction, const struct unit_type *utype)
Definition unittype.c:1255
const char * unit_rule_name(const struct unit *punit)
Definition unittype.c:1593
bool utype_is_unmoved_by_action(const struct action *paction, const struct unit_type *utype)
Definition unittype.c:1294