1 /**********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
15 This file includes the definition of a new savegame format introduced with
16 2.3.0. It is defined by the mandatory option '+version2'. The main load
17 function checks if this option is present. If not, the old (pre-2.3.0)
18 loading routines are used.
19 The format version is also saved in the settings section of the savefile, as an
20 integer (savefile.version). The integer is used to determine the version
23 For each savefile format after 2.3.0, compatibility functions are defined
24 which translate secfile structures from previous version to that version;
25 all necessary compat functions are called in order to
26 translate between the file and current version. See sg_load_compat().
28 The integer version ID should be increased every time the format is changed.
29 If the change is not backwards compatible, please state the changes in the
30 following list and update the compat functions at the end of this file.
32 - what was added / removed
33 - when was it added / removed (date and version)
34 - when can additional capability checks be set to mandatory (version)
35 - which compatibility checks are needed and till when (version)
37 freeciv | what | date | id
38 --------+------------------------------------------------+------------+----
39 current | (mapped to current savegame format) | ----/--/-- | 0
40 | first version (svn17538) | 2010/07/05 | -
41 2.3.0 | 2.3.0 release | 2010/11/?? | 3
42 2.4.0 | 2.4.0 release | 201./../.. | 10
43 | * player ai type | |
46 | * save player color | |
47 | * "known" info format change | |
48 2.5.0 | 2.5.0 release (development) | 201./../.. | 20
51 Structure of this file:
53 - The main functions are savegame2_load() and savegame2_save(). Within
54 former function the savegame version is tested and the requested savegame version is
57 - The real work is done by savegame2_load_real() and savegame2_save_real().
58 This function call all submodules (settings, players, etc.)
60 - The remaining part of this file is split into several sections:
62 * save / load functions for all submodules (and their subsubmodules)
64 - If possible, all functions for load / save submodules should exit in
65 pairs named sg_load_<submodule> and sg_save_<submodule>. If one is not
66 needed please add a comment why.
68 - The submodules can be further divided as:
69 sg_load_<submodule>_<subsubmodule>
71 - If needed (due to static variables in the *.c files) these functions
72 can be located in the corresponding source files (as done for the settings
77 (nothing at the moment)
81 - The status of the process is saved within the static variable
82 'sg_success'. This variable is set to TRUE within savegame2_load_real().
83 If you encounter an error use sg_failure_*() to set it to FALSE and
84 return an error message. Furthermore, sg_check_* should be used at the
85 start of each (submodule) function to return if previous functions failed.
87 - While the loading process dependencies between different modules exits.
88 They can be handled within the struct loaddata *loading which is used as
89 first argument for all sg_load_*() function. Please indicate the
90 dependencies within the definition of this struct.
95 #include <fc_config.h>
105 #include "bitvector.h"
111 #include "registry.h"
113 #include "support.h" /* bool type */
118 #include "bitvector.h"
119 #include "capability.h"
120 #include "citizens.h"
123 #include "government.h"
126 #include "movement.h"
128 #include "research.h"
129 #include "rgbcolor.h"
130 #include "specialist.h"
132 #include "unitlist.h"
136 #include "barbarian.h"
137 #include "citizenshand.h"
138 #include "citytools.h"
139 #include "cityturn.h"
140 #include "diplhand.h"
146 #include "sanitycheck.h"
147 #include "savegame.h"
149 #include "settings.h"
150 #include "spacerace.h"
151 #include "srv_main.h"
152 #include "stdinhand.h"
153 #include "techtools.h"
154 #include "unittools.h"
156 /* server/advisors */
158 #include "advbuilding.h"
159 #include "infracache.h"
161 /* server/generator */
163 #include "utilities.h"
165 /* server/scripting */
166 #include "script_server.h"
168 #include "savegame2.h"
170 #define log_sg log_error
172 static bool sg_success
;
174 #define sg_check_ret(...) \
178 #define sg_check_ret_val(_val) \
183 #define sg_warn(condition, message, ...) \
184 if (!(condition)) { \
185 log_sg(message, ## __VA_ARGS__); \
187 #define sg_warn_ret(condition, message, ...) \
188 if (!(condition)) { \
189 log_sg(message, ## __VA_ARGS__); \
192 #define sg_warn_ret_val(condition, _val, message, ...) \
193 if (!(condition)) { \
194 log_sg(message, ## __VA_ARGS__); \
198 #define sg_failure_ret(condition, message, ...) \
199 if (!(condition)) { \
200 sg_success = FALSE; \
201 log_sg(message, ## __VA_ARGS__); \
204 #define sg_failure_ret_val(condition, _val, message, ...) \
205 if (!(condition)) { \
206 sg_success = FALSE; \
207 log_sg(message, ## __VA_ARGS__); \
208 sg_check_ret_val(_val); \
212 * This loops over the entire map to save data. It collects all the data of
213 * a line using GET_XY_CHAR and then executes the macro SECFILE_INSERT_LINE.
216 * ptile: current tile within the line (used by GET_XY_CHAR)
217 * GET_XY_CHAR: macro returning the map character for each position
218 * secfile: a secfile struct
219 * secpath, ...: path as used for sprintf() with arguments; the last item
220 * will be the the y coordinate
222 * SAVE_MAP_CHAR(ptile, terrain2char(ptile->terrain), file, "map.t%04d");
224 #define SAVE_MAP_CHAR(ptile, GET_XY_CHAR, secfile, secpath, ...) \
226 char _line[map.xsize + 1]; \
227 int _nat_x, _nat_y; \
229 for (_nat_y = 0; _nat_y < map.ysize; _nat_y++) { \
230 for (_nat_x = 0; _nat_x < map.xsize; _nat_x++) { \
231 struct tile *ptile = native_pos_to_tile(_nat_x, _nat_y); \
232 fc_assert_action(ptile != NULL, continue); \
233 _line[_nat_x] = (GET_XY_CHAR); \
234 sg_failure_ret(fc_isprint(_line[_nat_x] & 0x7f), \
235 "Trying to write invalid map data at position " \
236 "(%d, %d) for path %s: '%c' (%d)", _nat_x, _nat_y, \
237 secpath, _line[_nat_x], _line[_nat_x]); \
239 _line[map.xsize] = '\0'; \
240 secfile_insert_str(secfile, _line, secpath, ## __VA_ARGS__, _nat_y); \
245 * This loops over the entire map to load data. It inputs a line of data
246 * using the macro SECFILE_LOOKUP_LINE and then loops using the macro
247 * SET_XY_CHAR to load each char into the map at (map_x, map_y). Internal
248 * variables ch, map_x, map_y, nat_x, and nat_y are allocated within the
249 * macro but definable by the caller.
252 * ch: a variable to hold a char (data for a single position,
253 * used by SET_XY_CHAR)
254 * ptile: current tile within the line (used by SET_XY_CHAR)
255 * SET_XY_CHAR: macro to load the map character at each (map_x, map_y)
256 * secfile: a secfile struct
257 * secpath, ...: path as used for sprintf() with arguments; the last item
258 * will be the the y coordinate
260 * LOAD_MAP_CHAR(ch, ptile,
261 * map_get_player_tile(ptile, plr)->terrain
262 * = char2terrain(ch), file, "player%d.map_t%04d", plrno);
264 * Note: some (but not all) of the code this is replacing used to skip over
265 * lines that did not exist. This allowed for backward-compatibility.
266 * We could add another parameter that specified whether it was OK to
267 * skip the data, but there's not really much advantage to exiting
268 * early in this case. Instead, we let any map data type to be empty,
269 * and just print an informative warning message about it.
271 #define LOAD_MAP_CHAR(ch, ptile, SET_XY_CHAR, secfile, secpath, ...) \
273 int _nat_x, _nat_y; \
274 bool _printed_warning = FALSE; \
275 for (_nat_y = 0; _nat_y < map.ysize; _nat_y++) { \
276 const char *_line = secfile_lookup_str(secfile, secpath, \
277 ## __VA_ARGS__, _nat_y); \
278 if (NULL == _line) { \
280 fc_snprintf(buf, sizeof(buf), secpath, ## __VA_ARGS__, _nat_y); \
281 log_verbose("Line not found='%s'", buf); \
282 _printed_warning = TRUE; \
284 } else if (strlen(_line) != map.xsize) { \
286 fc_snprintf(buf, sizeof(buf), secpath, ## __VA_ARGS__, _nat_y); \
287 log_verbose("Line too short (expected %d got %lu)='%s'", \
288 map.xsize, (unsigned long) strlen(_line), buf); \
289 _printed_warning = TRUE; \
292 for (_nat_x = 0; _nat_x < map.xsize; _nat_x++) { \
293 const char ch = _line[_nat_x]; \
294 struct tile *ptile = native_pos_to_tile(_nat_x, _nat_y); \
298 if (_printed_warning) { \
299 /* TRANS: Minor error message. */ \
300 log_sg(_("Saved game contains incomplete map data. This can" \
301 " happen with old saved games, or it may indicate an" \
302 " invalid saved game file. Proceed at your own risk.")); \
306 /* Iterate on the specials half-bytes */
307 #define halfbyte_iterate_special(s, num_specials_types) \
309 enum tile_special_type s; \
310 for(s = 0; 4 * s < (num_specials_types); s++) {
312 #define halfbyte_iterate_special_end \
316 /* Iterate on the bases half-bytes */
317 #define halfbyte_iterate_bases(b, num_bases_types) \
320 for(b = 0; 4 * b < (num_bases_types); b++) {
322 #define halfbyte_iterate_bases_end \
326 /* Iterate on the roads half-bytes */
327 #define halfbyte_iterate_roads(r, num_roads_types) \
330 for(r = 0; 4 * r < (num_roads_types); r++) {
332 #define halfbyte_iterate_roads_end \
337 struct section_file
*file
;
338 const char *secfile_options
;
341 /* loaded in sg_load_savefile(); needed in sg_load_player() */
346 /* loaded in sg_load_savefile(); needed in sg_load_player() */
351 /* loaded in sg_load_savefile(); needed in sg_load_player() */
356 /* loaded in sg_load_savefile(); needed in sg_load_map(), ... */
358 enum tile_special_type
*order
;
361 /* loaded in sg_load_savefile(); needed in sg_load_map(), ... */
363 struct base_type
**order
;
366 /* loaded in sg_load_savefile(); needed in sg_load_map(), ... */
368 struct road_type
**order
;
372 /* loaded in sg_load_game(); needed in sg_load_random(), ... */
373 enum server_states server_state
;
375 /* loaded in sg_load_random(); needed in sg_load_sanitycheck() */
378 /* loaded in sg_load_map_worked(); needed in sg_load_player_cities() */
383 struct section_file
*file
;
384 char secfile_options
[512];
386 /* set by the caller */
387 const char *save_reason
;
390 /* Set in sg_save_game(); needed in sg_save_map_*(); ... */
394 #define TOKEN_SIZE 10
396 #define log_worker log_verbose
398 static const char savefile_options_default
[] =
400 /* The following savefile option are added if needed:
403 * See also calls to sg_save_savefile_options(). */
405 static const char hex_chars
[] = "0123456789abcdef";
406 static const char num_chars
[] =
407 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-+";
409 static void savegame2_load_real(struct section_file
*file
);
410 static void savegame2_save_real(struct section_file
*file
,
411 const char *save_reason
,
413 struct loaddata
*loaddata_new(struct section_file
*file
);
414 void loaddata_destroy(struct loaddata
*loading
);
416 struct savedata
*savedata_new(struct section_file
*file
,
417 const char *save_reason
,
419 void savedata_destroy(struct savedata
*saving
);
421 static enum unit_orders
char2order(char order
);
422 static char order2char(enum unit_orders order
);
423 static enum direction8
char2dir(char dir
);
424 static char dir2char(enum direction8 dir
);
425 static char activity2char(enum unit_activity activity
);
426 static enum unit_activity
char2activity(char activity
);
427 static char *quote_block(const void *const data
, int length
);
428 static int unquote_block(const char *const quoted_
, void *dest
,
430 static void worklist_load(struct section_file
*file
, struct worklist
*pwl
,
431 const char *path
, ...);
432 static void worklist_save(struct section_file
*file
,
433 const struct worklist
*pwl
,
434 int max_length
, const char *path
, ...);
435 static void unit_ordering_calc(void);
436 static void unit_ordering_apply(void);
437 static void sg_special_set(bv_special
*specials
, bv_roads
*roads
, char ch
,
438 const enum tile_special_type
*index
,
439 bool rivers_overlay
);
440 static char sg_special_get(bv_special specials
,
441 const enum tile_special_type
*index
);
442 static void sg_bases_set(bv_bases
*bases
, char ch
, struct base_type
**index
);
443 static char sg_bases_get(bv_bases bases
, const int *index
);
444 static void sg_roads_set(bv_roads
*roads
, char ch
, struct road_type
**index
);
445 static char sg_roads_get(bv_roads roads
, const int *index
);
446 static struct resource
*char2resource(char c
);
447 static char resource2char(const struct resource
*presource
);
448 /* bin2ascii_hex() is defined as macro */
449 static int ascii_hex2bin(char ch
, int halfbyte
);
450 static char num2char(unsigned int num
);
451 static int char2num(char ch
);
452 static struct terrain
*char2terrain(char ch
);
453 static char terrain2char(const struct terrain
*pterrain
);
454 static Tech_type_id
technology_load(struct section_file
*file
,
455 const char* path
, int plrno
);
456 static void technology_save(struct section_file
*file
,
457 const char* path
, int plrno
, Tech_type_id tech
);
459 static void sg_load_compat(struct loaddata
*loading
);
461 static void sg_load_savefile(struct loaddata
*loading
);
462 static void sg_save_savefile(struct savedata
*saving
);
463 static void sg_save_savefile_options(struct savedata
*saving
,
466 static void sg_load_game(struct loaddata
*loading
);
467 static void sg_save_game(struct savedata
*saving
);
469 static void sg_load_random(struct loaddata
*loading
);
470 static void sg_save_random(struct savedata
*saving
);
472 static void sg_load_script(struct loaddata
*loading
);
473 static void sg_save_script(struct savedata
*saving
);
475 static void sg_load_scenario(struct loaddata
*loading
);
476 static void sg_save_scenario(struct savedata
*saving
);
478 static void sg_load_settings(struct loaddata
*loading
);
479 static void sg_save_settings(struct savedata
*saving
);
481 static void sg_load_map(struct loaddata
*loading
);
482 static void sg_save_map(struct savedata
*saving
);
483 static void sg_load_map_tiles(struct loaddata
*loading
);
484 static void sg_save_map_tiles(struct savedata
*saving
);
485 static void sg_load_map_tiles_bases(struct loaddata
*loading
);
486 static void sg_save_map_tiles_bases(struct savedata
*saving
);
487 static void sg_load_map_tiles_roads(struct loaddata
*loading
);
488 static void sg_save_map_tiles_roads(struct savedata
*saving
);
489 static void sg_load_map_tiles_specials(struct loaddata
*loading
,
490 bool rivers_overlay
);
491 static void sg_save_map_tiles_specials(struct savedata
*saving
,
492 bool rivers_overlay
);
493 static void sg_load_map_tiles_resources(struct loaddata
*loading
);
494 static void sg_save_map_tiles_resources(struct savedata
*saving
);
496 static void sg_load_map_startpos(struct loaddata
*loading
);
497 static void sg_save_map_startpos(struct savedata
*saving
);
498 static void sg_load_map_owner(struct loaddata
*loading
);
499 static void sg_save_map_owner(struct savedata
*saving
);
500 static void sg_load_map_worked(struct loaddata
*loading
);
501 static void sg_save_map_worked(struct savedata
*saving
);
502 static void sg_load_map_known(struct loaddata
*loading
);
503 static void sg_save_map_known(struct savedata
*saving
);
505 static void sg_load_players_basic(struct loaddata
*loading
);
506 static void sg_load_players(struct loaddata
*loading
);
507 static void sg_load_player_main(struct loaddata
*loading
,
509 static void sg_load_player_cities(struct loaddata
*loading
,
511 static bool sg_load_player_city(struct loaddata
*loading
, struct player
*plr
,
512 struct city
*pcity
, const char *citystr
);
513 static void sg_load_player_city_citizens(struct loaddata
*loading
,
516 const char *citystr
);
517 static void sg_load_player_units(struct loaddata
*loading
,
519 static bool sg_load_player_unit(struct loaddata
*loading
,
520 struct player
*plr
, struct unit
*punit
,
521 const char *unitstr
);
522 static void sg_load_player_units_transport(struct loaddata
*loading
,
524 static void sg_load_player_attributes(struct loaddata
*loading
,
526 static void sg_load_player_vision(struct loaddata
*loading
,
528 static bool sg_load_player_vision_city(struct loaddata
*loading
,
530 struct vision_site
*pdcity
,
531 const char *citystr
);
532 static void sg_save_players(struct savedata
*saving
);
533 static void sg_save_player_main(struct savedata
*saving
,
535 static void sg_save_player_cities(struct savedata
*saving
,
537 static void sg_save_player_units(struct savedata
*saving
,
539 static void sg_save_player_attributes(struct savedata
*saving
,
541 static void sg_save_player_vision(struct savedata
*saving
,
544 static void sg_load_event_cache(struct loaddata
*loading
);
545 static void sg_save_event_cache(struct savedata
*saving
);
547 static void sg_load_mapimg(struct loaddata
*loading
);
548 static void sg_save_mapimg(struct savedata
*saving
);
550 static void sg_load_sanitycheck(struct loaddata
*loading
);
551 static void sg_save_sanitycheck(struct savedata
*saving
);
555 typedef void (*load_version_func_t
) (struct loaddata
*loading
);
557 static void compat_load_020400(struct loaddata
*loading
);
558 static void compat_load_020500(struct loaddata
*loading
);
560 struct compatibility
{
562 const load_version_func_t load
;
565 /* The struct below contains the information about the savegame versions. It
566 * is identified by the version number (first element), which should be
567 * steadily increasing. It is saved as 'savefile.version'. The support
568 * string (first element of 'name') is not saved in the savegame; it is
569 * saved in settings files (so, once assigned, cannot be changed). The
570 * 'pretty' string (second element of 'name') can be changed if necessary
571 * For changes in the development version, edit the definitions above and
572 * add the needed code to load the old version below. Thus, old
573 * savegames can still be loaded while the main definition
574 * represents the current state of the art. */
575 /* While developing freeciv 2.5.0, add the compatibility functions to
576 * - compat_load_020500 to load old savegame. */
577 static struct compatibility compat
[] = {
578 /* dummy; equal to the current version (last element) */
580 /* version 1 and 2 is not used */
581 /* version 3: first savegame2 format, so no compat functions for translation
582 * from previous format */
584 /* version 4 to 9 are reserved for possible changes in 2.3.x */
585 { 10, compat_load_020400
},
586 /* version 11 to 19 are reserved for possible changes in 2.4.x */
587 { 20, compat_load_020500
},
588 /* Current savefile version is listed above this line; it corresponds to
589 the definitions in this file. */
592 static const int compat_num
= ARRAY_SIZE(compat
);
593 #define compat_current (compat_num - 1)
595 /****************************************************************************
596 Main entry point for loading a game.
597 Called only in ./server/stdinhand.c:load_command().
598 The entire ruleset is always sent afterwards->
599 ****************************************************************************/
600 void savegame2_load(struct section_file
*file
)
602 const char *savefile_options
;
604 fc_assert_ret(file
!= NULL
);
607 struct timer
*loadtimer
= timer_new(TIMER_CPU
, TIMER_DEBUG
);
608 timer_start(loadtimer
);
611 savefile_options
= secfile_lookup_str(file
, "savefile.options");
613 if (!savefile_options
) {
614 log_error("Missing savefile options. Can not load the savegame.");
618 if (!has_capabilities("+version2", savefile_options
)) {
619 /* load old format (freeciv 2.2.x) */
620 log_verbose("loading savefile in old format ...");
621 secfile_allow_digital_boolean(file
, TRUE
);
622 legacy_game_load(file
);
624 /* load new format (freeciv 2.2.99 and newer) */
625 log_verbose("loading savefile in new format ...");
626 savegame2_load_real(file
);
630 timer_stop(loadtimer
);
631 log_debug("Loading secfile in %.3f seconds.", timer_read_seconds(loadtimer
));
632 timer_destroy(loadtimer
);
633 #endif /* DEBUG_TIMERS */
636 /****************************************************************************
637 Main entry point for saving a game.
638 Called only in ./server/srv_main.c:save_game().
639 ****************************************************************************/
640 void savegame2_save(struct section_file
*file
, const char *save_reason
,
643 fc_assert_ret(file
!= NULL
);
646 struct timer
*savetimer
= timer_new(TIMER_CPU
, TIMER_DEBUG
);
647 timer_start(savetimer
);
650 log_verbose("saving game in new format ...");
651 savegame2_save_real(file
, save_reason
, scenario
);
654 timer_stop(savetimer
);
655 log_debug("Creating secfile in %.3f seconds.", timer_read_seconds(savetimer
));
656 timer_destroy(savetimer
);
657 #endif /* DEBUG_TIMERS */
660 /* =======================================================================
661 * Basic load / save functions.
662 * ======================================================================= */
664 /****************************************************************************
665 Really loading the savegame.
666 ****************************************************************************/
667 static void savegame2_load_real(struct section_file
*file
)
669 struct loaddata
*loading
;
670 bool was_send_city_suppressed
, was_send_tile_suppressed
;
672 /* initialise loading */
673 was_send_city_suppressed
= send_city_suppression(TRUE
);
674 was_send_tile_suppressed
= send_tile_suppression(TRUE
);
675 loading
= loaddata_new(file
);
678 /* Load the savegame data. */
680 sg_load_compat(loading
);
682 sg_load_savefile(loading
);
684 sg_load_game(loading
);
686 sg_load_random(loading
);
688 sg_load_script(loading
);
690 sg_load_scenario(loading
);
692 sg_load_settings(loading
);
693 /* [players] (basic data) */
694 sg_load_players_basic(loading
);
695 /* [map]; needs width and height loaded by [settings] */
696 sg_load_map(loading
);
698 sg_load_players(loading
);
700 sg_load_event_cache(loading
);
702 sg_load_mapimg(loading
);
704 /* Sanity checks for the loaded game. */
705 sg_load_sanitycheck(loading
);
707 /* deinitialise loading */
708 loaddata_destroy(loading
);
709 send_tile_suppression(was_send_tile_suppressed
);
710 send_city_suppression(was_send_city_suppressed
);
713 log_error("Failure loading savegame!");
718 /****************************************************************************
719 Really save the game to a file.
720 ****************************************************************************/
721 static void savegame2_save_real(struct section_file
*file
,
722 const char *save_reason
,
725 struct savedata
*saving
;
727 /* initialise loading */
728 saving
= savedata_new(file
, save_reason
, scenario
);
732 /* This should be first section so scanning through all scenarios just for
733 * names and descriptions would go faster. */
734 sg_save_scenario(saving
);
736 sg_save_savefile(saving
);
738 sg_save_game(saving
);
740 sg_save_random(saving
);
742 sg_save_script(saving
);
744 sg_save_settings(saving
);
748 sg_save_players(saving
);
750 sg_save_event_cache(saving
);
752 sg_save_mapimg(saving
);
754 /* Sanity checks for the saved game. */
755 sg_save_sanitycheck(saving
);
757 /* deinitialise saving */
758 savedata_destroy(saving
);
761 log_error("Failure saving savegame!");
765 /****************************************************************************
766 Create new loaddata item for given section file.
767 ****************************************************************************/
768 struct loaddata
*loaddata_new(struct section_file
*file
)
770 struct loaddata
*loading
= calloc(1, sizeof(*loading
));
771 loading
->file
= file
;
772 loading
->secfile_options
= NULL
;
774 loading
->improvement
.order
= NULL
;
775 loading
->improvement
.size
= -1;
776 loading
->technology
.order
= NULL
;
777 loading
->technology
.size
= -1;
778 loading
->trait
.order
= NULL
;
779 loading
->trait
.size
= -1;
780 loading
->special
.order
= NULL
;
781 loading
->special
.size
= -1;
782 loading
->base
.order
= NULL
;
783 loading
->base
.size
= -1;
784 loading
->road
.order
= NULL
;
785 loading
->road
.size
= -1;
787 loading
->server_state
= S_S_INITIAL
;
788 loading
->rstate
= fc_rand_state();
789 loading
->worked_tiles
= NULL
;
794 /****************************************************************************
795 Free resources allocated for loaddata item.
796 ****************************************************************************/
797 void loaddata_destroy(struct loaddata
*loading
)
799 if (loading
->improvement
.order
!= NULL
) {
800 free(loading
->improvement
.order
);
803 if (loading
->technology
.order
!= NULL
) {
804 free(loading
->technology
.order
);
807 if (loading
->trait
.order
!= NULL
) {
808 free(loading
->trait
.order
);
811 if (loading
->special
.order
!= NULL
) {
812 free(loading
->special
.order
);
815 if (loading
->base
.order
!= NULL
) {
816 free(loading
->base
.order
);
819 if (loading
->road
.order
!= NULL
) {
820 free(loading
->road
.order
);
823 if (loading
->worked_tiles
!= NULL
) {
824 free(loading
->worked_tiles
);
830 /****************************************************************************
831 Create new savedata item for given file.
832 ****************************************************************************/
833 struct savedata
*savedata_new(struct section_file
*file
,
834 const char *save_reason
,
837 struct savedata
*saving
= calloc(1, sizeof(*saving
));
839 saving
->secfile_options
[0] = '\0';
841 saving
->save_reason
= save_reason
;
842 saving
->scenario
= scenario
;
844 saving
->save_players
= FALSE
;
849 /****************************************************************************
850 Free resources allocated for savedata item
851 ****************************************************************************/
852 void savedata_destroy(struct savedata
*saving
)
857 /* =======================================================================
859 * ======================================================================= */
861 /****************************************************************************
862 Returns an order for a character identifier. See also order2char.
863 ****************************************************************************/
864 static enum unit_orders
char2order(char order
)
872 return ORDER_FULL_MP
;
875 return ORDER_BUILD_CITY
;
878 return ORDER_ACTIVITY
;
881 return ORDER_DISBAND
;
884 return ORDER_BUILD_WONDER
;
887 return ORDER_TRADE_ROUTE
;
890 return ORDER_HOMECITY
;
893 /* This can happen if the savegame is invalid. */
897 /****************************************************************************
898 Returns a character identifier for an order. See also char2order.
899 ****************************************************************************/
900 static char order2char(enum unit_orders order
)
909 case ORDER_BUILD_CITY
:
913 case ORDER_BUILD_WONDER
:
915 case ORDER_TRADE_ROUTE
:
927 /****************************************************************************
928 Returns a direction for a character identifier. See also dir2char.
929 ****************************************************************************/
930 static enum direction8
char2dir(char dir
)
932 /* Numberpad values for the directions. */
935 return DIR8_SOUTHWEST
;
939 return DIR8_SOUTHEAST
;
945 return DIR8_NORTHWEST
;
949 return DIR8_NORTHEAST
;
952 /* This can happen if the savegame is invalid. */
953 return direction8_invalid();
956 /****************************************************************************
957 Returns a character identifier for a direction. See also char2dir.
958 ****************************************************************************/
959 static char dir2char(enum direction8 dir
)
961 /* Numberpad values for the directions. */
985 /****************************************************************************
986 Returns a character identifier for an activity. See also char2activity.
987 ****************************************************************************/
988 static char activity2char(enum unit_activity activity
)
993 case ACTIVITY_POLLUTION
:
995 case ACTIVITY_OLD_ROAD
:
999 case ACTIVITY_IRRIGATE
:
1001 case ACTIVITY_FORTIFIED
:
1003 case ACTIVITY_FORTRESS
:
1005 case ACTIVITY_SENTRY
:
1007 case ACTIVITY_OLD_RAILROAD
:
1009 case ACTIVITY_PILLAGE
:
1013 case ACTIVITY_EXPLORE
:
1015 case ACTIVITY_TRANSFORM
:
1017 case ACTIVITY_AIRBASE
:
1019 case ACTIVITY_FORTIFYING
:
1021 case ACTIVITY_FALLOUT
:
1025 case ACTIVITY_GEN_ROAD
:
1027 case ACTIVITY_CONVERT
:
1029 case ACTIVITY_UNKNOWN
:
1030 case ACTIVITY_PATROL_UNUSED
:
1040 /****************************************************************************
1041 Returns an activity for a character identifier. See also activity2char.
1042 ****************************************************************************/
1043 static enum unit_activity
char2activity(char activity
)
1045 enum unit_activity a
;
1047 for (a
= 0; a
< ACTIVITY_LAST
; a
++) {
1048 char achar
= activity2char(a
);
1050 if (activity
== achar
) {
1055 /* This can happen if the savegame is invalid. */
1056 return ACTIVITY_LAST
;
1059 /****************************************************************************
1060 Quote the memory block denoted by data and length so it consists only of
1061 " a-f0-9:". The returned string has to be freed by the caller using free().
1062 ****************************************************************************/
1063 static char *quote_block(const void *const data
, int length
)
1065 char *buffer
= fc_malloc(length
* 3 + 10);
1069 sprintf(buffer
, "%d:", length
);
1070 offset
= strlen(buffer
);
1072 for (i
= 0; i
< length
; i
++) {
1073 sprintf(buffer
+ offset
, "%02x ", ((unsigned char *) data
)[i
]);
1079 /****************************************************************************
1080 Unquote a string. The unquoted data is written into dest. If the unqoted
1081 data will be largern than dest_length the function aborts. It returns the
1082 actual length of the unquoted block.
1083 ****************************************************************************/
1084 static int unquote_block(const char *const quoted_
, void *dest
,
1087 int i
, length
, parsed
, tmp
;
1089 const char *quoted
= quoted_
;
1091 parsed
= sscanf(quoted
, "%d", &length
);
1092 fc_assert_ret_val(1 == parsed
, 0);
1094 fc_assert_ret_val(length
<= dest_length
, 0);
1095 quoted
= strchr(quoted
, ':');
1096 fc_assert_ret_val(quoted
!= NULL
, 0);
1099 for (i
= 0; i
< length
; i
++) {
1100 tmp
= strtol(quoted
, &endptr
, 16);
1101 fc_assert_ret_val((endptr
- quoted
) == 2, 0);
1102 fc_assert_ret_val(*endptr
== ' ', 0);
1103 fc_assert_ret_val((tmp
& 0xff) == tmp
, 0);
1104 ((unsigned char *) dest
)[i
] = tmp
;
1110 /****************************************************************************
1111 Load the worklist elements specified by path to the worklist pointed to
1112 by 'pwl'. 'pwl' should be a pointer to an existing worklist.
1113 ****************************************************************************/
1114 static void worklist_load(struct section_file
*file
, struct worklist
*pwl
,
1115 const char *path
, ...)
1120 char path_str
[1024];
1123 /* The first part of the registry path is taken from the varargs to the
1126 fc_vsnprintf(path_str
, sizeof(path_str
), path
, ap
);
1130 pwl
->length
= secfile_lookup_int_default(file
, 0,
1131 "%s.wl_length", path_str
);
1133 for (i
= 0; i
< pwl
->length
; i
++) {
1134 kind
= secfile_lookup_str(file
, "%s.wl_kind%d", path_str
, i
);
1136 /* We lookup the production value by name. An invalid entry isn't a
1137 * fatal error; we just truncate the worklist. */
1138 name
= secfile_lookup_str_default(file
, "-", "%s.wl_value%d",
1140 pwl
->entries
[i
] = universal_by_rule_name(kind
, name
);
1141 if (pwl
->entries
[i
].kind
== universals_n_invalid()) {
1142 log_sg("%s.wl_value%d: unknown \"%s\" \"%s\".", path_str
, i
, kind
,
1150 /****************************************************************************
1151 Save the worklist elements specified by path from the worklist pointed to
1152 by 'pwl'. 'pwl' should be a pointer to an existing worklist.
1153 ****************************************************************************/
1154 static void worklist_save(struct section_file
*file
,
1155 const struct worklist
*pwl
,
1156 int max_length
, const char *path
, ...)
1158 char path_str
[1024];
1162 /* The first part of the registry path is taken from the varargs to the
1165 fc_vsnprintf(path_str
, sizeof(path_str
), path
, ap
);
1168 secfile_insert_int(file
, pwl
->length
, "%s.wl_length", path_str
);
1170 for (i
= 0; i
< pwl
->length
; i
++) {
1171 const struct universal
*entry
= pwl
->entries
+ i
;
1172 secfile_insert_str(file
, universal_type_rule_name(entry
),
1173 "%s.wl_kind%d", path_str
, i
);
1174 secfile_insert_str(file
, universal_rule_name(entry
),
1175 "%s.wl_value%d", path_str
, i
);
1178 fc_assert_ret(max_length
<= MAX_LEN_WORKLIST
);
1180 /* We want to keep savegame in tabular format, so each line has to be
1181 * of equal length. Fill table up to maximum worklist size. */
1182 for (i
= pwl
->length
; i
< max_length
; i
++) {
1183 secfile_insert_str(file
, "", "%s.wl_kind%d", path_str
, i
);
1184 secfile_insert_str(file
, "", "%s.wl_value%d", path_str
, i
);
1188 /****************************************************************************
1189 Assign values to ord_city and ord_map for each unit, so the values can be
1191 ****************************************************************************/
1192 static void unit_ordering_calc(void)
1196 players_iterate(pplayer
) {
1197 /* to avoid junk values for unsupported units: */
1198 unit_list_iterate(pplayer
->units
, punit
) {
1199 punit
->server
.ord_city
= 0;
1200 } unit_list_iterate_end
;
1201 city_list_iterate(pplayer
->cities
, pcity
) {
1203 unit_list_iterate(pcity
->units_supported
, punit
) {
1204 punit
->server
.ord_city
= j
++;
1205 } unit_list_iterate_end
;
1206 } city_list_iterate_end
;
1207 } players_iterate_end
;
1209 whole_map_iterate(ptile
) {
1211 unit_list_iterate(ptile
->units
, punit
) {
1212 punit
->server
.ord_map
= j
++;
1213 } unit_list_iterate_end
;
1214 } whole_map_iterate_end
;
1217 /****************************************************************************
1218 For each city and tile, sort unit lists according to ord_city and ord_map
1220 ****************************************************************************/
1221 static void unit_ordering_apply(void)
1223 players_iterate(pplayer
) {
1224 city_list_iterate(pplayer
->cities
, pcity
) {
1225 unit_list_sort_ord_city(pcity
->units_supported
);
1227 city_list_iterate_end
;
1228 } players_iterate_end
;
1230 whole_map_iterate(ptile
) {
1231 unit_list_sort_ord_map(ptile
->units
);
1232 } whole_map_iterate_end
;
1235 /****************************************************************************
1236 Complicated helper function for loading specials from a savegame.
1238 'ch' gives the character loaded from the savegame. Specials are packed
1239 in four to a character in hex notation. 'index' is a mapping of
1240 savegame bit -> special bit. S_LAST is used to mark unused savegame bits.
1241 ****************************************************************************/
1242 static void sg_special_set(bv_special
*specials
, bv_roads
*roads
,
1244 const enum tile_special_type
*index
,
1245 bool rivers_overlay
)
1248 const char *pch
= strchr(hex_chars
, ch
);
1250 if (!pch
|| ch
== '\0') {
1251 log_sg("Unknown hex value: '%c' (%d)", ch
, ch
);
1254 bin
= pch
- hex_chars
;
1257 for (i
= 0; i
< 4; i
++) {
1258 enum tile_special_type sp
= index
[i
];
1263 if (rivers_overlay
&& sp
!= S_OLD_RIVER
) {
1267 if (bin
& (1 << i
)) {
1268 if (sp
== S_OLD_ROAD
) {
1270 struct road_type
*proad
;
1272 proad
= road_by_compat_special(ROCO_ROAD
);
1274 BV_SET(*roads
, road_index(proad
));
1277 } else if (sp
== S_OLD_RAILROAD
) {
1279 struct road_type
*proad
;
1281 proad
= road_by_compat_special(ROCO_RAILROAD
);
1283 BV_SET(*roads
, road_index(proad
));
1286 } else if (sp
== S_OLD_RIVER
) {
1288 struct road_type
*proad
;
1290 proad
= road_by_compat_special(ROCO_RIVER
);
1292 BV_SET(*roads
, road_index(proad
));
1296 set_special(specials
, sp
);
1302 /****************************************************************************
1303 Complicated helper function for saving specials into a savegame.
1305 Specials are packed in four to a character in hex notation. 'index'
1306 specifies which set of specials are included in this character.
1307 ****************************************************************************/
1308 static char sg_special_get(bv_special specials
,
1309 const enum tile_special_type
*index
)
1313 for (i
= 0; i
< 4; i
++) {
1314 enum tile_special_type sp
= index
[i
];
1319 if (contains_special(specials
, sp
)) {
1324 return hex_chars
[bin
];
1327 /****************************************************************************
1328 Helper function for loading bases from a savegame.
1330 'ch' gives the character loaded from the savegame. Bases are packed
1331 in four to a character in hex notation. 'index' is a mapping of
1332 savegame bit -> base bit.
1333 ****************************************************************************/
1334 static void sg_bases_set(bv_bases
*bases
, char ch
, struct base_type
**index
)
1337 const char *pch
= strchr(hex_chars
, ch
);
1339 if (!pch
|| ch
== '\0') {
1340 log_sg("Unknown hex value: '%c' (%d)", ch
, ch
);
1343 bin
= pch
- hex_chars
;
1346 for (i
= 0; i
< 4; i
++) {
1347 struct base_type
*pbase
= index
[i
];
1349 if (pbase
== NULL
) {
1352 if (bin
& (1 << i
)) {
1353 BV_SET(*bases
, base_index(pbase
));
1358 /****************************************************************************
1359 Helper function for saving bases into a savegame.
1361 Specials are packed in four to a character in hex notation. 'index'
1362 specifies which set of bases are included in this character.
1363 ****************************************************************************/
1364 static char sg_bases_get(bv_bases bases
, const int *index
)
1368 for (i
= 0; i
< 4; i
++) {
1369 int base
= index
[i
];
1374 if (BV_ISSET(bases
, base
)) {
1379 return hex_chars
[bin
];
1382 /****************************************************************************
1383 Helper function for loading roads from a savegame.
1385 'ch' gives the character loaded from the savegame. Roads are packed
1386 in four to a character in hex notation. 'index' is a mapping of
1387 savegame bit -> road bit.
1388 ****************************************************************************/
1389 static void sg_roads_set(bv_roads
*roads
, char ch
, struct road_type
**index
)
1392 const char *pch
= strchr(hex_chars
, ch
);
1394 if (!pch
|| ch
== '\0') {
1395 log_sg("Unknown hex value: '%c' (%d)", ch
, ch
);
1398 bin
= pch
- hex_chars
;
1401 for (i
= 0; i
< 4; i
++) {
1402 struct road_type
*proad
= index
[i
];
1404 if (proad
== NULL
) {
1407 if (bin
& (1 << i
)) {
1408 BV_SET(*roads
, road_index(proad
));
1413 /****************************************************************************
1414 Helper function for saving roads into a savegame.
1416 Specials are packed in four to a character in hex notation. 'index'
1417 specifies which set of roads are included in this character.
1418 ****************************************************************************/
1419 static char sg_roads_get(bv_roads roads
, const int *index
)
1423 for (i
= 0; i
< 4; i
++) {
1424 int road
= index
[i
];
1429 if (BV_ISSET(roads
, road
)) {
1434 return hex_chars
[bin
];
1437 /****************************************************************************
1438 Return the resource for the given identifier.
1439 ****************************************************************************/
1440 static struct resource
*char2resource(char c
)
1442 /* speed common values */
1443 if (c
== RESOURCE_NULL_IDENTIFIER
1444 || c
== RESOURCE_NONE_IDENTIFIER
) {
1447 return resource_by_identifier(c
);
1450 /****************************************************************************
1451 Return the identifier for the given resource.
1452 ****************************************************************************/
1453 static char resource2char(const struct resource
*presource
)
1455 return presource
? presource
->identifier
: RESOURCE_NONE_IDENTIFIER
;
1458 /****************************************************************************
1459 This returns an ascii hex value of the given half-byte of the binary
1460 integer. See ascii_hex2bin().
1461 example: bin2ascii_hex(0xa00, 2) == 'a'
1462 ****************************************************************************/
1463 #define bin2ascii_hex(value, halfbyte_wanted) \
1464 hex_chars[((value) >> ((halfbyte_wanted) * 4)) & 0xf]
1466 /****************************************************************************
1467 This returns a binary integer value of the ascii hex char, offset by the
1468 given number of half-bytes. See bin2ascii_hex().
1469 example: ascii_hex2bin('a', 2) == 0xa00
1470 This is only used in loading games, and it requires some error checking so
1471 it's done as a function.
1472 ****************************************************************************/
1473 static int ascii_hex2bin(char ch
, int halfbyte
)
1478 /* Sane value. It is unknow if there are savegames out there which
1479 * need this fix. Savegame.c doesn't write such savegames
1480 * (anymore) since the inclusion into CVS (2000-08-25). */
1484 pch
= strchr(hex_chars
, ch
);
1486 sg_failure_ret_val(NULL
!= pch
&& '\0' != ch
, 0,
1487 "Unknown hex value: '%c' %d", ch
, ch
);
1488 return (pch
- hex_chars
) << (halfbyte
* 4);
1491 /****************************************************************************
1492 Converts number in to single character. This works to values up to ~70.
1493 ****************************************************************************/
1494 static char num2char(unsigned int num
)
1496 if (num
>= strlen(num_chars
)) {
1500 return num_chars
[num
];
1503 /****************************************************************************
1504 Converts single character into numerical value. This is not hex conversion.
1505 ****************************************************************************/
1506 static int char2num(char ch
)
1510 pch
= strchr(num_chars
, ch
);
1512 sg_failure_ret_val(NULL
!= pch
, 0,
1513 "Unknown ascii value for num: '%c' %d", ch
, ch
);
1515 return pch
- num_chars
;
1518 /****************************************************************************
1519 Dereferences the terrain character. See terrains[].identifier
1520 example: char2terrain('a') => T_ARCTIC
1521 ****************************************************************************/
1522 static struct terrain
*char2terrain(char ch
)
1524 /* terrain_by_identifier plus fatal error */
1525 if (ch
== TERRAIN_UNKNOWN_IDENTIFIER
) {
1528 terrain_type_iterate(pterrain
) {
1529 if (pterrain
->identifier
== ch
) {
1532 } terrain_type_iterate_end
;
1534 log_fatal("Unknown terrain identifier '%c' in savegame.", ch
);
1538 /****************************************************************************
1539 References the terrain character. See terrains[].identifier
1540 example: terrain2char(T_ARCTIC) => 'a'
1541 ****************************************************************************/
1542 static char terrain2char(const struct terrain
*pterrain
)
1544 if (pterrain
== T_UNKNOWN
) {
1545 return TERRAIN_UNKNOWN_IDENTIFIER
;
1547 return pterrain
->identifier
;
1551 /*****************************************************************************
1552 Load technology from path_name and if doesn't exist (because savegame
1553 is too old) load from path.
1554 *****************************************************************************/
1555 static Tech_type_id
technology_load(struct section_file
*file
,
1556 const char* path
, int plrno
)
1558 char path_with_name
[128];
1560 struct advance
*padvance
;
1562 fc_snprintf(path_with_name
, sizeof(path_with_name
),
1565 name
= secfile_lookup_str(file
, path_with_name
, plrno
);
1567 if (!name
|| name
[0] == '\0') {
1568 /* used by researching_saved */
1571 if (fc_strcasecmp(name
, "A_FUTURE") == 0) {
1574 if (fc_strcasecmp(name
, "A_NONE") == 0) {
1577 if (fc_strcasecmp(name
, "A_UNSET") == 0) {
1581 padvance
= advance_by_rule_name(name
);
1582 sg_failure_ret_val(NULL
!= padvance
, A_NONE
,
1583 "%s: unknown technology \"%s\".", path_with_name
, name
);
1585 return advance_number(padvance
);
1588 /*****************************************************************************
1589 Save technology in secfile entry called path_name.
1590 *****************************************************************************/
1591 static void technology_save(struct section_file
*file
,
1592 const char* path
, int plrno
, Tech_type_id tech
)
1594 char path_with_name
[128];
1597 fc_snprintf(path_with_name
, sizeof(path_with_name
),
1601 case A_UNKNOWN
: /* used by researching_saved */
1614 name
= advance_rule_name(advance_by_number(tech
));
1618 secfile_insert_str(file
, name
, path_with_name
, plrno
);
1621 /* =======================================================================
1622 * Load / save savefile data.
1623 * ======================================================================= */
1625 /****************************************************************************
1627 ****************************************************************************/
1628 static void sg_load_savefile(struct loaddata
*loading
)
1630 /* Check status and return if not OK (sg_success != TRUE). */
1633 /* Load savefile options. */
1634 loading
->secfile_options
1635 = secfile_lookup_str(loading
->file
, "savefile.options");
1637 /* We don't need savefile.reason, but read it anyway to avoid
1638 * warnings about unread secfile entries. */
1639 (void) secfile_entry_by_path(loading
->file
, "savefile.reason");
1642 sz_strlcpy(game
.server
.rulesetdir
,
1643 secfile_lookup_str_default(loading
->file
, "classic",
1644 "savefile.rulesetdir"));
1645 if (!strcmp("default", game
.server
.rulesetdir
)) {
1646 sz_strlcpy(game
.server
.rulesetdir
, "classic");
1648 if (!load_rulesets(NULL
, TRUE
)) {
1649 /* Failed to load correct ruleset */
1650 sg_failure_ret(TRUE
, "Failed to load ruleset");
1653 /* Load improvements. */
1654 loading
->improvement
.size
1655 = secfile_lookup_int_default(loading
->file
, 0,
1656 "savefile.improvement_size");
1657 if (loading
->improvement
.size
) {
1658 loading
->improvement
.order
1659 = secfile_lookup_str_vec(loading
->file
, &loading
->improvement
.size
,
1660 "savefile.improvement_vector");
1661 sg_failure_ret(loading
->improvement
.size
!= 0,
1662 "Failed to load improvement order: %s",
1666 /* Load technologies. */
1667 loading
->technology
.size
1668 = secfile_lookup_int_default(loading
->file
, 0,
1669 "savefile.technology_size");
1670 if (loading
->technology
.size
) {
1671 loading
->technology
.order
1672 = secfile_lookup_str_vec(loading
->file
, &loading
->technology
.size
,
1673 "savefile.technology_vector");
1674 sg_failure_ret(loading
->improvement
.size
!= 0,
1675 "Failed to load technology order: %s",
1681 = secfile_lookup_int_default(loading
->file
, 0,
1682 "savefile.trait_size");
1683 if (loading
->trait
.size
) {
1684 loading
->trait
.order
1685 = secfile_lookup_str_vec(loading
->file
, &loading
->trait
.size
,
1686 "savefile.trait_vector");
1687 sg_failure_ret(loading
->trait
.size
!= 0,
1688 "Failed to load trait order: %s",
1692 /* Load specials. */
1693 loading
->special
.size
1694 = secfile_lookup_int_default(loading
->file
, 0,
1695 "savefile.specials_size");
1697 const char **modname
;
1699 enum tile_special_type j
;
1701 modname
= secfile_lookup_str_vec(loading
->file
, &loading
->special
.size
,
1702 "savefile.specials_vector");
1703 sg_failure_ret(loading
->special
.size
!= 0,
1704 "Failed to load specials order: %s",
1706 /* make sure that the size of the array is divisible by 4 */
1707 /* Allocating extra 4 slots, just a couple of bytes,
1708 * in case of special.size being divisible by 4 already is intentional.
1709 * Added complexity would cost those couple of bytes in code size alone,
1710 * and we actually need at least one slot immediately after last valid
1711 * one. That's where S_LAST is (or was in version that saved the game)
1712 * and in some cases S_LAST gets written to savegame, at least as
1713 * activity target special when activity targets some base or road
1714 * instead. By having current S_LAST in that index allows us to map
1715 * that old S_LAST to current S_LAST, just like any real special within
1716 * special.size gets mapped. */
1717 nmod
= loading
->special
.size
+ (4 - (loading
->special
.size
% 4));
1718 loading
->special
.order
= fc_calloc(nmod
,
1719 sizeof(*loading
->special
.order
));
1720 for (j
= 0; j
< loading
->special
.size
; j
++) {
1721 if (!strcasecmp("Road", modname
[j
])) {
1722 loading
->special
.order
[j
] = S_OLD_ROAD
;
1723 } else if (!strcasecmp("Railroad", modname
[j
])) {
1724 loading
->special
.order
[j
] = S_OLD_RAILROAD
;
1725 } else if (!strcasecmp("River", modname
[j
])) {
1726 loading
->special
.order
[j
] = S_OLD_RIVER
;
1728 loading
->special
.order
[j
] = special_by_rule_name(modname
[j
]);
1732 for (; j
< nmod
; j
++) {
1733 loading
->special
.order
[j
] = S_LAST
;
1739 = secfile_lookup_int_default(loading
->file
, 0,
1740 "savefile.bases_size");
1741 if (loading
->base
.size
) {
1742 const char **modname
;
1746 modname
= secfile_lookup_str_vec(loading
->file
, &loading
->base
.size
,
1747 "savefile.bases_vector");
1748 sg_failure_ret(loading
->base
.size
!= 0,
1749 "Failed to load bases order: %s",
1751 sg_failure_ret(!(game
.control
.num_base_types
< loading
->base
.size
),
1752 "Number of bases defined by the ruleset (= %d) are "
1753 "lower than the number in the savefile (= %d).",
1754 game
.control
.num_base_types
, (int)loading
->base
.size
);
1755 /* make sure that the size of the array is divisible by 4 */
1756 nmod
= 4 * ((loading
->base
.size
+ 3) / 4);
1757 loading
->base
.order
= fc_calloc(nmod
, sizeof(*loading
->base
.order
));
1758 for (j
= 0; j
< loading
->base
.size
; j
++) {
1759 loading
->base
.order
[j
] = base_type_by_rule_name(modname
[j
]);
1762 for (; j
< nmod
; j
++) {
1763 loading
->base
.order
[j
] = NULL
;
1769 = secfile_lookup_int_default(loading
->file
, 0,
1770 "savefile.roads_size");
1771 if (loading
->road
.size
) {
1772 const char **modname
;
1776 modname
= secfile_lookup_str_vec(loading
->file
, &loading
->road
.size
,
1777 "savefile.roads_vector");
1778 sg_failure_ret(loading
->road
.size
!= 0,
1779 "Failed to load roads order: %s",
1781 sg_failure_ret(!(game
.control
.num_road_types
< loading
->road
.size
),
1782 "Number of roads defined by the ruleset (= %d) are "
1783 "lower than the number in the savefile (= %d).",
1784 game
.control
.num_road_types
, (int)loading
->road
.size
);
1785 /* make sure that the size of the array is divisible by 4 */
1786 nmod
= 4 * ((loading
->road
.size
+ 3) / 4);
1787 loading
->road
.order
= fc_calloc(nmod
, sizeof(*loading
->road
.order
));
1788 for (j
= 0; j
< loading
->road
.size
; j
++) {
1789 loading
->road
.order
[j
] = road_type_by_rule_name(modname
[j
]);
1792 for (; j
< nmod
; j
++) {
1793 loading
->road
.order
[j
] = NULL
;
1798 /****************************************************************************
1800 ****************************************************************************/
1801 static void sg_save_savefile(struct savedata
*saving
)
1803 /* Check status and return if not OK (sg_success != TRUE). */
1806 /* Save savefile options. */
1807 sg_save_savefile_options(saving
, savefile_options_default
);
1809 secfile_insert_int(saving
->file
, compat
[compat_current
].version
, "savefile.version");
1811 /* Save reason of the savefile generation. */
1812 secfile_insert_str(saving
->file
, saving
->save_reason
, "savefile.reason");
1814 /* Save rulesetdir at this point as this ruleset is required by this
1816 secfile_insert_str(saving
->file
, game
.server
.rulesetdir
, "savefile.rulesetdir");
1818 /* Save improvement order in savegame, so we are not dependent on ruleset
1819 * order. If the game isn't started improvements aren't loaded so we can
1820 * not save the order. */
1821 secfile_insert_int(saving
->file
, improvement_count(),
1822 "savefile.improvement_size");
1823 if (improvement_count() > 0) {
1824 const char* buf
[improvement_count()];
1826 improvement_iterate(pimprove
) {
1827 buf
[improvement_index(pimprove
)] = improvement_rule_name(pimprove
);
1828 } improvement_iterate_end
;
1830 secfile_insert_str_vec(saving
->file
, buf
, improvement_count(),
1831 "savefile.improvement_vector");
1834 /* Save technology order in savegame, so we are not dependent on ruleset
1835 * order. If the game isn't started advances aren't loaded so we can not
1836 * save the order. */
1837 secfile_insert_int(saving
->file
, game
.control
.num_tech_types
,
1838 "savefile.technology_size");
1839 if (game
.control
.num_tech_types
> 0) {
1840 const char* buf
[game
.control
.num_tech_types
];
1842 buf
[A_NONE
] = "A_NONE";
1843 advance_iterate(A_FIRST
, a
) {
1844 buf
[advance_index(a
)] = advance_rule_name(a
);
1845 } advance_iterate_end
;
1846 secfile_insert_str_vec(saving
->file
, buf
, game
.control
.num_tech_types
,
1847 "savefile.technology_vector");
1850 /* Save activities order in the savegame. */
1851 secfile_insert_int(saving
->file
, ACTIVITY_LAST
,
1852 "savefile.activities_size");
1853 if (ACTIVITY_LAST
> 0) {
1854 const char **modname
;
1858 modname
= fc_calloc(ACTIVITY_LAST
, sizeof(*modname
));
1860 for (j
= 0; j
< ACTIVITY_LAST
; j
++) {
1861 modname
[i
++] = unit_activity_name(j
);
1864 secfile_insert_str_vec(saving
->file
, modname
,
1866 "savefile.activities_vector");
1870 /* Save trait order in savegame. */
1871 secfile_insert_int(saving
->file
, TRAIT_COUNT
,
1872 "savefile.trait_size");
1874 const char **modname
;
1878 modname
= fc_calloc(TRAIT_COUNT
, sizeof(*modname
));
1880 for (tr
= trait_begin(), j
= 0; tr
!= trait_end(); tr
= trait_next(tr
), j
++) {
1881 modname
[j
] = trait_name(tr
);
1884 secfile_insert_str_vec(saving
->file
, modname
, TRAIT_COUNT
,
1885 "savefile.trait_vector");
1889 /* Save specials order in savegame. */
1890 secfile_insert_int(saving
->file
, S_LAST
, "savefile.specials_size");
1892 const char **modname
;
1894 modname
= fc_calloc(S_LAST
, sizeof(*modname
));
1895 tile_special_type_iterate(j
) {
1896 modname
[j
] = special_rule_name(j
);
1897 } tile_special_type_iterate_end
;
1899 secfile_insert_str_vec(saving
->file
, modname
, S_LAST
,
1900 "savefile.specials_vector");
1904 /* Save bases order in the savegame. */
1905 secfile_insert_int(saving
->file
, game
.control
.num_base_types
,
1906 "savefile.bases_size");
1907 if (game
.control
.num_base_types
> 0) {
1908 const char **modname
;
1911 modname
= fc_calloc(game
.control
.num_base_types
, sizeof(*modname
));
1913 base_type_iterate(pbase
) {
1914 modname
[i
++] = base_rule_name(pbase
);
1915 } base_type_iterate_end
;
1917 secfile_insert_str_vec(saving
->file
, modname
,
1918 game
.control
.num_base_types
,
1919 "savefile.bases_vector");
1923 /* Save roads order in the savegame. */
1924 secfile_insert_int(saving
->file
, game
.control
.num_road_types
,
1925 "savefile.roads_size");
1926 if (game
.control
.num_road_types
> 0) {
1927 const char **modname
;
1930 modname
= fc_calloc(game
.control
.num_road_types
, sizeof(*modname
));
1932 road_type_iterate(proad
) {
1933 modname
[i
++] = road_rule_name(proad
);
1934 } road_type_iterate_end
;
1936 secfile_insert_str_vec(saving
->file
, modname
,
1937 game
.control
.num_road_types
,
1938 "savefile.roads_vector");
1943 /****************************************************************************
1944 Save options for this savegame. sg_load_savefile_options() is not defined.
1945 ****************************************************************************/
1946 static void sg_save_savefile_options(struct savedata
*saving
,
1949 /* Check status and return if not OK (sg_success != TRUE). */
1952 if (option
== NULL
) {
1953 /* no additional option */
1957 sz_strlcat(saving
->secfile_options
, option
);
1958 secfile_replace_str(saving
->file
, saving
->secfile_options
,
1959 "savefile.options");
1962 /* =======================================================================
1963 * Load / save game status.
1964 * ======================================================================= */
1966 /****************************************************************************
1968 ****************************************************************************/
1969 static void sg_load_game(struct loaddata
*loading
)
1974 /* Check status and return if not OK (sg_success != TRUE). */
1979 = secfile_lookup_int_default(loading
->file
, 0, "game.version");
1980 /* We require at least version 2.2.99 */
1981 sg_failure_ret(20299 <= game_version
, "Saved game is too old, at least "
1982 "version 2.2.99 required.");
1984 /* Load server state. */
1985 string
= secfile_lookup_str_default(loading
->file
, "S_S_INITIAL",
1986 "game.server_state");
1987 loading
->server_state
= server_states_by_name(string
, strcmp
);
1988 if (!server_states_is_valid(loading
->server_state
)) {
1989 /* Don't take any risk! */
1990 loading
->server_state
= S_S_INITIAL
;
1993 string
= secfile_lookup_str_default(loading
->file
,
1994 default_meta_patches_string(),
1995 "game.meta_patches");
1996 set_meta_patches_string(string
);
1997 game
.server
.meta_info
.user_message_set
1998 = secfile_lookup_bool_default(loading
->file
, FALSE
,
1999 "game.meta_usermessage");
2000 if (game
.server
.meta_info
.user_message_set
) {
2001 string
= secfile_lookup_str_default(loading
->file
,
2002 default_meta_message_string(),
2003 "game.meta_message");
2004 set_user_meta_message_string(string
);
2007 if (0 == strcmp(DEFAULT_META_SERVER_ADDR
, srvarg
.metaserver_addr
)) {
2008 /* Do not overwrite this if the user requested a specific metaserver
2009 * from the command line (option --Metaserver). */
2010 sz_strlcpy(srvarg
.metaserver_addr
,
2011 secfile_lookup_str_default(loading
->file
,
2012 DEFAULT_META_SERVER_ADDR
,
2013 "game.meta_server"));
2016 if ('\0' == srvarg
.serverid
[0]) {
2017 /* Do not overwrite this if the user requested a specific metaserver
2018 * from the command line (option --serverid). */
2019 sz_strlcpy(srvarg
.serverid
,
2020 secfile_lookup_str_default(loading
->file
, "",
2023 sz_strlcpy(server
.game_identifier
,
2024 secfile_lookup_str_default(loading
->file
, "", "game.id"));
2025 /* We are not checking game_identifier legality just yet.
2026 * That's done when we are sure that rand seed has been initialized,
2027 * so that we can generate new game_identifier, if needed.
2028 * See sq_load_sanitycheck(). */
2030 game
.info
.skill_level
2031 = secfile_lookup_int_default(loading
->file
, GAME_DEFAULT_SKILL_LEVEL
,
2032 "game.skill_level");
2033 game
.info
.phase_mode
2034 = secfile_lookup_int_default(loading
->file
, GAME_DEFAULT_PHASE_MODE
,
2036 game
.server
.phase_mode_stored
2037 = secfile_lookup_int_default(loading
->file
, GAME_DEFAULT_PHASE_MODE
,
2038 "game.phase_mode_stored");
2040 = secfile_lookup_int_default(loading
->file
, 0,
2042 game
.server
.scoreturn
2043 = secfile_lookup_int_default(loading
->file
,
2044 game
.info
.turn
+ GAME_DEFAULT_SCORETURN
,
2047 game
.server
.timeoutint
2048 = secfile_lookup_int_default(loading
->file
, GAME_DEFAULT_TIMEOUTINT
,
2050 game
.server
.timeoutintinc
2051 = secfile_lookup_int_default(loading
->file
, GAME_DEFAULT_TIMEOUTINTINC
,
2052 "game.timeoutintinc");
2053 game
.server
.timeoutinc
2054 = secfile_lookup_int_default(loading
->file
, GAME_DEFAULT_TIMEOUTINC
,
2056 game
.server
.timeoutincmult
2057 = secfile_lookup_int_default(loading
->file
, GAME_DEFAULT_TIMEOUTINCMULT
,
2058 "game.timeoutincmult");
2059 game
.server
.timeoutcounter
2060 = secfile_lookup_int_default(loading
->file
, GAME_DEFAULT_TIMEOUTCOUNTER
,
2061 "game.timeoutcounter");
2064 = secfile_lookup_int_default(loading
->file
, 0, "game.turn");
2065 sg_failure_ret(secfile_lookup_int(loading
->file
, &game
.info
.year
,
2066 "game.year"), "%s", secfile_error());
2067 game
.info
.year_0_hack
2068 = secfile_lookup_bool_default(loading
->file
, FALSE
, "game.year_0_hack");
2070 game
.info
.globalwarming
2071 = secfile_lookup_int_default(loading
->file
, 0, "game.globalwarming");
2073 = secfile_lookup_int_default(loading
->file
, 0, "game.heating");
2074 game
.info
.warminglevel
2075 = secfile_lookup_int_default(loading
->file
, 0, "game.warminglevel");
2077 game
.info
.nuclearwinter
2078 = secfile_lookup_int_default(loading
->file
, 0, "game.nuclearwinter");
2080 = secfile_lookup_int_default(loading
->file
, 0, "game.cooling");
2081 game
.info
.coolinglevel
2082 = secfile_lookup_int_default(loading
->file
, 0, "game.coolinglevel");
2084 game
.info
.is_new_game
2085 = !secfile_lookup_bool_default(loading
->file
, TRUE
, "game.save_players");
2088 /****************************************************************************
2090 ****************************************************************************/
2091 static void sg_save_game(struct savedata
*saving
)
2094 const char *user_message
;
2095 enum server_states srv_state
;
2097 /* Check status and return if not OK (sg_success != TRUE). */
2100 game_version
= MAJOR_VERSION
*10000 + MINOR_VERSION
*100 + PATCH_VERSION
;
2101 secfile_insert_int(saving
->file
, game_version
, "game.version");
2103 /* Game state: once the game is no longer a new game (ie, has been
2104 * started the first time), it should always be considered a running
2105 * game for savegame purposes. */
2106 if (saving
->scenario
&& !game
.scenario
.players
) {
2107 srv_state
= S_S_INITIAL
;
2109 srv_state
= game
.info
.is_new_game
? server_state() : S_S_RUNNING
;
2111 secfile_insert_str(saving
->file
, server_states_name(srv_state
),
2112 "game.server_state");
2114 secfile_insert_str(saving
->file
, get_meta_patches_string(),
2115 "game.meta_patches");
2116 secfile_insert_bool(saving
->file
, game
.server
.meta_info
.user_message_set
,
2117 "game.meta_usermessage");
2118 user_message
= get_user_meta_message_string();
2119 if (user_message
!= NULL
) {
2120 secfile_insert_str(saving
->file
, user_message
, "game.meta_message");
2122 secfile_insert_str(saving
->file
, meta_addr_port(), "game.meta_server");
2124 secfile_insert_str(saving
->file
, server
.game_identifier
, "game.id");
2125 secfile_insert_str(saving
->file
, srvarg
.serverid
, "game.serverid");
2127 secfile_insert_int(saving
->file
, game
.info
.skill_level
,
2128 "game.skill_level");
2129 secfile_insert_int(saving
->file
, game
.info
.phase_mode
,
2131 secfile_insert_int(saving
->file
, game
.server
.phase_mode_stored
,
2132 "game.phase_mode_stored");
2133 secfile_insert_int(saving
->file
, game
.info
.phase
,
2135 secfile_insert_int(saving
->file
, game
.server
.scoreturn
,
2138 secfile_insert_int(saving
->file
, game
.server
.timeoutint
,
2140 secfile_insert_int(saving
->file
, game
.server
.timeoutintinc
,
2141 "game.timeoutintinc");
2142 secfile_insert_int(saving
->file
, game
.server
.timeoutinc
,
2144 secfile_insert_int(saving
->file
, game
.server
.timeoutincmult
,
2145 "game.timeoutincmult");
2146 secfile_insert_int(saving
->file
, game
.server
.timeoutcounter
,
2147 "game.timeoutcounter");
2149 secfile_insert_int(saving
->file
, game
.info
.turn
, "game.turn");
2150 secfile_insert_int(saving
->file
, game
.info
.year
, "game.year");
2151 secfile_insert_bool(saving
->file
, game
.info
.year_0_hack
,
2152 "game.year_0_hack");
2154 secfile_insert_int(saving
->file
, game
.info
.globalwarming
,
2155 "game.globalwarming");
2156 secfile_insert_int(saving
->file
, game
.info
.heating
,
2158 secfile_insert_int(saving
->file
, game
.info
.warminglevel
,
2159 "game.warminglevel");
2161 secfile_insert_int(saving
->file
, game
.info
.nuclearwinter
,
2162 "game.nuclearwinter");
2163 secfile_insert_int(saving
->file
, game
.info
.cooling
,
2165 secfile_insert_int(saving
->file
, game
.info
.coolinglevel
,
2166 "game.coolinglevel");
2168 if (!game_was_started()) {
2169 saving
->save_players
= FALSE
;
2170 } else if (saving
->scenario
) {
2171 saving
->save_players
= game
.scenario
.players
;
2173 saving
->save_players
= TRUE
;
2175 secfile_insert_bool(saving
->file
, saving
->save_players
,
2176 "game.save_players");
2179 /* =======================================================================
2180 * Load / save random status.
2181 * ======================================================================= */
2183 /****************************************************************************
2185 ****************************************************************************/
2186 static void sg_load_random(struct loaddata
*loading
)
2188 /* Check status and return if not OK (sg_success != TRUE). */
2191 if (secfile_lookup_bool_default(loading
->file
, FALSE
, "random.save")) {
2195 sg_failure_ret(secfile_lookup_int(loading
->file
, &loading
->rstate
.j
,
2196 "random.index_J"), "%s", secfile_error());
2197 sg_failure_ret(secfile_lookup_int(loading
->file
, &loading
->rstate
.k
,
2198 "random.index_K"), "%s", secfile_error());
2199 sg_failure_ret(secfile_lookup_int(loading
->file
, &loading
->rstate
.x
,
2200 "random.index_X"), "%s", secfile_error());
2202 for (i
= 0; i
< 8; i
++) {
2203 string
= secfile_lookup_str(loading
->file
, "random.table%d",i
);
2204 sg_failure_ret(NULL
!= string
, "%s", secfile_error());
2205 sscanf(string
, "%8x %8x %8x %8x %8x %8x %8x", &loading
->rstate
.v
[7*i
],
2206 &loading
->rstate
.v
[7*i
+1], &loading
->rstate
.v
[7*i
+2],
2207 &loading
->rstate
.v
[7*i
+3], &loading
->rstate
.v
[7*i
+4],
2208 &loading
->rstate
.v
[7*i
+5], &loading
->rstate
.v
[7*i
+6]);
2210 loading
->rstate
.is_init
= TRUE
;
2211 fc_rand_set_state(loading
->rstate
);
2213 /* No random values - mark the setting. */
2214 (void) secfile_entry_by_path(loading
->file
, "random.save");
2216 /* We're loading a game without a seed (which is okay, if it's a scenario).
2217 * We need to generate the game seed now because it will be needed later
2218 * during the load. */
2220 loading
->rstate
= fc_rand_state();
2224 /****************************************************************************
2226 ****************************************************************************/
2227 static void sg_save_random(struct savedata
*saving
)
2229 /* Check status and return if not OK (sg_success != TRUE). */
2232 if (fc_rand_is_init() && game
.server
.save_options
.save_random
) {
2234 RANDOM_STATE rstate
= fc_rand_state();
2236 secfile_insert_bool(saving
->file
, TRUE
, "random.save");
2237 fc_assert(rstate
.is_init
);
2239 secfile_insert_int(saving
->file
, rstate
.j
, "random.index_J");
2240 secfile_insert_int(saving
->file
, rstate
.k
, "random.index_K");
2241 secfile_insert_int(saving
->file
, rstate
.x
, "random.index_X");
2243 for (i
= 0; i
< 8; i
++) {
2246 fc_snprintf(vec
, sizeof(vec
),
2247 "%8x %8x %8x %8x %8x %8x %8x", rstate
.v
[7 * i
],
2248 rstate
.v
[7 * i
+ 1], rstate
.v
[7 * i
+ 2],
2249 rstate
.v
[7 * i
+ 3], rstate
.v
[7 * i
+ 4],
2250 rstate
.v
[7 * i
+ 5], rstate
.v
[7 * i
+ 6]);
2251 secfile_insert_str(saving
->file
, vec
, "random.table%d", i
);
2254 secfile_insert_bool(saving
->file
, FALSE
, "random.save");
2258 /* =======================================================================
2259 * Load / save lua script data.
2260 * ======================================================================= */
2262 /****************************************************************************
2264 ****************************************************************************/
2265 static void sg_load_script(struct loaddata
*loading
)
2267 /* Check status and return if not OK (sg_success != TRUE). */
2270 script_server_state_load(loading
->file
);
2273 /****************************************************************************
2275 ****************************************************************************/
2276 static void sg_save_script(struct savedata
*saving
)
2278 /* Check status and return if not OK (sg_success != TRUE). */
2281 script_server_state_save(saving
->file
);
2284 /* =======================================================================
2285 * Load / save scenario data.
2286 * ======================================================================= */
2288 /****************************************************************************
2290 ****************************************************************************/
2291 static void sg_load_scenario(struct loaddata
*loading
)
2295 /* Check status and return if not OK (sg_success != TRUE). */
2298 if (NULL
== secfile_section_lookup(loading
->file
, "scenario")) {
2299 /* Nothing to do. */
2303 /* Default is that when there's scenario section (which we already checked)
2304 * this is a scenario. Only if it explicitly says that it's not, we consider
2305 * this regular savegame */
2306 if (!secfile_lookup_bool_default(loading
->file
, TRUE
, "scenario.is_scenario")) {
2310 buf
= secfile_lookup_str_default(loading
->file
, "", "scenario.name");
2311 if (buf
[0] != '\0') {
2312 game
.scenario
.is_scenario
= TRUE
;
2313 sz_strlcpy(game
.scenario
.name
, buf
);
2314 buf
= secfile_lookup_str_default(loading
->file
, "",
2315 "scenario.description");
2316 if (buf
[0] != '\0') {
2317 sz_strlcpy(game
.scenario
.description
, buf
);
2319 game
.scenario
.description
[0] = '\0';
2321 game
.scenario
.players
2322 = secfile_lookup_bool_default(loading
->file
, TRUE
, "scenario.players");
2323 game
.scenario
.startpos_nations
2324 = secfile_lookup_bool_default(loading
->file
, FALSE
,
2325 "scenario.startpos_nations");
2327 sg_failure_ret(loading
->server_state
== S_S_INITIAL
2328 || (loading
->server_state
== S_S_RUNNING
2329 && game
.scenario
.players
== TRUE
),
2330 "Invalid scenario definition (server state '%s' and "
2332 server_states_name(loading
->server_state
),
2333 game
.scenario
.players
? "saved" : "not saved");
2335 game
.scenario
.is_scenario
= FALSE
;
2338 if (game
.scenario
.is_scenario
) {
2339 /* Remove all defined players. They are recreated with the skill level
2340 * defined by the scenario. */
2345 /****************************************************************************
2347 ****************************************************************************/
2348 static void sg_save_scenario(struct savedata
*saving
)
2350 /* Check status and return if not OK (sg_success != TRUE). */
2353 if (!saving
->scenario
|| !game
.scenario
.is_scenario
) {
2354 secfile_insert_bool(saving
->file
, FALSE
, "scenario.is_scenario");
2358 secfile_insert_bool(saving
->file
, TRUE
, "scenario.is_scenario");
2359 secfile_insert_str(saving
->file
, game
.scenario
.name
, "scenario.name");
2360 secfile_insert_str(saving
->file
, game
.scenario
.description
,
2361 "scenario.description");
2362 secfile_insert_bool(saving
->file
, game
.scenario
.players
, "scenario.players");
2363 secfile_insert_bool(saving
->file
, game
.scenario
.startpos_nations
,
2364 "scenario.startpos_nations");
2367 /* =======================================================================
2368 * Load / save game settings.
2369 * ======================================================================= */
2371 /****************************************************************************
2373 ****************************************************************************/
2374 static void sg_load_settings(struct loaddata
*loading
)
2376 /* Check status and return if not OK (sg_success != TRUE). */
2379 settings_game_load(loading
->file
, "settings");
2381 /* Save current status of fogofwar. */
2382 game
.server
.fogofwar_old
= game
.info
.fogofwar
;
2384 /* Add all compatibility settings here. */
2387 /****************************************************************************
2389 ****************************************************************************/
2390 static void sg_save_settings(struct savedata
*saving
)
2392 enum map_generator real_generator
= map
.server
.generator
;
2394 /* Check status and return if not OK (sg_success != TRUE). */
2397 if (saving
->scenario
) {
2398 map
.server
.generator
= MAPGEN_SCENARIO
; /* We want a scenario. */
2400 settings_game_save(saving
->file
, "settings");
2401 /* Restore real map generator. */
2402 map
.server
.generator
= real_generator
;
2404 /* Add all compatibility settings here. */
2407 /* =======================================================================
2408 * Load / save the main map.
2409 * ======================================================================= */
2411 /****************************************************************************
2413 ****************************************************************************/
2414 static void sg_load_map(struct loaddata
*loading
)
2416 /* Check status and return if not OK (sg_success != TRUE). */
2419 map
.server
.have_huts
2420 = secfile_lookup_bool_default(loading
->file
, TRUE
, "map.have_huts");
2422 if (S_S_INITIAL
== loading
->server_state
2423 && MAPGEN_SCENARIO
== map
.server
.generator
) {
2424 /* Generator MAPGEN_SCENARIO is used;
2425 * this map was done with the map editor. */
2428 sg_load_map_tiles(loading
);
2429 sg_load_map_startpos(loading
);
2430 sg_load_map_tiles_bases(loading
);
2431 if (loading
->version
>= 20) {
2432 /* 2.5.0 or newer */
2433 sg_load_map_tiles_roads(loading
);
2435 if (has_capability("specials", loading
->secfile_options
)) {
2436 /* Load specials and resources. */
2437 sg_load_map_tiles_specials(loading
, FALSE
);
2438 sg_load_map_tiles_resources(loading
);
2439 } else if (has_capability("riversoverlay", loading
->secfile_options
)) {
2440 /* Load only rivers overlay. */
2441 struct road_type
*priver
;
2443 sg_load_map_tiles_specials(loading
, TRUE
);
2444 priver
= road_by_compat_special(ROCO_RIVER
);
2445 if (priver
== NULL
) {
2446 /* They are still as river specials */
2447 map
.server
.have_rivers_overlay
= TRUE
;
2451 /* Nothing more needed for a scenario. */
2455 if (S_S_INITIAL
== loading
->server_state
) {
2456 /* Nothing more to do if it is not a scenario but in initial state. */
2460 sg_load_map_tiles(loading
);
2461 sg_load_map_startpos(loading
);
2462 sg_load_map_tiles_bases(loading
);
2463 if (loading
->version
>= 20) {
2464 /* 2.5.0 or newer */
2465 sg_load_map_tiles_roads(loading
);
2467 sg_load_map_tiles_specials(loading
, FALSE
);
2468 sg_load_map_tiles_resources(loading
);
2469 sg_load_map_known(loading
);
2470 sg_load_map_owner(loading
);
2471 sg_load_map_worked(loading
);
2474 /****************************************************************************
2476 ****************************************************************************/
2477 static void sg_save_map(struct savedata
*saving
)
2479 /* Check status and return if not OK (sg_success != TRUE). */
2482 secfile_insert_bool(saving
->file
, map
.server
.have_huts
, "map.have_huts");
2484 if (map_is_empty()) {
2489 sg_save_map_tiles(saving
);
2490 sg_save_map_startpos(saving
);
2491 sg_save_map_tiles_bases(saving
);
2492 sg_save_map_tiles_roads(saving
);
2493 if (!map
.server
.have_resources
) {
2494 if (map
.server
.have_rivers_overlay
) {
2495 /* Save the rivers overlay map; this is a special case to allow
2496 * re-saving scenarios which have rivers overlay data. This only
2497 * applies if you don't have the rest of the specials. */
2498 sg_save_savefile_options(saving
, " riversoverlay");
2499 sg_save_map_tiles_specials(saving
, TRUE
);
2502 sg_save_savefile_options(saving
, " specials");
2503 sg_save_map_tiles_specials(saving
, FALSE
);
2504 sg_save_map_tiles_resources(saving
);
2507 sg_save_map_owner(saving
);
2508 sg_save_map_worked(saving
);
2509 sg_save_map_known(saving
);
2512 /****************************************************************************
2514 ****************************************************************************/
2515 static void sg_load_map_tiles(struct loaddata
*loading
)
2517 /* Check status and return if not OK (sg_success != TRUE). */
2520 /* Initialize the map for the current topology. 'map.xsize' and
2521 * 'map.ysize' must be set. */
2522 map_init_topology();
2527 /* get the terrain type */
2528 LOAD_MAP_CHAR(ch
, ptile
, ptile
->terrain
= char2terrain(ch
), loading
->file
,
2530 assign_continent_numbers();
2532 /* Check for special tile sprites. */
2533 whole_map_iterate(ptile
) {
2534 const char *spec_sprite
;
2538 index_to_native_pos(&nat_x
, &nat_y
, tile_index(ptile
));
2539 spec_sprite
= secfile_lookup_str(loading
->file
, "map.spec_sprite_%d_%d",
2541 label
= secfile_lookup_str_default(loading
->file
, NULL
, "map.label_%d_%d",
2543 if (NULL
!= ptile
->spec_sprite
) {
2544 ptile
->spec_sprite
= fc_strdup(spec_sprite
);
2546 if (label
!= NULL
) {
2547 tile_set_label(ptile
, label
);
2549 } whole_map_iterate_end
;
2552 /****************************************************************************
2554 ****************************************************************************/
2555 static void sg_save_map_tiles(struct savedata
*saving
)
2557 /* Check status and return if not OK (sg_success != TRUE). */
2560 /* Save the terrain type. */
2561 SAVE_MAP_CHAR(ptile
, terrain2char(ptile
->terrain
), saving
->file
,
2564 /* Save special tile sprites. */
2565 whole_map_iterate(ptile
) {
2568 index_to_native_pos(&nat_x
, &nat_y
, tile_index(ptile
));
2569 if (ptile
->spec_sprite
) {
2570 secfile_insert_str(saving
->file
, ptile
->spec_sprite
,
2571 "map.spec_sprite_%d_%d", nat_x
, nat_y
);
2573 if (ptile
->label
!= NULL
) {
2574 secfile_insert_str(saving
->file
, ptile
->label
,
2575 "map.label_%d_%d", nat_x
, nat_y
);
2577 } whole_map_iterate_end
;
2580 /****************************************************************************
2582 ****************************************************************************/
2583 static void sg_load_map_tiles_bases(struct loaddata
*loading
)
2585 /* Check status and return if not OK (sg_success != TRUE). */
2589 halfbyte_iterate_bases(j
, loading
->base
.size
) {
2590 LOAD_MAP_CHAR(ch
, ptile
, sg_bases_set(&ptile
->bases
, ch
,
2591 loading
->base
.order
+ 4 * j
),
2592 loading
->file
, "map.b%02d_%04d", j
);
2593 } halfbyte_iterate_bases_end
;
2596 /****************************************************************************
2597 Save information about bases on map
2598 ****************************************************************************/
2599 static void sg_save_map_tiles_bases(struct savedata
*saving
)
2601 /* Check status and return if not OK (sg_success != TRUE). */
2605 halfbyte_iterate_bases(j
, game
.control
.num_base_types
) {
2609 for (l
= 0; l
< 4; l
++) {
2610 if (4 * j
+ 1 > game
.control
.num_base_types
) {
2616 SAVE_MAP_CHAR(ptile
, sg_bases_get(ptile
->bases
, mod
), saving
->file
,
2617 "map.b%02d_%04d", j
);
2618 } halfbyte_iterate_bases_end
;
2621 /****************************************************************************
2623 ****************************************************************************/
2624 static void sg_load_map_tiles_roads(struct loaddata
*loading
)
2626 /* Check status and return if not OK (sg_success != TRUE). */
2630 halfbyte_iterate_roads(j
, loading
->road
.size
) {
2631 LOAD_MAP_CHAR(ch
, ptile
, sg_roads_set(&ptile
->roads
, ch
,
2632 loading
->road
.order
+ 4 * j
),
2633 loading
->file
, "map.r%02d_%04d", j
);
2634 } halfbyte_iterate_roads_end
;
2637 /****************************************************************************
2638 Save information about roads on map
2639 ****************************************************************************/
2640 static void sg_save_map_tiles_roads(struct savedata
*saving
)
2642 /* Check status and return if not OK (sg_success != TRUE). */
2646 halfbyte_iterate_roads(j
, game
.control
.num_road_types
) {
2650 for (l
= 0; l
< 4; l
++) {
2651 if (4 * j
+ 1 > game
.control
.num_road_types
) {
2657 SAVE_MAP_CHAR(ptile
, sg_roads_get(ptile
->roads
, mod
), saving
->file
,
2658 "map.r%02d_%04d", j
);
2659 } halfbyte_iterate_roads_end
;
2662 /****************************************************************************
2663 Load information about specials on map
2664 ****************************************************************************/
2665 static void sg_load_map_tiles_specials(struct loaddata
*loading
,
2666 bool rivers_overlay
)
2668 /* Check status and return if not OK (sg_success != TRUE). */
2671 /* If 'rivers_overlay' is set to TRUE, load only the rivers overlay map
2672 * from the savegame file.
2674 * A scenario may define the terrain of the map but not list the specials
2675 * on it (thus allowing users to control the placement of specials).
2676 * However rivers are a special case and must be included in the map along
2677 * with the scenario. Thus in those cases this function should be called
2678 * to load the river information separate from any other special data.
2680 * This does not need to be called from map_load(), because map_load()
2681 * loads the rivers overlay along with the rest of the specials. Call this
2682 * only if you've already called map_load_tiles(), and want to load only
2683 * the rivers overlay but no other specials. Scenarios that encode things
2684 * this way should have the "riversoverlay" capability. */
2685 halfbyte_iterate_special(j
, loading
->special
.size
) {
2686 LOAD_MAP_CHAR(ch
, ptile
, sg_special_set(&ptile
->special
, &ptile
->roads
, ch
,
2687 loading
->special
.order
+ 4 * j
,
2689 loading
->file
, "map.spe%02d_%04d", j
);
2690 } halfbyte_iterate_special_end
;
2693 /****************************************************************************
2694 Save information about specials on map.
2695 ****************************************************************************/
2696 static void sg_save_map_tiles_specials(struct savedata
*saving
,
2697 bool rivers_overlay
)
2699 /* Check status and return if not OK (sg_success != TRUE). */
2702 halfbyte_iterate_special(j
, S_LAST
) {
2703 enum tile_special_type mod
[4];
2706 for (l
= 0; l
< 4; l
++) {
2707 if (rivers_overlay
) {
2708 /* Save only rivers overlay. */
2709 mod
[l
] = (4 * j
+ l
== S_OLD_RIVER
) ? S_OLD_RIVER
: S_LAST
;
2711 /* Save all specials. */
2712 mod
[l
] = MIN(4 * j
+ l
, S_LAST
);
2715 SAVE_MAP_CHAR(ptile
, sg_special_get(ptile
->special
, mod
), saving
->file
,
2716 "map.spe%02d_%04d", j
);
2717 } halfbyte_iterate_special_end
;
2720 /****************************************************************************
2721 Load information about resources on map.
2722 ****************************************************************************/
2723 static void sg_load_map_tiles_resources(struct loaddata
*loading
)
2725 /* Check status and return if not OK (sg_success != TRUE). */
2728 LOAD_MAP_CHAR(ch
, ptile
, ptile
->resource
= char2resource(ch
),
2729 loading
->file
, "map.res%04d");
2731 /* After the resources are loaded, indicate those currently valid. */
2732 whole_map_iterate(ptile
) {
2733 if (NULL
== ptile
->resource
|| NULL
== ptile
->terrain
) {
2737 if (terrain_has_resource(ptile
->terrain
, ptile
->resource
)) {
2738 /* cannot use set_special() for internal values */
2739 BV_SET(ptile
->special
, S_RESOURCE_VALID
);
2741 } whole_map_iterate_end
;
2743 map
.server
.have_resources
= TRUE
;
2746 /****************************************************************************
2747 Load information about resources on map.
2748 ****************************************************************************/
2749 static void sg_save_map_tiles_resources(struct savedata
*saving
)
2751 /* Check status and return if not OK (sg_success != TRUE). */
2754 SAVE_MAP_CHAR(ptile
, resource2char(ptile
->resource
), saving
->file
,
2758 /****************************************************************************
2759 Load starting positions for the players from a savegame file. There should
2760 be at least enough for every player.
2761 ****************************************************************************/
2762 static void sg_load_map_startpos(struct loaddata
*loading
)
2764 struct nation_type
*pnation
;
2765 struct startpos
*psp
;
2767 const char SEPARATOR
= '#';
2768 const char *nation_names
;
2771 int i
, startpos_count
;
2773 /* Check status and return if not OK (sg_success != TRUE). */
2777 = secfile_lookup_int_default(loading
->file
, 0, "map.startpos_count");
2779 if (0 == startpos_count
) {
2780 /* Nothing to do. */
2784 for (i
= 0; i
< startpos_count
; i
++) {
2785 if (!secfile_lookup_int(loading
->file
, &nat_x
, "map.startpos%d.x", i
)
2786 || !secfile_lookup_int(loading
->file
, &nat_y
,
2787 "map.startpos%d.y", i
)) {
2788 log_sg("Warning: Undefined coordinates for startpos %d", i
);
2792 ptile
= native_pos_to_tile(nat_x
, nat_y
);
2793 if (NULL
== ptile
) {
2794 log_error("Start position native coordinates (%d, %d) do not exist "
2795 "in this map. Skipping...", nat_x
, nat_y
);
2799 exclude
= secfile_lookup_bool_default(loading
->file
, FALSE
,
2800 "map.startpos%d.exclude", i
);
2802 psp
= map_startpos_new(ptile
);
2804 nation_names
= secfile_lookup_str(loading
->file
,
2805 "map.startpos%d.nations", i
);
2806 if (NULL
!= nation_names
&& '\0' != nation_names
[0]) {
2807 const size_t size
= strlen(nation_names
) + 1;
2808 char buf
[size
], *start
, *end
;
2810 memcpy(buf
, nation_names
, size
);
2811 for (start
= buf
- 1; NULL
!= start
; start
= end
) {
2813 if ((end
= strchr(start
, SEPARATOR
))) {
2817 pnation
= nation_by_rule_name(start
);
2818 if (NO_NATION_SELECTED
!= pnation
) {
2820 startpos_disallow(psp
, pnation
);
2822 startpos_allow(psp
, pnation
);
2825 log_verbose("Missing nation \"%s\".", start
);
2831 if (0 < map_startpos_count()
2832 && loading
->server_state
== S_S_INITIAL
2833 && map_startpos_count() < game
.server
.max_players
) {
2834 log_verbose("Number of starts (%d) are lower than rules.max_players "
2835 "(%d), lowering rules.max_players.",
2836 map_startpos_count(), game
.server
.max_players
);
2837 game
.server
.max_players
= map_startpos_count();
2840 /* Re-initialize nation availability in light of start positions.
2841 * This has to be after loading [scenario] and [map].startpos and
2842 * before we seek nations for players. */
2843 update_nations_with_startpos();
2846 /****************************************************************************
2847 Save the map start positions.
2848 ****************************************************************************/
2849 static void sg_save_map_startpos(struct savedata
*saving
)
2852 const char SEPARATOR
= '#';
2855 /* Check status and return if not OK (sg_success != TRUE). */
2858 if (!game
.server
.save_options
.save_starts
) {
2862 secfile_insert_int(saving
->file
, map_startpos_count(),
2863 "map.startpos_count");
2865 map_startpos_iterate(psp
) {
2868 ptile
= startpos_tile(psp
);
2870 index_to_native_pos(&nat_x
, &nat_y
, tile_index(ptile
));
2871 secfile_insert_int(saving
->file
, nat_x
, "map.startpos%d.x", i
);
2872 secfile_insert_int(saving
->file
, nat_y
, "map.startpos%d.y", i
);
2874 secfile_insert_bool(saving
->file
, startpos_is_excluding(psp
),
2875 "map.startpos%d.exclude", i
);
2876 if (startpos_allows_all(psp
)) {
2877 secfile_insert_str(saving
->file
, "", "map.startpos%d.nations", i
);
2879 const struct nation_hash
*nations
= startpos_raw_nations(psp
);
2880 char nation_names
[MAX_LEN_NAME
* nation_hash_size(nations
)];
2882 nation_names
[0] = '\0';
2883 nation_hash_iterate(nations
, pnation
) {
2884 if ('\0' == nation_names
[0]) {
2885 fc_strlcpy(nation_names
, nation_rule_name(pnation
),
2886 sizeof(nation_names
));
2888 cat_snprintf(nation_names
, sizeof(nation_names
),
2889 "%c%s", SEPARATOR
, nation_rule_name(pnation
));
2891 } nation_hash_iterate_end
;
2892 secfile_insert_str(saving
->file
, nation_names
,
2893 "map.startpos%d.nations", i
);
2896 } map_startpos_iterate_end
;
2898 fc_assert(map_startpos_count() == i
);
2901 /****************************************************************************
2902 Load tile owner information
2903 ****************************************************************************/
2904 static void sg_load_map_owner(struct loaddata
*loading
)
2907 struct player
*owner
= NULL
;
2908 struct tile
*claimer
= NULL
;
2910 /* Check status and return if not OK (sg_success != TRUE). */
2913 if (game
.info
.is_new_game
) {
2914 /* No owner/source information for a new game / scenario. */
2918 /* Owner and ownership source are stored as plain numbers */
2919 for (y
= 0; y
< map
.ysize
; y
++) {
2920 const char *buffer1
= secfile_lookup_str(loading
->file
,
2921 "map.owner%04d", y
);
2922 const char *buffer2
= secfile_lookup_str(loading
->file
,
2923 "map.source%04d", y
);
2924 const char *ptr1
= buffer1
;
2925 const char *ptr2
= buffer2
;
2927 sg_failure_ret(buffer1
!= NULL
, "%s", secfile_error());
2928 sg_failure_ret(buffer2
!= NULL
, "%s", secfile_error());
2930 for (x
= 0; x
< map
.xsize
; x
++) {
2931 char token1
[TOKEN_SIZE
];
2932 char token2
[TOKEN_SIZE
];
2934 struct tile
*ptile
= native_pos_to_tile(x
, y
);
2936 scanin(&ptr1
, ",", token1
, sizeof(token1
));
2937 sg_failure_ret(token1
[0] != '\0',
2938 "Map size not correct (map.owner%d).", y
);
2939 if (strcmp(token1
, "-") == 0) {
2942 sg_failure_ret(str_to_int(token1
, &number
),
2943 "Got map owner %s in (%d, %d).", token1
, x
, y
);
2944 owner
= player_by_number(number
);
2947 scanin(&ptr2
, ",", token2
, sizeof(token2
));
2948 sg_failure_ret(token2
[0] != '\0',
2949 "Map size not correct (map.source%d).", y
);
2950 if (strcmp(token2
, "-") == 0) {
2953 sg_failure_ret(str_to_int(token2
, &number
),
2954 "Got map source %s in (%d, %d).", token2
, x
, y
);
2955 claimer
= index_to_tile(number
);
2958 map_claim_ownership(ptile
, owner
, claimer
);
2963 /****************************************************************************
2964 Save tile owner information
2965 ****************************************************************************/
2966 static void sg_save_map_owner(struct savedata
*saving
)
2970 /* Check status and return if not OK (sg_success != TRUE). */
2973 if (saving
->scenario
&& !saving
->save_players
) {
2974 /* Nothing to do for a scenario without saved players. */
2978 /* Store owner and ownership source as plain numbers. */
2979 for (y
= 0; y
< map
.ysize
; y
++) {
2980 char line
[map
.xsize
* TOKEN_SIZE
];
2983 for (x
= 0; x
< map
.xsize
; x
++) {
2984 char token
[TOKEN_SIZE
];
2985 struct tile
*ptile
= native_pos_to_tile(x
, y
);
2987 if (!saving
->save_players
|| tile_owner(ptile
) == NULL
) {
2990 fc_snprintf(token
, sizeof(token
), "%d",
2991 player_number(tile_owner(ptile
)));
2993 strcat(line
, token
);
2994 if (x
+ 1 < map
.xsize
) {
2998 secfile_insert_str(saving
->file
, line
, "map.owner%04d", y
);
3001 for (y
= 0; y
< map
.ysize
; y
++) {
3002 char line
[map
.xsize
* TOKEN_SIZE
];
3005 for (x
= 0; x
< map
.xsize
; x
++) {
3006 char token
[TOKEN_SIZE
];
3007 struct tile
*ptile
= native_pos_to_tile(x
, y
);
3009 if (ptile
->claimer
== NULL
) {
3012 fc_snprintf(token
, sizeof(token
), "%d", tile_index(ptile
->claimer
));
3014 strcat(line
, token
);
3015 if (x
+ 1 < map
.xsize
) {
3019 secfile_insert_str(saving
->file
, line
, "map.source%04d", y
);
3023 /****************************************************************************
3024 Save worked tiles information
3025 ****************************************************************************/
3026 static void sg_load_map_worked(struct loaddata
*loading
)
3030 /* Check status and return if not OK (sg_success != TRUE). */
3033 sg_failure_ret(loading
->worked_tiles
== NULL
,
3034 "City worked map not loaded!");
3036 loading
->worked_tiles
= fc_malloc(MAP_INDEX_SIZE
*
3037 sizeof(*loading
->worked_tiles
));
3039 for (y
= 0; y
< map
.ysize
; y
++) {
3040 const char *buffer
= secfile_lookup_str(loading
->file
, "map.worked%04d",
3042 const char *ptr
= buffer
;
3044 sg_failure_ret(NULL
!= buffer
,
3045 "Savegame corrupt - map line %d not found.", y
);
3046 for (x
= 0; x
< map
.xsize
; x
++) {
3047 char token
[TOKEN_SIZE
];
3049 struct tile
*ptile
= native_pos_to_tile(x
, y
);
3051 scanin(&ptr
, ",", token
, sizeof(token
));
3052 sg_failure_ret('\0' != token
[0],
3053 "Savegame corrupt - map size not correct.");
3054 if (strcmp(token
, "-") == 0) {
3057 sg_failure_ret(str_to_int(token
, &number
) && 0 < number
,
3058 "Savegame corrupt - got tile worked by city "
3059 "id=%s in (%d, %d).", token
, x
, y
);
3062 loading
->worked_tiles
[ptile
->index
] = number
;
3067 /****************************************************************************
3068 Save worked tiles information
3069 ****************************************************************************/
3070 static void sg_save_map_worked(struct savedata
*saving
)
3074 /* Check status and return if not OK (sg_success != TRUE). */
3077 if (saving
->scenario
&& !saving
->save_players
) {
3078 /* Nothing to do for a scenario without saved players. */
3082 /* additionally save the tiles worked by the cities */
3083 for (y
= 0; y
< map
.ysize
; y
++) {
3084 char line
[map
.xsize
* TOKEN_SIZE
];
3087 for (x
= 0; x
< map
.xsize
; x
++) {
3088 char token
[TOKEN_SIZE
];
3089 struct tile
*ptile
= native_pos_to_tile(x
, y
);
3090 struct city
*pcity
= tile_worked(ptile
);
3092 if (pcity
== NULL
) {
3095 fc_snprintf(token
, sizeof(token
), "%d", pcity
->id
);
3097 strcat(line
, token
);
3098 if (x
< map
.xsize
) {
3102 secfile_insert_str(saving
->file
, line
, "map.worked%04d", y
);
3106 /****************************************************************************
3107 Load tile known status
3108 ****************************************************************************/
3109 static void sg_load_map_known(struct loaddata
*loading
)
3111 /* Check status and return if not OK (sg_success != TRUE). */
3114 players_iterate(pplayer
) {
3115 /* Allocate player private map here; it is needed in different modules
3116 * besides this one ((i.e. sg_load_player_*()). */
3117 player_map_init(pplayer
);
3118 } players_iterate_end
;
3120 if (secfile_lookup_bool_default(loading
->file
, TRUE
,
3121 "game.save_known")) {
3122 int lines
= player_slot_max_used_number()/32 + 1, j
, p
, l
, i
;
3123 unsigned int *known
= fc_calloc(lines
* MAP_INDEX_SIZE
, sizeof(*known
));
3125 for (l
= 0; l
< lines
; l
++) {
3126 for (j
= 0; j
< 8; j
++) {
3127 for (i
= 0; i
< 4; i
++) {
3128 /* Only bother trying to load the map for this halfbyte if at least
3129 * one of the corresponding player slots is in use. */
3130 if (player_slot_is_used(player_slot_by_number(l
*32 + j
*4 + i
))) {
3131 LOAD_MAP_CHAR(ch
, ptile
,
3132 known
[l
* MAP_INDEX_SIZE
+ tile_index(ptile
)]
3133 |= ascii_hex2bin(ch
, j
),
3134 loading
->file
, "map.k%02d_%04d", l
* 8 + j
);
3141 players_iterate(pplayer
) {
3142 dbv_clr_all(&pplayer
->tile_known
);
3143 } players_iterate_end
;
3145 /* HACK: we read the known data from hex into 32-bit integers, and
3146 * now we convert it to the known tile data of each player. */
3147 whole_map_iterate(ptile
) {
3148 players_iterate(pplayer
) {
3149 p
= player_index(pplayer
);
3150 l
= player_index(pplayer
) / 32;
3152 if (known
[l
* MAP_INDEX_SIZE
+ tile_index(ptile
)] & (1u << (p
% 32))) {
3153 map_set_known(ptile
, pplayer
);
3155 } players_iterate_end
;
3156 } whole_map_iterate_end
;
3162 /****************************************************************************
3163 Save tile known status for whole map and all players
3164 ****************************************************************************/
3165 static void sg_save_map_known(struct savedata
*saving
)
3167 /* Check status and return if not OK (sg_success != TRUE). */
3170 if (!saving
->save_players
) {
3171 secfile_insert_bool(saving
->file
, FALSE
, "game.save_known");
3174 int lines
= player_slot_max_used_number()/32 + 1;
3176 secfile_insert_bool(saving
->file
, game
.server
.save_options
.save_known
,
3178 if (game
.server
.save_options
.save_known
) {
3180 unsigned int *known
= fc_calloc(lines
* MAP_INDEX_SIZE
, sizeof(*known
));
3182 /* HACK: we convert the data into a 32-bit integer, and then save it as
3185 whole_map_iterate(ptile
) {
3186 players_iterate(pplayer
) {
3187 if (map_is_known(ptile
, pplayer
)) {
3188 p
= player_index(pplayer
);
3190 known
[l
* MAP_INDEX_SIZE
+ tile_index(ptile
)]
3191 |= (1u << (p
% 32)); /* "p % 32" = "p - l * 32" */
3193 } players_iterate_end
;
3194 } whole_map_iterate_end
;
3196 for (l
= 0; l
< lines
; l
++) {
3197 for (j
= 0; j
< 8; j
++) {
3198 for (i
= 0; i
< 4; i
++) {
3199 /* Only bother saving the map for this halfbyte if at least one
3200 * of the corresponding player slots is in use */
3201 if (player_slot_is_used(player_slot_by_number(l
*32 + j
*4 + i
))) {
3202 /* put 4-bit segments of the 32-bit "known" field */
3203 SAVE_MAP_CHAR(ptile
, bin2ascii_hex(known
[l
* MAP_INDEX_SIZE
3204 + tile_index(ptile
)], j
),
3205 saving
->file
, "map.k%02d_%04d", l
* 8 + j
);
3217 /* =======================================================================
3218 * Load / save player data.
3220 * This is splitted into two parts as some data can only be loaded if the
3221 * number of players is known and the corresponding player slots are
3223 * ======================================================================= */
3225 /****************************************************************************
3226 Load '[player]' (basic data).
3227 ****************************************************************************/
3228 static void sg_load_players_basic(struct loaddata
*loading
)
3232 bool shuffle_loaded
= TRUE
;
3234 /* Check status and return if not OK (sg_success != TRUE). */
3237 if (S_S_INITIAL
== loading
->server_state
3238 || game
.info
.is_new_game
) {
3239 /* Nothing more to do. */
3243 /* Load destroyed wonders: */
3244 string
= secfile_lookup_str(loading
->file
,
3245 "players.destroyed_wonders");
3246 sg_failure_ret(string
!= NULL
, "%s", secfile_error());
3247 sg_failure_ret(strlen(string
) == loading
->improvement
.size
,
3248 "Invalid length for 'players.destroyed_wonders' "
3249 "(%lu ~= %lu)", (unsigned long) strlen(string
),
3250 (unsigned long) loading
->improvement
.size
);
3251 for (k
= 0; k
< loading
->improvement
.size
; k
++) {
3252 sg_failure_ret(string
[k
] == '1' || string
[k
] == '0',
3253 "Undefined value '%c' within "
3254 "'players.destroyed_wonders'.", string
[k
]);
3256 if (string
[k
] == '1') {
3257 struct impr_type
*pimprove
=
3258 improvement_by_rule_name(loading
->improvement
.order
[k
]);
3260 game
.info
.great_wonder_owners
[improvement_index(pimprove
)]
3266 server
.identity_number
3267 = secfile_lookup_int_default(loading
->file
, server
.identity_number
,
3268 "players.identity_number_used");
3270 /* First remove all defined players. */
3271 players_iterate(pplayer
) {
3272 server_remove_player(pplayer
);
3273 } players_iterate_end
;
3275 /* Now, load the players from the savefile. */
3276 player_slots_iterate(pslot
) {
3277 struct player
*pplayer
;
3278 struct rgbcolor
*prgbcolor
= NULL
;
3279 int pslot_id
= player_slot_index(pslot
);
3281 if (NULL
== secfile_section_lookup(loading
->file
, "player%d",
3286 /* Get player AI type. */
3287 string
= secfile_lookup_str(loading
->file
, "player%d.ai_type",
3288 player_slot_index(pslot
));
3289 sg_failure_ret(string
!= NULL
, "%s", secfile_error());
3291 /* Get player color */
3292 if (!rgbcolor_load(loading
->file
, &prgbcolor
, "player%d.color",
3294 if (loading
->version
>= 10 && game_was_started()) {
3295 /* 2.4.0 or later savegame. This is not an error in 2.3 savefiles,
3296 * as they predate the introduction of configurable player colors. */
3297 log_sg("Game has started, yet player %d has no color defined.",
3299 /* This will be fixed up later */
3301 log_verbose("No color defined for player %d.", pslot_id
);
3302 /* Colors will be assigned on game start, or at end of savefile
3303 * loading if game has already started */
3307 /* Create player. */
3308 pplayer
= server_create_player(player_slot_index(pslot
), string
,
3310 sg_failure_ret(pplayer
!= NULL
, "Invalid AI type: '%s'!", string
);
3312 server_player_init(pplayer
, FALSE
, FALSE
);
3314 /* Free the color definition. */
3315 rgbcolor_destroy(prgbcolor
);
3316 } player_slots_iterate_end
;
3318 /* check number of players */
3319 nplayers
= secfile_lookup_int_default(loading
->file
, 0, "players.nplayers");
3320 sg_failure_ret(player_count() == nplayers
, "The value of players.nplayers "
3321 "(%d) from the loaded game does not match the number of "
3322 "players present (%d).", nplayers
, player_count());
3324 /* Load team informations. */
3325 players_iterate(pplayer
) {
3327 struct team_slot
*tslot
= NULL
;
3329 sg_failure_ret(secfile_lookup_int(loading
->file
, &team
,
3331 player_number(pplayer
))
3332 && (tslot
= team_slot_by_number(team
)),
3333 "Invalid team definition for player %s (nb %d).",
3334 player_name(pplayer
), player_number(pplayer
));
3335 team_add_player(pplayer
, team_new(tslot
));
3336 } players_iterate_end
;
3338 /* Loading the shuffle list is quite complex. At the time of saving the
3339 * shuffle data is saved as
3340 * shuffled_player_<number> = player_slot_id
3341 * where number is an increasing number and player_slot_id is a number
3342 * between 0 and the maximum number of player slots. Now we have to create
3344 * shuffler_players[number] = player_slot_id
3345 * where all player slot IDs are used exactly one time. The code below
3346 * handles this ... */
3347 if (secfile_lookup_int_default(loading
->file
, -1,
3348 "players.shuffled_player_%d", 0) >= 0) {
3349 int shuffled_players
[player_slot_count()];
3350 bool shuffled_player_set
[player_slot_count()];
3352 player_slots_iterate(pslot
) {
3353 int plrid
= player_slot_index(pslot
);
3355 /* Array to save used numbers. */
3356 shuffled_player_set
[plrid
] = FALSE
;
3357 /* List of all player IDs (needed for set_shuffled_players()). It is
3358 * initialised with the value -1 to indicate that no value is set. */
3359 shuffled_players
[plrid
] = -1;
3360 } player_slots_iterate_end
;
3362 /* Load shuffled player list. */
3363 for (i
= 0; i
< player_count(); i
++){
3365 = secfile_lookup_int_default(loading
->file
, -1,
3366 "players.shuffled_player_%d", i
);
3368 if (shuffle
== -1) {
3369 log_sg("Missing player shuffle information (index %d) "
3370 "- reshuffle player list!", i
);
3371 shuffle_loaded
= FALSE
;
3373 } else if (shuffled_player_set
[shuffle
]) {
3374 log_sg("Player shuffle %d used two times "
3375 "- reshuffle player list!", shuffle
);
3376 shuffle_loaded
= FALSE
;
3379 /* Set this ID as used. */
3380 shuffled_player_set
[shuffle
] = TRUE
;
3382 /* Save the player ID in the shuffle list. */
3383 shuffled_players
[i
] = shuffle
;
3386 if (shuffle_loaded
) {
3387 /* Insert missing numbers. */
3388 int shuffle_index
= player_count();
3389 for (i
= 0; i
< player_slot_count(); i
++){
3390 if (!shuffled_player_set
[i
]) {
3391 shuffled_players
[shuffle_index
] = i
;
3394 /* shuffle_index must not grow behind the size of shuffled_players. */
3395 sg_failure_ret(shuffle_index
<= player_slot_count(),
3396 "Invalid player shuffle data!");
3400 log_debug("[load shuffle] player_count() = %d", player_count());
3401 player_slots_iterate(pslot
) {
3402 int plrid
= player_slot_index(pslot
);
3403 log_debug("[load shuffle] id: %3d => slot: %3d | slot %3d: %s",
3404 plrid
, shuffled_players
[plrid
], plrid
,
3405 shuffled_player_set
[plrid
] ? "is used" : "-");
3406 } player_slots_iterate_end
;
3409 /* Set shuffle list from savegame. */
3410 set_shuffled_players(shuffled_players
);
3414 if (!shuffle_loaded
) {
3415 /* No shuffled players included or error loading them, so shuffle them
3416 * (this may include scenarios). */
3421 /****************************************************************************
3423 ****************************************************************************/
3424 static void sg_load_players(struct loaddata
*loading
)
3426 /* Check status and return if not OK (sg_success != TRUE). */
3429 if (game
.info
.is_new_game
) {
3430 /* Nothing to do. */
3434 players_iterate(pplayer
) {
3435 sg_load_player_main(loading
, pplayer
);
3436 sg_load_player_cities(loading
, pplayer
);
3437 sg_load_player_units(loading
, pplayer
);
3438 sg_load_player_attributes(loading
, pplayer
);
3440 /* Check the sucess of the functions above. */
3443 /* print out some informations */
3444 if (pplayer
->ai_controlled
) {
3445 log_normal(_("%s has been added as %s level AI-controlled player "
3446 "(%s)."), player_name(pplayer
),
3447 ai_level_name(pplayer
->ai_common
.skill_level
),
3448 ai_name(pplayer
->ai
));
3450 log_normal(_("%s has been added as human player."),
3451 player_name(pplayer
));
3453 } players_iterate_end
;
3455 /* In case of tech_leakage, we can update research only after all the
3456 * players have been loaded */
3457 /* Also load the transport status of the units here. It must be a special
3458 * case as all units must be known (unit on an allied transporter). */
3459 players_iterate(pplayer
) {
3460 struct player_research
*presearch
= player_research_get(pplayer
);
3462 /* Mark the reachable techs */
3463 player_research_update(pplayer
);
3465 /* Check researching technology and goal. */
3466 if (presearch
->researching
!= A_UNSET
3467 && !is_future_tech(presearch
->researching
)
3468 && (valid_advance_by_number(presearch
->researching
) == NULL
3469 || (player_invention_state(pplayer
, presearch
->researching
)
3470 != TECH_PREREQS_KNOWN
))) {
3471 log_sg(_("%s had invalid researching technology."),
3472 player_name(pplayer
));
3473 presearch
->researching
= A_UNSET
;
3475 if (presearch
->tech_goal
!= A_UNSET
3476 && !is_future_tech(presearch
->tech_goal
)
3477 && (valid_advance_by_number(presearch
->researching
) == NULL
3478 || !player_invention_reachable(pplayer
, presearch
->tech_goal
,
3480 || (player_invention_state(pplayer
, presearch
->tech_goal
)
3482 log_sg(_("%s had invalid technology goal."),
3483 player_name(pplayer
));
3484 presearch
->tech_goal
= A_UNSET
;
3487 /* Load unit transport status. */
3488 sg_load_player_units_transport(loading
, pplayer
);
3489 } players_iterate_end
;
3491 /* Savegame may contain nation assignments that are incompatible with the
3492 * current nationset -- for instance, if it predates the introduction of
3493 * nationsets. Ensure they are compatible, one way or another. */
3494 fit_nationset_to_players();
3496 /* Some players may have invalid nations in the ruleset. Once all players
3497 * are loaded, pick one of the remaining nations for them. */
3498 players_iterate(pplayer
) {
3499 if (pplayer
->nation
== NO_NATION_SELECTED
) {
3500 player_set_nation(pplayer
, pick_a_nation(NULL
, FALSE
, TRUE
,
3502 /* TRANS: Minor error message: <Leader> ... <Poles>. */
3503 log_sg(_("%s had invalid nation; changing to %s."),
3504 player_name(pplayer
), nation_plural_for_player(pplayer
));
3506 } players_iterate_end
;
3508 /* Sanity check alliances, prevent allied-with-ally-of-enemy. */
3509 players_iterate_alive(plr
) {
3510 players_iterate_alive(aplayer
) {
3511 if (pplayers_allied(plr
, aplayer
)) {
3512 enum dipl_reason can_ally
= pplayer_can_make_treaty(plr
, aplayer
,
3514 if (can_ally
== DIPL_ALLIANCE_PROBLEM_US
3515 || can_ally
== DIPL_ALLIANCE_PROBLEM_THEM
) {
3516 log_sg("Illegal alliance structure detected: "
3517 "%s alliance to %s reduced to peace treaty.",
3518 nation_rule_name(nation_of_player(plr
)),
3519 nation_rule_name(nation_of_player(aplayer
)));
3520 player_diplstate_get(plr
, aplayer
)->type
= DS_PEACE
;
3521 player_diplstate_get(aplayer
, plr
)->type
= DS_PEACE
;
3524 } players_iterate_alive_end
;
3525 } players_iterate_alive_end
;
3527 /* Update all city information. This must come after all cities are
3528 * loaded (in player_load) but before player (dumb) cities are loaded
3529 * in player_load_vision(). */
3530 cities_iterate(pcity
) {
3531 city_refresh_from_main_map(pcity
, NULL
);
3532 } cities_iterate_end
;
3534 /* Since the cities must be placed on the map to put them on the
3535 player map we do this afterwards */
3536 players_iterate(pplayer
) {
3537 sg_load_player_vision(loading
, pplayer
);
3538 /* Check the sucess of the function above. */
3540 } players_iterate_end
;
3542 /* Check shared vision. */
3543 players_iterate(pplayer
) {
3544 BV_CLR_ALL(pplayer
->gives_shared_vision
);
3545 BV_CLR_ALL(pplayer
->server
.really_gives_vision
);
3546 } players_iterate_end
;
3548 players_iterate(pplayer
) {
3549 int plr1
= player_index(pplayer
);
3551 players_iterate(pplayer2
) {
3552 int plr2
= player_index(pplayer2
);
3553 if (secfile_lookup_bool_default(loading
->file
, FALSE
,
3554 "player%d.diplstate%d.gives_shared_vision", plr1
, plr2
)) {
3555 give_shared_vision(pplayer
, pplayer2
);
3557 } players_iterate_end
;
3558 } players_iterate_end
;
3560 initialize_globals();
3561 unit_ordering_apply();
3563 /* All vision is ready; this calls city_thaw_workers_queue(). */
3564 map_calculate_borders();
3566 /* Make sure everything is consistent. */
3567 players_iterate(pplayer
) {
3568 unit_list_iterate(pplayer
->units
, punit
) {
3569 if (!can_unit_continue_current_activity(punit
)) {
3570 log_sg("Unit doing illegal activity in savegame!");
3571 punit
->activity
= ACTIVITY_IDLE
;
3573 } unit_list_iterate_end
;
3574 } players_iterate_end
;
3576 cities_iterate(pcity
) {
3577 city_refresh(pcity
);
3578 city_thaw_workers(pcity
); /* may auto_arrange_workers() */
3579 } cities_iterate_end
;
3581 /* Player colors are always needed once game has started. Pre-2.4 savegames
3582 * lack them. This cannot be in compatibility conversion layer as we need
3583 * all the player data available to be able to assign best colors. */
3584 if (game_was_started()) {
3585 assign_player_colors();
3589 /****************************************************************************
3591 ****************************************************************************/
3592 static void sg_save_players(struct savedata
*saving
)
3594 /* Check status and return if not OK (sg_success != TRUE). */
3597 if ((saving
->scenario
&& !saving
->save_players
)
3598 || !game_was_started()) {
3599 /* Nothing to do for a scenario without saved players or a game in
3604 secfile_insert_int(saving
->file
, player_count(), "players.nplayers");
3606 /* Save destroyed wonders as bitvector. Note that improvement order
3607 * is saved in 'savefile.improvement.order'. */
3609 char destroyed
[B_LAST
+1];
3611 improvement_iterate(pimprove
) {
3612 if (is_great_wonder(pimprove
)
3613 && great_wonder_is_destroyed(pimprove
)) {
3614 destroyed
[improvement_index(pimprove
)] = '1';
3616 destroyed
[improvement_index(pimprove
)] = '0';
3618 } improvement_iterate_end
;
3619 destroyed
[improvement_count()] = '\0';
3620 secfile_insert_str(saving
->file
, destroyed
,
3621 "players.destroyed_wonders");
3624 secfile_insert_int(saving
->file
, server
.identity_number
,
3625 "players.identity_number_used");
3627 /* Save player order. */
3630 shuffled_players_iterate(pplayer
) {
3631 secfile_insert_int(saving
->file
, player_number(pplayer
),
3632 "players.shuffled_player_%d", i
);
3634 } shuffled_players_iterate_end
;
3638 unit_ordering_calc();
3641 players_iterate(pplayer
) {
3642 sg_save_player_main(saving
, pplayer
);
3643 sg_save_player_cities(saving
, pplayer
);
3644 sg_save_player_units(saving
, pplayer
);
3645 sg_save_player_attributes(saving
, pplayer
);
3646 sg_save_player_vision(saving
, pplayer
);
3647 } players_iterate_end
;
3650 /****************************************************************************
3651 Main player data loading function
3652 ****************************************************************************/
3653 static void sg_load_player_main(struct loaddata
*loading
,
3656 int i
, plrno
= player_number(plr
);
3658 struct government
*gov
;
3659 struct player_research
*research
;
3661 /* Check status and return if not OK (sg_success != TRUE). */
3664 /* Basic player data. */
3665 string
= secfile_lookup_str(loading
->file
, "player%d.name", plrno
);
3666 sg_failure_ret(string
!= NULL
, "%s", secfile_error());
3667 server_player_set_name(plr
, string
);
3668 sz_strlcpy(plr
->username
,
3669 secfile_lookup_str_default(loading
->file
, "",
3670 "player%d.username", plrno
));
3671 sz_strlcpy(plr
->ranked_username
,
3672 secfile_lookup_str_default(loading
->file
, "",
3673 "player%d.ranked_username",
3675 string
= secfile_lookup_str_default(loading
->file
, "",
3676 "player%d.delegation_username",
3678 /* Defaults to no delegation. */
3679 if (strlen(string
)) {
3680 player_delegation_set(plr
, string
);
3684 string
= secfile_lookup_str(loading
->file
, "player%d.nation", plrno
);
3685 player_set_nation(plr
, nation_by_rule_name(string
));
3688 string
= secfile_lookup_str(loading
->file
, "player%d.government_name",
3690 gov
= government_by_rule_name(string
);
3691 sg_failure_ret(gov
!= NULL
, "Player%d: unsupported government \"%s\".",
3693 plr
->government
= gov
;
3695 /* Target government */
3696 string
= secfile_lookup_str(loading
->file
,
3697 "player%d.target_government_name", plrno
);
3699 plr
->target_government
= government_by_rule_name(string
);
3701 plr
->target_government
= NULL
;
3703 plr
->revolution_finishes
3704 = secfile_lookup_int_default(loading
->file
, -1,
3705 "player%d.revolution_finishes", plrno
);
3707 /* Called 'capital' in the savefile for historical reasons */
3708 sg_failure_ret(secfile_lookup_bool(loading
->file
,
3709 &plr
->server
.got_first_city
,
3710 "player%d.capital", plrno
),
3711 "%s", secfile_error());
3713 sg_failure_ret(secfile_lookup_bool(loading
->file
, &plr
->ai_controlled
,
3714 "player%d.ai.control", plrno
),
3715 "%s", secfile_error());
3717 /* Load diplomatic data (diplstate + embassy + vision).
3718 * Shared vision is loaded in sg_load_players(). */
3719 BV_CLR_ALL(plr
->real_embassy
);
3720 players_iterate(pplayer
) {
3722 struct player_diplstate
*ds
= player_diplstate_get(plr
, pplayer
);
3723 i
= player_index(pplayer
);
3725 /* load diplomatic status */
3726 fc_snprintf(buf
, sizeof(buf
), "player%d.diplstate%d", plrno
, i
);
3729 secfile_lookup_int_default(loading
->file
, DS_WAR
, "%s.type", buf
);
3731 secfile_lookup_int_default(loading
->file
, DS_WAR
, "%s.max_state", buf
);
3732 ds
->first_contact_turn
=
3733 secfile_lookup_int_default(loading
->file
, 0,
3734 "%s.first_contact_turn", buf
);
3736 secfile_lookup_int_default(loading
->file
, -2, "%s.turns_left", buf
);
3737 ds
->has_reason_to_cancel
=
3738 secfile_lookup_int_default(loading
->file
, 0,
3739 "%s.has_reason_to_cancel", buf
);
3740 ds
->contact_turns_left
=
3741 secfile_lookup_int_default(loading
->file
, 0,
3742 "%s.contact_turns_left", buf
);
3744 if (secfile_lookup_bool_default(loading
->file
, FALSE
, "%s.embassy",
3746 BV_SET(plr
->real_embassy
, i
);
3748 /* 'gives_shared_vision' is loaded in sg_load_players() as all cities
3750 } players_iterate_end
;
3753 players_iterate(aplayer
) {
3756 fc_snprintf(buf
, sizeof(buf
), "player%d.ai%d", plrno
,
3757 player_index(aplayer
));
3759 plr
->ai_common
.love
[player_index(aplayer
)] =
3760 secfile_lookup_int_default(loading
->file
, 1, "%s.love", buf
);
3761 } players_iterate_end
;
3763 CALL_FUNC_EACH_AI(player_load
, plr
, loading
->file
, plrno
);
3765 /* Some sane defaults */
3766 BV_CLR_ALL(plr
->ai_common
.handicaps
);
3767 plr
->ai_common
.fuzzy
= 0;
3768 plr
->ai_common
.expand
= 100;
3769 plr
->ai_common
.science_cost
= 100;
3770 plr
->ai_common
.skill_level
=
3771 secfile_lookup_int_default(loading
->file
, game
.info
.skill_level
,
3772 "player%d.ai.skill_level", plrno
);
3774 plr
->ai_common
.barbarian_type
3775 = secfile_lookup_int_default(loading
->file
, 0,
3776 "player%d.ai.is_barbarian", plrno
);
3777 if (is_barbarian(plr
)) {
3778 server
.nbarbarians
++;
3781 if (plr
->ai_controlled
) {
3782 set_ai_level_directer(plr
, plr
->ai_common
.skill_level
);
3783 CALL_PLR_AI_FUNC(gained_control
, plr
, plr
);
3786 /* Load city style. */
3790 string
= secfile_lookup_str(loading
->file
, "player%d.city_style_by_name",
3792 sg_failure_ret(string
!= NULL
, "%s", secfile_error());
3793 city_style
= city_style_by_rule_name(string
);
3794 if (city_style
< 0) {
3795 log_sg("Player%d: unsupported city_style_name \"%s\". "
3796 "Changed to \"%s\".", plrno
, string
, city_style_rule_name(0));
3799 plr
->city_style
= city_style
;
3802 plr
->nturns_idle
= 0;
3803 plr
->is_male
= secfile_lookup_bool_default(loading
->file
, TRUE
,
3804 "player%d.is_male", plrno
);
3805 sg_failure_ret(secfile_lookup_bool(loading
->file
, &plr
->is_alive
,
3806 "player%d.is_alive", plrno
),
3807 "%s", secfile_error());
3808 sg_failure_ret(secfile_lookup_int(loading
->file
, &plr
->economic
.gold
,
3809 "player%d.gold", plrno
),
3810 "%s", secfile_error());
3811 sg_failure_ret(secfile_lookup_int(loading
->file
, &plr
->economic
.tax
,
3812 "player%d.rates.tax", plrno
),
3813 "%s", secfile_error());
3814 sg_failure_ret(secfile_lookup_int(loading
->file
, &plr
->economic
.science
,
3815 "player%d.rates.science", plrno
),
3816 "%s", secfile_error());
3817 sg_failure_ret(secfile_lookup_int(loading
->file
, &plr
->economic
.luxury
,
3818 "player%d.rates.luxury", plrno
),
3819 "%s", secfile_error());
3821 /* Add techs from game and nation, but ignore game.info.tech. */
3822 init_tech(plr
, FALSE
);
3824 /* Load research related data. */
3825 research
= player_research_get(plr
);
3827 research
->tech_goal
=
3828 technology_load(loading
->file
, "player%d.research.goal", plrno
);
3829 plr
->server
.bulbs_last_turn
=
3830 secfile_lookup_int_default(loading
->file
, 0,
3831 "player%d.research.bulbs_last_turn", plrno
);
3832 sg_failure_ret(secfile_lookup_int(loading
->file
,
3833 &research
->techs_researched
,
3834 "player%d.research.techs", plrno
),
3835 "%s", secfile_error());
3836 sg_failure_ret(secfile_lookup_int(loading
->file
,
3837 &research
->future_tech
,
3838 "player%d.research.futuretech", plrno
),
3839 "%s", secfile_error());
3840 sg_failure_ret(secfile_lookup_int(loading
->file
,
3841 &research
->bulbs_researched
,
3842 "player%d.research.bulbs", plrno
),
3843 "%s", secfile_error());
3844 research
->bulbs_researching_saved
3845 = secfile_lookup_int_default(loading
->file
, 0,
3846 "player%d.research.bulbs_before", plrno
);
3847 research
->researching_saved
3848 = technology_load(loading
->file
, "player%d.research.saved", plrno
);
3849 research
->researching
3850 = technology_load(loading
->file
, "player%d.research.now", plrno
);
3852 = secfile_lookup_bool_default(loading
->file
, FALSE
,
3853 "player%d.research.got_tech", plrno
);
3855 string
= secfile_lookup_str(loading
->file
, "player%d.research.done", plrno
);
3856 sg_failure_ret(string
!= NULL
, "%s", secfile_error());
3857 sg_failure_ret(strlen(string
) == loading
->technology
.size
,
3858 "Invalid length of 'player%d.technology' (%lu ~= %lu).",
3859 plrno
, (unsigned long) strlen(string
),
3860 (unsigned long) loading
->technology
.size
);
3861 for (i
= 0; i
< loading
->technology
.size
; i
++) {
3862 sg_failure_ret(string
[i
] == '1' || string
[i
] == '0',
3863 "Undefined value '%c' within 'player%d.technology'.",
3866 if (string
[i
] == '1') {
3867 struct advance
*padvance
=
3868 advance_by_rule_name(loading
->technology
.order
[i
]);
3870 player_invention_set(plr
, advance_number(padvance
), TECH_KNOWN
);
3876 for (i
= 0; i
< loading
->trait
.size
; i
++) {
3877 enum trait tr
= trait_by_name(loading
->trait
.order
[i
], fc_strcasecmp
);
3879 if (trait_is_valid(tr
)) {
3880 plr
->ai_common
.traits
[tr
].mod
=
3881 secfile_lookup_int_default(loading
->file
, 0,
3882 "plr%d.trait.mod%d", plrno
, i
);
3887 /* Unit statistics. */
3888 plr
->score
.units_built
=
3889 secfile_lookup_int_default(loading
->file
, 0,
3890 "player%d.units_built", plrno
);
3891 plr
->score
.units_killed
=
3892 secfile_lookup_int_default(loading
->file
, 0,
3893 "player%d.units_killed", plrno
);
3894 plr
->score
.units_lost
=
3895 secfile_lookup_int_default(loading
->file
, 0,
3896 "player%d.units_lost", plrno
);
3898 /* Load space ship data. */
3900 struct player_spaceship
*ship
= &plr
->spaceship
;
3905 fc_snprintf(prefix
, sizeof(prefix
), "player%d.spaceship", plrno
);
3906 spaceship_init(ship
);
3907 sg_failure_ret(secfile_lookup_int(loading
->file
,
3909 "%s.state", prefix
),
3910 "%s", secfile_error());
3913 if (ship
->state
!= SSHIP_NONE
) {
3914 sg_failure_ret(secfile_lookup_int(loading
->file
, &ship
->structurals
,
3915 "%s.structurals", prefix
),
3916 "%s", secfile_error());
3917 sg_failure_ret(secfile_lookup_int(loading
->file
, &ship
->components
,
3918 "%s.components", prefix
),
3919 "%s", secfile_error());
3920 sg_failure_ret(secfile_lookup_int(loading
->file
, &ship
->modules
,
3921 "%s.modules", prefix
),
3922 "%s", secfile_error());
3923 sg_failure_ret(secfile_lookup_int(loading
->file
, &ship
->fuel
,
3925 "%s", secfile_error());
3926 sg_failure_ret(secfile_lookup_int(loading
->file
, &ship
->propulsion
,
3927 "%s.propulsion", prefix
),
3928 "%s", secfile_error());
3929 sg_failure_ret(secfile_lookup_int(loading
->file
, &ship
->habitation
,
3930 "%s.habitation", prefix
),
3931 "%s", secfile_error());
3932 sg_failure_ret(secfile_lookup_int(loading
->file
, &ship
->life_support
,
3933 "%s.life_support", prefix
),
3934 "%s", secfile_error());
3935 sg_failure_ret(secfile_lookup_int(loading
->file
, &ship
->solar_panels
,
3936 "%s.solar_panels", prefix
),
3937 "%s", secfile_error());
3939 st
= secfile_lookup_str(loading
->file
, "%s.structure", prefix
);
3940 sg_failure_ret(st
!= NULL
, "%s", secfile_error())
3941 for (i
= 0; i
< NUM_SS_STRUCTURALS
&& st
[i
]; i
++) {
3942 sg_failure_ret(st
[i
] == '1' || st
[i
] == '0',
3943 "Undefined value '%c' within '%s.structure'.", st
[i
],
3946 if (!(st
[i
] == '0')) {
3947 BV_SET(ship
->structure
, i
);
3950 if (ship
->state
>= SSHIP_LAUNCHED
) {
3951 sg_failure_ret(secfile_lookup_int(loading
->file
, &ship
->launch_year
,
3952 "%s.launch_year", prefix
),
3953 "%s", secfile_error());
3955 spaceship_calc_derived(ship
);
3959 /* Load lost wonder data. */
3960 string
= secfile_lookup_str(loading
->file
, "player%d.lost_wonders", plrno
);
3961 /* If not present, probably an old savegame; nothing to be done */
3964 sg_failure_ret(strlen(string
) == loading
->improvement
.size
,
3965 "Invalid length for 'player%d.lost_wonders' "
3966 "(%lu ~= %lu)", plrno
, (unsigned long) strlen(string
),
3967 (unsigned long) loading
->improvement
.size
);
3968 for (k
= 0; k
< loading
->improvement
.size
; k
++) {
3969 sg_failure_ret(string
[k
] == '1' || string
[k
] == '0',
3970 "Undefined value '%c' within "
3971 "'player%d.lost_wonders'.", plrno
, string
[k
]);
3973 if (string
[k
] == '1') {
3974 struct impr_type
*pimprove
=
3975 improvement_by_rule_name(loading
->improvement
.order
[k
]);
3977 plr
->wonders
[improvement_index(pimprove
)] = WONDER_LOST
;
3984 /****************************************************************************
3985 Main player data saving function.
3986 ****************************************************************************/
3987 static void sg_save_player_main(struct savedata
*saving
,
3990 int i
, plrno
= player_number(plr
);
3991 struct player_spaceship
*ship
= &plr
->spaceship
;
3993 /* Check status and return if not OK (sg_success != TRUE). */
3996 secfile_insert_str(saving
->file
, ai_name(plr
->ai
),
3997 "player%d.ai_type", plrno
);
3998 secfile_insert_str(saving
->file
, player_name(plr
),
3999 "player%d.name", plrno
);
4000 secfile_insert_str(saving
->file
, plr
->username
,
4001 "player%d.username", plrno
);
4002 if (plr
->rgb
!= NULL
) {
4003 rgbcolor_save(saving
->file
, plr
->rgb
, "player%d.color", plrno
);
4005 /* Colorless players are ok in pregame */
4006 if (game_was_started()) {
4007 log_sg("Game has started, yet player %d has no color defined.", plrno
);
4010 secfile_insert_str(saving
->file
, plr
->ranked_username
,
4011 "player%d.ranked_username", plrno
);
4012 secfile_insert_str(saving
->file
,
4013 player_delegation_get(plr
) ? player_delegation_get(plr
)
4015 "player%d.delegation_username", plrno
);
4016 secfile_insert_str(saving
->file
, nation_rule_name(nation_of_player(plr
)),
4017 "player%d.nation", plrno
);
4018 secfile_insert_int(saving
->file
, plr
->team
? team_index(plr
->team
) : -1,
4019 "player%d.team_no", plrno
);
4021 secfile_insert_str(saving
->file
,
4022 government_rule_name(government_of_player(plr
)),
4023 "player%d.government_name", plrno
);
4024 if (plr
->target_government
) {
4025 secfile_insert_str(saving
->file
,
4026 government_rule_name(plr
->target_government
),
4027 "player%d.target_government_name", plrno
);
4030 secfile_insert_str(saving
->file
, city_style_rule_name(plr
->city_style
),
4031 "player%d.city_style_by_name", plrno
);
4033 secfile_insert_bool(saving
->file
, plr
->is_male
,
4034 "player%d.is_male", plrno
);
4035 secfile_insert_bool(saving
->file
, plr
->is_alive
,
4036 "player%d.is_alive", plrno
);
4037 secfile_insert_bool(saving
->file
, plr
->ai_controlled
,
4038 "player%d.ai.control", plrno
);
4040 players_iterate(pplayer
) {
4042 struct player_diplstate
*ds
= player_diplstate_get(plr
, pplayer
);
4044 i
= player_index(pplayer
);
4046 /* save diplomatic state */
4047 fc_snprintf(buf
, sizeof(buf
), "player%d.diplstate%d", plrno
, i
);
4049 secfile_insert_int(saving
->file
, ds
->type
,
4051 secfile_insert_int(saving
->file
, ds
->max_state
,
4052 "%s.max_state", buf
);
4053 secfile_insert_int(saving
->file
, ds
->first_contact_turn
,
4054 "%s.first_contact_turn", buf
);
4055 secfile_insert_int(saving
->file
, ds
->turns_left
,
4056 "%s.turns_left", buf
);
4057 secfile_insert_int(saving
->file
, ds
->has_reason_to_cancel
,
4058 "%s.has_reason_to_cancel", buf
);
4059 secfile_insert_int(saving
->file
, ds
->contact_turns_left
,
4060 "%s.contact_turns_left", buf
);
4061 secfile_insert_bool(saving
->file
, player_has_real_embassy(plr
, pplayer
),
4063 secfile_insert_bool(saving
->file
, gives_shared_vision(plr
, pplayer
),
4064 "%s.gives_shared_vision", buf
);
4065 } players_iterate_end
;
4067 players_iterate(aplayer
) {
4068 i
= player_index(aplayer
);
4070 secfile_insert_int(saving
->file
, plr
->ai_common
.love
[i
],
4071 "player%d.ai%d.love", plrno
, i
);
4072 } players_iterate_end
;
4074 CALL_FUNC_EACH_AI(player_save
, plr
, saving
->file
, plrno
);
4076 secfile_insert_int(saving
->file
, plr
->ai_common
.skill_level
,
4077 "player%d.ai.skill_level", plrno
);
4078 secfile_insert_int(saving
->file
, plr
->ai_common
.barbarian_type
,
4079 "player%d.ai.is_barbarian", plrno
);
4080 secfile_insert_int(saving
->file
, plr
->economic
.gold
,
4081 "player%d.gold", plrno
);
4082 secfile_insert_int(saving
->file
, plr
->economic
.tax
,
4083 "player%d.rates.tax", plrno
);
4084 secfile_insert_int(saving
->file
, plr
->economic
.science
,
4085 "player%d.rates.science", plrno
);
4086 secfile_insert_int(saving
->file
, plr
->economic
.luxury
,
4087 "player%d.rates.luxury", plrno
);
4089 technology_save(saving
->file
, "player%d.research.goal",
4090 plrno
, player_research_get(plr
)->tech_goal
);
4091 secfile_insert_int(saving
->file
, plr
->server
.bulbs_last_turn
,
4092 "player%d.research.bulbs_last_turn", plrno
);
4093 secfile_insert_int(saving
->file
,
4094 player_research_get(plr
)->techs_researched
,
4095 "player%d.research.techs", plrno
);
4096 secfile_insert_int(saving
->file
, player_research_get(plr
)->future_tech
,
4097 "player%d.research.futuretech", plrno
);
4098 secfile_insert_int(saving
->file
,
4099 player_research_get(plr
)->bulbs_researching_saved
,
4100 "player%d.research.bulbs_before", plrno
);
4101 technology_save(saving
->file
, "player%d.research.saved", plrno
,
4102 player_research_get(plr
)->researching_saved
);
4103 secfile_insert_int(saving
->file
,
4104 player_research_get(plr
)->bulbs_researched
,
4105 "player%d.research.bulbs", plrno
);
4106 technology_save(saving
->file
, "player%d.research.now", plrno
,
4107 player_research_get(plr
)->researching
);
4108 secfile_insert_bool(saving
->file
, player_research_get(plr
)->got_tech
,
4109 "player%d.research.got_tech", plrno
);
4111 /* Save technology lists as bytevector. Note that technology order is
4112 * saved in savefile.technology.order */
4114 char invs
[A_LAST
+1];
4115 advance_index_iterate(A_NONE
, tech_id
) {
4116 invs
[tech_id
] = (player_invention_state(plr
, tech_id
) == TECH_KNOWN
)
4118 } advance_index_iterate_end
;
4119 invs
[game
.control
.num_tech_types
] = '\0';
4120 secfile_insert_str(saving
->file
, invs
, "player%d.research.done", plrno
);
4128 for (tr
= trait_begin(), j
= 0; tr
!= trait_end(); tr
= trait_next(tr
), j
++) {
4129 secfile_insert_int(saving
->file
, plr
->ai_common
.traits
[tr
].mod
,
4130 "player%d.trait.mod%d", plrno
, j
);
4134 /* Called 'capital' in the savefile for historical reasons */
4135 secfile_insert_bool(saving
->file
, plr
->server
.got_first_city
,
4136 "player%d.capital", plrno
);
4137 secfile_insert_int(saving
->file
, plr
->revolution_finishes
,
4138 "player%d.revolution_finishes", plrno
);
4140 /* Unit statistics. */
4141 secfile_insert_int(saving
->file
, plr
->score
.units_built
,
4142 "player%d.units_built", plrno
);
4143 secfile_insert_int(saving
->file
, plr
->score
.units_killed
,
4144 "player%d.units_killed", plrno
);
4145 secfile_insert_int(saving
->file
, plr
->score
.units_lost
,
4146 "player%d.units_lost", plrno
);
4148 /* Save space ship status. */
4149 secfile_insert_int(saving
->file
, ship
->state
, "player%d.spaceship.state",
4151 if (ship
->state
!= SSHIP_NONE
) {
4153 char st
[NUM_SS_STRUCTURALS
+1];
4156 fc_snprintf(buf
, sizeof(buf
), "player%d.spaceship", plrno
);
4158 secfile_insert_int(saving
->file
, ship
->structurals
,
4159 "%s.structurals", buf
);
4160 secfile_insert_int(saving
->file
, ship
->components
,
4161 "%s.components", buf
);
4162 secfile_insert_int(saving
->file
, ship
->modules
,
4164 secfile_insert_int(saving
->file
, ship
->fuel
, "%s.fuel", buf
);
4165 secfile_insert_int(saving
->file
, ship
->propulsion
, "%s.propulsion", buf
);
4166 secfile_insert_int(saving
->file
, ship
->habitation
, "%s.habitation", buf
);
4167 secfile_insert_int(saving
->file
, ship
->life_support
,
4168 "%s.life_support", buf
);
4169 secfile_insert_int(saving
->file
, ship
->solar_panels
,
4170 "%s.solar_panels", buf
);
4172 for(i
= 0; i
< NUM_SS_STRUCTURALS
; i
++) {
4173 st
[i
] = BV_ISSET(ship
->structure
, i
) ? '1' : '0';
4176 secfile_insert_str(saving
->file
, st
, "%s.structure", buf
);
4177 if (ship
->state
>= SSHIP_LAUNCHED
) {
4178 secfile_insert_int(saving
->file
, ship
->launch_year
,
4179 "%s.launch_year", buf
);
4183 /* Save lost wonders info. */
4185 char lost
[B_LAST
+1];
4187 improvement_iterate(pimprove
) {
4188 if (is_wonder(pimprove
) && wonder_is_lost(plr
, pimprove
)) {
4189 lost
[improvement_index(pimprove
)] = '1';
4191 lost
[improvement_index(pimprove
)] = '0';
4193 } improvement_iterate_end
;
4194 lost
[improvement_count()] = '\0';
4195 secfile_insert_str(saving
->file
, lost
,
4196 "player%d.lost_wonders", plrno
);
4200 /****************************************************************************
4202 ****************************************************************************/
4203 static void sg_load_player_cities(struct loaddata
*loading
,
4206 int ncities
, i
, plrno
= player_number(plr
);
4208 /* Check status and return if not OK (sg_success != TRUE). */
4211 sg_failure_ret(secfile_lookup_int(loading
->file
, &ncities
,
4212 "player%d.ncities", plrno
),
4213 "%s", secfile_error());
4215 if (!plr
->is_alive
&& ncities
> 0) {
4216 log_sg("'player%d.ncities' = %d for dead player!", plrno
, ncities
);
4220 if (!plr
->server
.got_first_city
&& ncities
> 0) {
4221 /* Probably barbarians in an old savegame; fix up */
4222 plr
->server
.got_first_city
= TRUE
;
4225 /* Load all cities of the player. */
4226 for (i
= 0; i
< ncities
; i
++) {
4230 fc_snprintf(buf
, sizeof(buf
), "player%d.c%d", plrno
, i
);
4232 /* Create a dummy city. */
4233 pcity
= create_city_virtual(plr
, NULL
, buf
);
4234 adv_city_alloc(pcity
);
4235 if (!sg_load_player_city(loading
, plr
, pcity
, buf
)) {
4236 adv_city_free(pcity
);
4237 destroy_city_virtual(pcity
);
4238 sg_failure_ret(FALSE
, "Error loading city %d of player %d.", i
, plrno
);
4241 identity_number_reserve(pcity
->id
);
4242 idex_register_city(pcity
);
4244 /* Load the information about the nationality of citizens. This is done
4245 * here because the city sanity check called by citizens_update() requires
4246 * that the city is registered. */
4247 sg_load_player_city_citizens(loading
, plr
, pcity
, buf
);
4249 /* After everything is loaded, but before vision. */
4250 map_claim_ownership(city_tile(pcity
), plr
, city_tile(pcity
));
4252 /* adding the city contribution to fog-of-war */
4253 pcity
->server
.vision
= vision_new(plr
, city_tile(pcity
));
4254 vision_reveal_tiles(pcity
->server
.vision
, game
.server
.vision_reveal_tiles
);
4255 city_refresh_vision(pcity
);
4257 /* Refresh the city. This also checks the squared city radius. Thus, it
4258 * must be after improvements, as the effect City_Radius_SQ could be
4259 * influenced by improvements; and after the vision is defined, as the
4260 * function calls city_refresh_vision(). */
4261 city_refresh(pcity
);
4263 city_list_append(plr
->cities
, pcity
);
4266 /* Check the sanity of the cities. */
4267 city_list_iterate(plr
->cities
, pcity
) {
4268 city_refresh(pcity
);
4269 sanity_check_city(pcity
);
4270 } city_list_iterate_end
;
4273 /****************************************************************************
4274 Load data for one city. sg_save_player_city() is not defined.
4275 ****************************************************************************/
4276 static bool sg_load_player_city(struct loaddata
*loading
, struct player
*plr
,
4277 struct city
*pcity
, const char *citystr
)
4279 struct player
*past
;
4280 const char *kind
, *name
, *string
;
4281 int id
, i
, repair
, specialists
= 0, workers
= 0, value
;
4285 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &nat_x
, "%s.x", citystr
),
4286 FALSE
, "%s", secfile_error());
4287 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &nat_y
, "%s.y", citystr
),
4288 FALSE
, "%s", secfile_error());
4289 pcity
->tile
= native_pos_to_tile(nat_x
, nat_y
);
4290 sg_warn_ret_val(NULL
!= pcity
->tile
, FALSE
,
4291 "%s has invalid center tile (%d, %d)",
4292 citystr
, nat_x
, nat_y
);
4293 sg_warn_ret_val(NULL
== tile_city(pcity
->tile
), FALSE
,
4294 "%s duplicates city (%d, %d)", citystr
, nat_x
, nat_y
);
4296 /* Instead of dying, use 'citystr' string for damaged name. */
4297 sz_strlcpy(pcity
->name
, secfile_lookup_str_default(loading
->file
, citystr
,
4298 "%s.name", citystr
));
4300 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &pcity
->id
, "%s.id",
4301 citystr
), FALSE
, "%s", secfile_error());
4303 id
= secfile_lookup_int_default(loading
->file
, player_number(plr
),
4304 "%s.original", citystr
);
4305 past
= player_by_number(id
);
4307 pcity
->original
= past
;
4310 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &value
, "%s.size",
4311 citystr
), FALSE
, "%s", secfile_error());
4312 size
= (citizens
)value
; /* set the correct type */
4313 sg_warn_ret_val(value
== (int)size
, FALSE
,
4314 "Invalid city size: %d, set to %d", value
, size
);
4315 city_size_set(pcity
, size
);
4317 specialist_type_iterate(sp
) {
4319 secfile_lookup_int(loading
->file
, &value
, "%s.n%s", citystr
,
4320 specialist_rule_name(specialist_by_number(sp
))),
4321 FALSE
, "%s", secfile_error());
4322 pcity
->specialists
[sp
] = (citizens
)value
; /* set the correct type */
4323 sg_warn_ret_val(value
== (int)pcity
->specialists
[sp
], FALSE
,
4324 "Invalid number of specialists: %d, set to %d.", value
,
4325 pcity
->specialists
[sp
]);
4326 specialists
+= pcity
->specialists
[sp
];
4327 } specialist_type_iterate_end
;
4329 for (i
= 0; i
< MAX_TRADE_ROUTES
; i
++) {
4330 pcity
->trade
[i
] = secfile_lookup_int_default(loading
->file
, 0,
4331 "%s.traderoute%d", citystr
, i
);
4334 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &pcity
->food_stock
,
4335 "%s.food_stock", citystr
),
4336 FALSE
, "%s", secfile_error());
4337 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &pcity
->shield_stock
,
4338 "%s.shield_stock", citystr
),
4339 FALSE
, "%s", secfile_error());
4342 secfile_lookup_int_default(loading
->file
, 0, "%s.airlift", citystr
);
4344 secfile_lookup_bool_default(loading
->file
, FALSE
, "%s.was_happy",
4347 pcity
->turn_plague
=
4348 secfile_lookup_int_default(loading
->file
, 0, "%s.turn_plague", citystr
);
4349 if (game
.info
.illness_on
) {
4350 /* recalculate city illness */
4351 pcity
->server
.illness
= city_illness_calc(pcity
, NULL
, NULL
,
4352 &(pcity
->illness_trade
), NULL
);
4355 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &pcity
->anarchy
,
4356 "%s.anarchy", citystr
),
4357 FALSE
, "%s", secfile_error());
4359 secfile_lookup_int_default(loading
->file
, 0, "%s.rapture", citystr
);
4360 pcity
->server
.steal
=
4361 secfile_lookup_int_default(loading
->file
, 0, "%s.steal", citystr
);
4363 /* before did_buy for undocumented hack */
4364 pcity
->turn_founded
=
4365 secfile_lookup_int_default(loading
->file
, -2, "%s.turn_founded",
4367 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &i
, "%s.did_buy",
4368 citystr
), FALSE
, "%s", secfile_error());
4369 pcity
->did_buy
= (i
!= 0);
4370 if (i
== -1 && pcity
->turn_founded
== -2) {
4371 /* undocumented hack */
4372 pcity
->turn_founded
= game
.info
.turn
;
4376 secfile_lookup_bool_default(loading
->file
, FALSE
, "%s.did_sell", citystr
);
4378 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &pcity
->turn_last_built
,
4379 "%s.turn_last_built", citystr
),
4380 FALSE
, "%s", secfile_error());
4382 kind
= secfile_lookup_str(loading
->file
, "%s.currently_building_kind",
4384 name
= secfile_lookup_str(loading
->file
, "%s.currently_building_name",
4386 pcity
->production
= universal_by_rule_name(kind
, name
);
4387 sg_warn_ret_val(pcity
->production
.kind
!= universals_n_invalid(), FALSE
,
4388 "%s.currently_building: unknown \"%s\" \"%s\".",
4389 citystr
, kind
, name
);
4391 kind
= secfile_lookup_str(loading
->file
, "%s.changed_from_kind",
4393 name
= secfile_lookup_str(loading
->file
, "%s.changed_from_name",
4395 pcity
->changed_from
= universal_by_rule_name(kind
, name
);
4396 sg_warn_ret_val(pcity
->changed_from
.kind
!= universals_n_invalid(), FALSE
,
4397 "%s.changed_from: unknown \"%s\" \"%s\".",
4398 citystr
, kind
, name
);
4400 pcity
->before_change_shields
=
4401 secfile_lookup_int_default(loading
->file
, pcity
->shield_stock
,
4402 "%s.before_change_shields", citystr
);
4403 pcity
->caravan_shields
=
4404 secfile_lookup_int_default(loading
->file
, 0,
4405 "%s.caravan_shields", citystr
);
4406 pcity
->disbanded_shields
=
4407 secfile_lookup_int_default(loading
->file
, 0,
4408 "%s.disbanded_shields", citystr
);
4409 pcity
->last_turns_shield_surplus
=
4410 secfile_lookup_int_default(loading
->file
, 0,
4411 "%s.last_turns_shield_surplus",
4414 pcity
->server
.synced
= FALSE
; /* must re-sync with clients */
4416 /* Initialise list of city improvements. */
4417 for (i
= 0; i
< ARRAY_SIZE(pcity
->built
); i
++) {
4418 pcity
->built
[i
].turn
= I_NEVER
;
4421 /* Load city improvements. */
4422 string
= secfile_lookup_str(loading
->file
, "%s.improvements", citystr
);
4423 sg_warn_ret_val(string
!= NULL
, FALSE
, "%s", secfile_error());
4424 sg_warn_ret_val(strlen(string
) == loading
->improvement
.size
, FALSE
,
4425 "Invalid length of '%s.improvements' (%lu ~= %lu).",
4426 citystr
, (unsigned long) strlen(string
),
4427 (unsigned long) loading
->improvement
.size
);
4428 for (i
= 0; i
< loading
->improvement
.size
; i
++) {
4429 sg_warn_ret_val(string
[i
] == '1' || string
[i
] == '0', FALSE
,
4430 "Undefined value '%c' within '%s.improvements'.",
4433 if (string
[i
] == '1') {
4434 struct impr_type
*pimprove
=
4435 improvement_by_rule_name(loading
->improvement
.order
[i
]);
4437 city_add_improvement(pcity
, pimprove
);
4442 sg_failure_ret_val(loading
->worked_tiles
!= NULL
, FALSE
,
4443 "No worked tiles map defined.");
4445 city_freeze_workers(pcity
);
4447 /* load new savegame with variable (squared) city radius and worked
4451 = secfile_lookup_int_default(loading
->file
, -1, "%s.city_radius_sq",
4453 city_map_radius_sq_set(pcity
, radius_sq
);
4455 city_tile_iterate(radius_sq
, city_tile(pcity
), ptile
) {
4456 if (loading
->worked_tiles
[ptile
->index
] == pcity
->id
) {
4457 tile_set_worked(ptile
, pcity
);
4461 /* set this tile to unused; a check for not resetted tiles is
4462 * included in game_load_internal() */
4463 loading
->worked_tiles
[ptile
->index
] = -1;
4466 } city_tile_iterate_end
;
4468 if (tile_worked(city_tile(pcity
)) != pcity
) {
4469 struct city
*pwork
= tile_worked(city_tile(pcity
));
4471 if (NULL
!= pwork
) {
4472 log_sg("[%s] city center of '%s' (%d,%d) [%d] is worked by '%s' "
4473 "(%d,%d) [%d]; repairing ", citystr
, city_name(pcity
),
4474 TILE_XY(city_tile(pcity
)), city_size_get(pcity
), city_name(pwork
),
4475 TILE_XY(city_tile(pwork
)), city_size_get(pwork
));
4477 tile_set_worked(city_tile(pcity
), NULL
); /* remove tile from pwork */
4478 pwork
->specialists
[DEFAULT_SPECIALIST
]++;
4479 auto_arrange_workers(pwork
);
4481 log_sg("[%s] city center of '%s' (%d,%d) [%d] is empty; repairing ",
4482 citystr
, city_name(pcity
), TILE_XY(city_tile(pcity
)),
4483 city_size_get(pcity
));
4487 tile_set_worked(city_tile(pcity
), pcity
);
4488 city_repair_size(pcity
, -1);
4491 repair
= city_size_get(pcity
) - specialists
- (workers
- FREE_WORKED_TILES
);
4493 log_sg("[%s] size mismatch for '%s' (%d,%d): size [%d] != "
4494 "(workers [%d] - free worked tiles [%d]) + specialists [%d]",
4495 citystr
, city_name(pcity
), TILE_XY(city_tile(pcity
)), city_size_get(pcity
),
4496 workers
, FREE_WORKED_TILES
, specialists
);
4499 city_repair_size(pcity
, repair
);
4502 /* worklist_init() done in create_city_virtual() */
4503 worklist_load(loading
->file
, &pcity
->worklist
, "%s", citystr
);
4505 /* Load city options. */
4506 BV_CLR_ALL(pcity
->city_options
);
4507 for (i
= 0; i
< CITYO_LAST
; i
++) {
4508 if (secfile_lookup_bool_default(loading
->file
, FALSE
, "%s.option%d",
4510 BV_SET(pcity
->city_options
, i
);
4514 CALL_FUNC_EACH_AI(city_load
, loading
->file
, pcity
, citystr
);
4519 /****************************************************************************
4520 Load nationality data for one city.
4521 ****************************************************************************/
4522 static void sg_load_player_city_citizens(struct loaddata
*loading
,
4525 const char *citystr
)
4527 if (game
.info
.citizen_nationality
) {
4530 citizens_init(pcity
);
4531 player_slots_iterate(pslot
) {
4534 nationality
= secfile_lookup_int_default(loading
->file
, -1,
4535 "%s.citizen%d", citystr
,
4536 player_slot_index(pslot
));
4537 if (nationality
> 0 && !player_slot_is_used(pslot
)) {
4538 log_sg("Citizens of an invalid nation for %s (player slot %d)!",
4539 city_name(pcity
), player_slot_index(pslot
));
4543 if (nationality
!= -1 && player_slot_is_used(pslot
)) {
4544 sg_warn(nationality
>= 0 && nationality
<= MAX_CITY_SIZE
,
4545 "Invalid value for citizens of player %d in %s: %d.",
4546 player_slot_index(pslot
), city_name(pcity
), nationality
);
4547 citizens_nation_set(pcity
, pslot
, nationality
);
4549 } player_slots_iterate_end
;
4551 size
= citizens_count(pcity
);
4552 if (size
!= city_size_get(pcity
)) {
4554 /* size == 0 can be result from the fact that ruleset had no
4555 * nationality enabled at saving time, so no citizens at all
4556 * were saved. But something more serious must be going on if
4557 * citizens have been saved partially - if some of them are there. */
4558 log_sg("City size and number of citizens does not match in %s "
4559 "(%d != %d)! Repairing ...", city_name(pcity
),
4560 city_size_get(pcity
), size
);
4562 citizens_update(pcity
, NULL
);
4567 /****************************************************************************
4569 ****************************************************************************/
4570 static void sg_save_player_cities(struct savedata
*saving
,
4573 int wlist_max_length
= 0;
4575 int plrno
= player_number(plr
);
4576 bool nations
[MAX_NUM_PLAYER_SLOTS
];
4578 /* Check status and return if not OK (sg_success != TRUE). */
4581 secfile_insert_int(saving
->file
, city_list_size(plr
->cities
),
4582 "player%d.ncities", plrno
);
4584 if (game
.info
.citizen_nationality
) {
4585 /* Initialise the nation list for the citizens information. */
4586 player_slots_iterate(pslot
) {
4587 nations
[player_slot_index(pslot
)] = FALSE
;
4588 } player_slots_iterate_end
;
4591 /* First determine lenght of longest worklist and the nations we have. */
4592 city_list_iterate(plr
->cities
, pcity
) {
4593 /* Check the sanity of the city. */
4594 city_refresh(pcity
);
4595 sanity_check_city(pcity
);
4597 if (pcity
->worklist
.length
> wlist_max_length
) {
4598 wlist_max_length
= pcity
->worklist
.length
;
4601 if (game
.info
.citizen_nationality
) {
4602 /* Find all nations of the citizens,*/
4603 players_iterate(pplayer
) {
4604 if (!nations
[player_index(pplayer
)]
4605 && citizens_nation_get(pcity
, pplayer
->slot
) != 0) {
4606 nations
[player_index(pplayer
)] = TRUE
;
4608 } players_iterate_end
;
4610 } city_list_iterate_end
;
4612 city_list_iterate(plr
->cities
, pcity
) {
4613 struct tile
*pcenter
= city_tile(pcity
);
4614 char impr_buf
[MAX_NUM_ITEMS
+ 1];
4616 int j
, nat_x
, nat_y
;
4618 fc_snprintf(buf
, sizeof(buf
), "player%d.c%d", plrno
, i
);
4621 index_to_native_pos(&nat_x
, &nat_y
, tile_index(pcenter
));
4622 secfile_insert_int(saving
->file
, nat_y
, "%s.y", buf
);
4623 secfile_insert_int(saving
->file
, nat_x
, "%s.x", buf
);
4625 secfile_insert_int(saving
->file
, pcity
->id
, "%s.id", buf
);
4627 secfile_insert_int(saving
->file
, player_number(pcity
->original
),
4628 "%s.original", buf
);
4629 secfile_insert_int(saving
->file
, city_size_get(pcity
), "%s.size", buf
);
4631 specialist_type_iterate(sp
) {
4632 secfile_insert_int(saving
->file
, pcity
->specialists
[sp
], "%s.n%s", buf
,
4633 specialist_rule_name(specialist_by_number(sp
)));
4634 } specialist_type_iterate_end
;
4636 for (j
= 0; j
< MAX_TRADE_ROUTES
; j
++) {
4637 secfile_insert_int(saving
->file
, pcity
->trade
[j
], "%s.traderoute%d",
4641 secfile_insert_int(saving
->file
, pcity
->food_stock
, "%s.food_stock",
4643 secfile_insert_int(saving
->file
, pcity
->shield_stock
, "%s.shield_stock",
4646 secfile_insert_int(saving
->file
, pcity
->airlift
, "%s.airlift",
4648 secfile_insert_bool(saving
->file
, pcity
->was_happy
, "%s.was_happy",
4650 secfile_insert_int(saving
->file
, pcity
->turn_plague
, "%s.turn_plague",
4653 secfile_insert_int(saving
->file
, pcity
->anarchy
, "%s.anarchy", buf
);
4654 secfile_insert_int(saving
->file
, pcity
->rapture
, "%s.rapture", buf
);
4655 secfile_insert_int(saving
->file
, pcity
->server
.steal
, "%s.steal", buf
);
4657 secfile_insert_int(saving
->file
, pcity
->turn_founded
, "%s.turn_founded",
4659 if (pcity
->turn_founded
== game
.info
.turn
) {
4660 j
= -1; /* undocumented hack */
4662 fc_assert(pcity
->did_buy
== TRUE
|| pcity
->did_buy
== FALSE
);
4663 j
= pcity
->did_buy
? 1 : 0;
4665 secfile_insert_int(saving
->file
, j
, "%s.did_buy", buf
);
4666 secfile_insert_bool(saving
->file
, pcity
->did_sell
, "%s.did_sell", buf
);
4667 secfile_insert_int(saving
->file
, pcity
->turn_last_built
,
4668 "%s.turn_last_built", buf
);
4670 /* for visual debugging, variable length strings together here */
4671 secfile_insert_str(saving
->file
, city_name(pcity
), "%s.name", buf
);
4673 secfile_insert_str(saving
->file
, universal_type_rule_name(&pcity
->production
),
4674 "%s.currently_building_kind", buf
);
4675 secfile_insert_str(saving
->file
, universal_rule_name(&pcity
->production
),
4676 "%s.currently_building_name", buf
);
4678 secfile_insert_str(saving
->file
, universal_type_rule_name(&pcity
->changed_from
),
4679 "%s.changed_from_kind", buf
);
4680 secfile_insert_str(saving
->file
, universal_rule_name(&pcity
->changed_from
),
4681 "%s.changed_from_name", buf
);
4683 secfile_insert_int(saving
->file
, pcity
->before_change_shields
,
4684 "%s.before_change_shields", buf
);
4685 secfile_insert_int(saving
->file
, pcity
->caravan_shields
,
4686 "%s.caravan_shields", buf
);
4687 secfile_insert_int(saving
->file
, pcity
->disbanded_shields
,
4688 "%s.disbanded_shields", buf
);
4689 secfile_insert_int(saving
->file
, pcity
->last_turns_shield_surplus
,
4690 "%s.last_turns_shield_surplus", buf
);
4692 /* Save the squared city radius and all tiles within the corresponing
4694 secfile_insert_int(saving
->file
, pcity
->city_radius_sq
,
4695 "player%d.c%d.city_radius_sq", plrno
, i
);
4696 /* The tiles worked by the city are saved using the main map.
4697 * See also sg_save_map_worked(). */
4699 /* Save improvement list as bytevector. Note that improvement order
4700 * is saved in savefile.improvement_order. */
4701 improvement_iterate(pimprove
) {
4702 impr_buf
[improvement_index(pimprove
)]
4703 = (pcity
->built
[improvement_index(pimprove
)].turn
<= I_NEVER
) ? '0'
4705 } improvement_iterate_end
;
4706 impr_buf
[improvement_count()] = '\0';
4707 sg_failure_ret(strlen(impr_buf
) < sizeof(impr_buf
),
4708 "Invalid size of the improvement vector (%s.improvements: "
4709 "%lu < %lu).", buf
, (long unsigned int) strlen(impr_buf
),
4710 (long unsigned int) sizeof(impr_buf
));
4711 secfile_insert_str(saving
->file
, impr_buf
, "%s.improvements", buf
);
4713 worklist_save(saving
->file
, &pcity
->worklist
, wlist_max_length
, "%s",
4716 for (j
= 0; j
< CITYO_LAST
; j
++) {
4717 secfile_insert_bool(saving
->file
, BV_ISSET(pcity
->city_options
, j
),
4718 "%s.option%d", buf
, j
);
4721 CALL_FUNC_EACH_AI(city_save
, saving
->file
, pcity
, buf
);
4723 if (game
.info
.citizen_nationality
) {
4724 /* Save nationality of the citizens,*/
4725 players_iterate(pplayer
) {
4726 if (nations
[player_index(pplayer
)]) {
4727 secfile_insert_int(saving
->file
,
4728 citizens_nation_get(pcity
, pplayer
->slot
),
4729 "%s.citizen%d", buf
, player_index(pplayer
));
4731 } players_iterate_end
;
4735 } city_list_iterate_end
;
4738 /****************************************************************************
4740 ****************************************************************************/
4741 static void sg_load_player_units(struct loaddata
*loading
,
4744 int nunits
, i
, plrno
= player_number(plr
);
4746 /* Check status and return if not OK (sg_success != TRUE). */
4749 sg_failure_ret(secfile_lookup_int(loading
->file
, &nunits
,
4750 "player%d.nunits", plrno
),
4751 "%s", secfile_error());
4752 if (!plr
->is_alive
&& nunits
> 0) {
4753 log_sg("'player%d.nunits' = %d for dead player!", plrno
, nunits
);
4754 nunits
= 0; /* Some old savegames may be buggy. */
4757 for (i
= 0; i
< nunits
; i
++) {
4762 struct unit_type
*type
;
4765 fc_snprintf(buf
, sizeof(buf
), "player%d.u%d", plrno
, i
);
4767 name
= secfile_lookup_str(loading
->file
, "%s.type_by_name", buf
);
4768 type
= unit_type_by_rule_name(name
);
4769 sg_failure_ret(type
!= NULL
, "%s: unknown unit type \"%s\".", buf
, name
);
4771 /* Create a dummy unit. */
4772 punit
= unit_virtual_create(plr
, NULL
, type
, 0);
4773 if (!sg_load_player_unit(loading
, plr
, punit
, buf
)) {
4774 unit_virtual_destroy(punit
);
4775 sg_failure_ret(FALSE
, "Error loading unit %d of player %d.", i
, plrno
);
4778 identity_number_reserve(punit
->id
);
4779 idex_register_unit(punit
);
4781 if ((pcity
= game_city_by_number(punit
->homecity
))) {
4782 unit_list_prepend(pcity
->units_supported
, punit
);
4783 } else if (punit
->homecity
> IDENTITY_NUMBER_ZERO
) {
4784 log_sg("%s: bad home city %d.", buf
, punit
->homecity
);
4785 punit
->homecity
= IDENTITY_NUMBER_ZERO
;
4788 ptile
= unit_tile(punit
);
4790 /* allocate the unit's contribution to fog of war */
4791 punit
->server
.vision
= vision_new(unit_owner(punit
), ptile
);
4792 unit_refresh_vision(punit
);
4793 /* NOTE: There used to be some map_set_known calls here. These were
4794 * unneeded since unfogging the tile when the unit sees it will
4795 * automatically reveal that tile. */
4797 unit_list_append(plr
->units
, punit
);
4798 unit_list_prepend(unit_tile(punit
)->units
, punit
);
4800 /* Claim ownership of fortress? */
4801 if ((!base_owner(ptile
)
4802 || pplayers_at_war(base_owner(ptile
), plr
))
4803 && tile_has_claimable_base(ptile
, unit_type(punit
))) {
4804 struct player
*old_owner
= base_owner(ptile
);
4806 base_type_iterate(pbase
) {
4807 map_claim_base(ptile
, pbase
, plr
, old_owner
);
4808 } base_type_iterate_end
;
4813 /****************************************************************************
4814 Load one unit. sg_save_player_unit() is not defined.
4815 ****************************************************************************/
4816 static bool sg_load_player_unit(struct loaddata
*loading
,
4817 struct player
*plr
, struct unit
*punit
,
4818 const char *unitstr
)
4821 enum unit_activity activity
;
4823 enum tile_special_type target
;
4824 struct base_type
*pbase
= NULL
;
4825 struct road_type
*proad
= NULL
;
4830 const char *facing_str
;
4831 enum tile_special_type cfspe
;
4834 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &punit
->id
, "%s.id",
4835 unitstr
), FALSE
, "%s", secfile_error());
4836 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &nat_x
, "%s.x", unitstr
),
4837 FALSE
, "%s", secfile_error());
4838 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &nat_y
, "%s.y", unitstr
),
4839 FALSE
, "%s", secfile_error());
4841 ptile
= native_pos_to_tile(nat_x
, nat_y
);
4842 sg_warn_ret_val(NULL
!= ptile
, FALSE
, "%s invalid tile (%d, %d)",
4843 unitstr
, nat_x
, nat_y
);
4844 unit_tile_set(punit
, ptile
);
4847 = secfile_lookup_str_default(loading
->file
, "x",
4848 "%s.facing", unitstr
);
4849 if (facing_str
[0] != 'x') {
4850 /* We don't touch punit->facing if savegame does not contain that
4851 * information. Initial orientation set by unit_virtual_create()
4852 * is as good as any. */
4853 enum direction8 facing
= char2dir(facing_str
[0]);
4855 if (direction8_is_valid(facing
)) {
4856 punit
->facing
= facing
;
4858 log_error("Illegal unit orientation '%s'", facing_str
);
4862 /* If savegame has unit nationality, it doesn't hurt to
4863 * internally set it even if nationality rules are disabled. */
4864 natnbr
= secfile_lookup_int_default(loading
->file
,
4866 "%s.nationality", unitstr
);
4868 punit
->nationality
= player_by_number(natnbr
);
4869 if (punit
->nationality
== NULL
) {
4870 punit
->nationality
= plr
;
4873 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &punit
->homecity
,
4874 "%s.homecity", unitstr
), FALSE
,
4875 "%s", secfile_error());
4876 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &punit
->moves_left
,
4877 "%s.moves", unitstr
), FALSE
,
4878 "%s", secfile_error());
4879 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &punit
->fuel
,
4880 "%s.fuel", unitstr
), FALSE
,
4881 "%s", secfile_error());
4882 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &ei
,
4883 "%s.activity", unitstr
), FALSE
,
4884 "%s", secfile_error());
4887 punit
->server
.birth_turn
4888 = secfile_lookup_int_default(loading
->file
, game
.info
.turn
,
4889 "%s.born", unitstr
);
4890 base
= secfile_lookup_int_default(loading
->file
, -1,
4891 "%s.activity_base", unitstr
);
4892 if (base
>= 0 && base
< loading
->base
.size
) {
4893 pbase
= loading
->base
.order
[base
];
4895 road
= secfile_lookup_int_default(loading
->file
, -1,
4896 "%s.activity_road", unitstr
);
4897 if (road
>= 0 && road
< loading
->road
.size
) {
4898 proad
= loading
->road
.order
[road
];
4902 int tgt_no
= secfile_lookup_int_default(loading
->file
,
4903 loading
->special
.size
/* S_LAST */,
4904 "%s.activity_target", unitstr
);
4905 if (tgt_no
>= 0 && tgt_no
< loading
->special
.size
) {
4906 target
= loading
->special
.order
[tgt_no
];
4912 if (target
== S_OLD_ROAD
) {
4914 proad
= road_by_compat_special(ROCO_ROAD
);
4915 } else if (target
== S_OLD_RAILROAD
) {
4917 proad
= road_by_compat_special(ROCO_RAILROAD
);
4920 if (activity
== ACTIVITY_PATROL_UNUSED
) {
4921 /* Previously ACTIVITY_PATROL and ACTIVITY_GOTO were used for
4922 * client-side goto. Now client-side goto is handled by setting
4923 * a special flag, and units with orders generally have ACTIVITY_IDLE.
4924 * Old orders are lost. Old client-side goto units will still have
4925 * ACTIVITY_GOTO and will goto the correct position via server goto.
4926 * Old client-side patrol units lose their patrol routes and are put
4927 * into idle mode. */
4928 activity
= ACTIVITY_IDLE
;
4931 if (activity
== ACTIVITY_FORTRESS
) {
4932 activity
= ACTIVITY_BASE
;
4933 pbase
= get_base_by_gui_type(BASE_GUI_FORTRESS
, punit
, unit_tile(punit
));
4934 } else if (activity
== ACTIVITY_AIRBASE
) {
4935 activity
= ACTIVITY_BASE
;
4936 pbase
= get_base_by_gui_type(BASE_GUI_AIRBASE
, punit
, unit_tile(punit
));
4939 if (activity
== ACTIVITY_OLD_ROAD
) {
4940 activity
= ACTIVITY_GEN_ROAD
;
4941 proad
= road_by_compat_special(ROCO_ROAD
);
4942 } else if (activity
== ACTIVITY_OLD_RAILROAD
) {
4943 activity
= ACTIVITY_GEN_ROAD
;
4944 proad
= road_by_compat_special(ROCO_RAILROAD
);
4947 /* We need changed_from == ACTIVITY_IDLE by now so that
4948 * set_unit_activity() and friends don't spuriously restore activity
4949 * points -- unit should have been created this way */
4950 fc_assert(punit
->changed_from
== ACTIVITY_IDLE
);
4952 if (activity
== ACTIVITY_BASE
) {
4954 set_unit_activity_base(punit
, base_number(pbase
));
4956 log_sg("Cannot find base %d for %s to build",
4957 base
, unit_rule_name(punit
));
4958 set_unit_activity(punit
, ACTIVITY_IDLE
);
4960 } else if (activity
== ACTIVITY_GEN_ROAD
) {
4962 set_unit_activity_road(punit
, road_number(proad
));
4964 log_sg("Cannot find road %d for %s to build",
4965 road
, unit_rule_name(punit
));
4966 set_unit_activity(punit
, ACTIVITY_IDLE
);
4968 } else if (activity
== ACTIVITY_PILLAGE
) {
4969 struct act_tgt a_target
;
4971 if (target
!= S_LAST
) {
4972 a_target
.type
= ATT_SPECIAL
;
4973 a_target
.obj
.spe
= target
;
4974 } else if (pbase
!= NULL
) {
4975 a_target
.type
= ATT_BASE
;
4976 a_target
.obj
.base
= base_index(pbase
);
4977 } else if (proad
!= NULL
) {
4978 a_target
.type
= ATT_ROAD
;
4979 a_target
.obj
.road
= road_index(proad
);
4981 a_target
.type
= ATT_SPECIAL
;
4982 a_target
.obj
.spe
= S_LAST
;
4984 /* An out-of-range base number is seen with old savegames. We take
4985 * it as indicating undirected pillaging. We will assign pillage
4986 * targets before play starts. */
4987 set_unit_activity_targeted(punit
, activity
, &a_target
);
4989 set_unit_activity(punit
, activity
);
4992 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &punit
->activity_count
,
4993 "%s.activity_count", unitstr
), FALSE
,
4994 "%s", secfile_error());
4996 punit
->changed_from
=
4997 secfile_lookup_int_default(loading
->file
, ACTIVITY_IDLE
,
4998 "%s.changed_from", unitstr
);
5000 secfile_lookup_int_default(loading
->file
, S_LAST
,
5001 "%s.changed_from_target", unitstr
);
5003 secfile_lookup_int_default(loading
->file
, -1,
5004 "%s.changed_from_base", unitstr
);
5006 secfile_lookup_int_default(loading
->file
, -1,
5007 "%s.changed_from_road", unitstr
);
5010 if (cfspe
== S_OLD_ROAD
) {
5011 proad
= road_by_compat_special(ROCO_ROAD
);
5013 road
= road_index(proad
);
5015 } else if (cfspe
== S_OLD_RAILROAD
) {
5016 proad
= road_by_compat_special(ROCO_RAILROAD
);
5018 road
= road_index(proad
);
5023 if (base
>= 0 && base
< loading
->base
.size
) {
5024 punit
->changed_from_target
.type
= ATT_BASE
;
5025 punit
->changed_from_target
.obj
.base
= base_number(loading
->base
.order
[base
]);
5026 } else if (road
>= 0 && road
< loading
->road
.size
) {
5027 punit
->changed_from_target
.type
= ATT_ROAD
;
5028 punit
->changed_from_target
.obj
.road
= road_number(loading
->road
.order
[road
]);
5030 punit
->changed_from_target
.type
= ATT_SPECIAL
;
5031 punit
->changed_from_target
.obj
.spe
= cfspe
;
5033 punit
->changed_from_count
=
5034 secfile_lookup_int_default(loading
->file
, 0,
5035 "%s.changed_from_count", unitstr
);
5037 /* Special case: for a long time, we accidentally incremented
5038 * activity_count while a unit was sentried, so it could increase
5039 * without bound (bug #20641) and be saved in old savefiles.
5040 * We zero it to prevent potential trouble overflowing the range
5041 * in network packets, etc. */
5042 if (activity
== ACTIVITY_SENTRY
) {
5043 punit
->activity_count
= 0;
5045 if (punit
->changed_from
== ACTIVITY_SENTRY
) {
5046 punit
->changed_from_count
= 0;
5050 = secfile_lookup_int_default(loading
->file
, 0, "%s.veteran", unitstr
);
5052 /* Protect against change in veteran system in ruleset */
5053 const int levels
= utype_veteran_levels(unit_type(punit
));
5054 if (punit
->veteran
>= levels
) {
5055 fc_assert(levels
>= 1);
5056 punit
->veteran
= levels
- 1;
5060 = secfile_lookup_bool_default(loading
->file
, (punit
->moves_left
== 0),
5061 "%s.done_moving", unitstr
);
5063 = secfile_lookup_int_default(loading
->file
, BATTLEGROUP_NONE
,
5064 "%s.battlegroup", unitstr
);
5066 if (secfile_lookup_bool_default(loading
->file
, FALSE
,
5067 "%s.go", unitstr
)) {
5070 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &nat_x
,
5071 "%s.goto_x", unitstr
), FALSE
,
5072 "%s", secfile_error());
5073 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &nat_y
,
5074 "%s.goto_y", unitstr
), FALSE
,
5075 "%s", secfile_error());
5077 punit
->goto_tile
= native_pos_to_tile(nat_x
, nat_y
);
5079 punit
->goto_tile
= NULL
;
5081 /* This variables are not used but needed for saving the unit table.
5082 * Load them to prevent unused variables errors. */
5083 (void) secfile_entry_lookup(loading
->file
, "%s.goto_x", unitstr
);
5084 (void) secfile_entry_lookup(loading
->file
, "%s.goto_y", unitstr
);
5087 /* Load AI data of the unit. */
5088 CALL_FUNC_EACH_AI(unit_load
, loading
->file
, punit
, unitstr
);
5090 sg_warn_ret_val(secfile_lookup_bool(loading
->file
,
5091 &punit
->ai_controlled
,
5092 "%s.ai", unitstr
), FALSE
,
5093 "%s", secfile_error());
5094 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &punit
->hp
,
5095 "%s.hp", unitstr
), FALSE
,
5096 "%s", secfile_error());
5098 punit
->server
.ord_map
5099 = secfile_lookup_int_default(loading
->file
, 0, "%s.ord_map", unitstr
);
5100 punit
->server
.ord_city
5101 = secfile_lookup_int_default(loading
->file
, 0, "%s.ord_city", unitstr
);
5103 = secfile_lookup_bool_default(loading
->file
, FALSE
, "%s.moved", unitstr
);
5105 = secfile_lookup_bool_default(loading
->file
, FALSE
,
5106 "%s.paradropped", unitstr
);
5108 /* The transport status (punit->transported_by) is loaded in
5109 * sg_player_units_transport(). */
5111 /* Initialize upkeep values: these are hopefully initialized
5112 * elsewhere before use (specifically, in city_support(); but
5113 * fixme: check whether always correctly initialized?).
5114 * Below is mainly for units which don't have homecity --
5115 * otherwise these don't get initialized (and AI calculations
5116 * etc may use junk values). */
5117 output_type_iterate(o
) {
5118 punit
->upkeep
[o
] = utype_upkeep_cost(unit_type(punit
), plr
, o
);
5119 } output_type_iterate_end
;
5121 /* load the unit orders */
5123 int len
= secfile_lookup_int_default(loading
->file
, 0,
5124 "%s.orders_length", unitstr
);
5126 const char *orders_unitstr
, *dir_unitstr
, *act_unitstr
, *base_unitstr
;
5127 const char *road_unitstr
;
5128 int road_idx
= road_index(road_by_compat_special(ROCO_ROAD
));
5129 int rail_idx
= road_index(road_by_compat_special(ROCO_RAILROAD
));
5131 punit
->orders
.list
= fc_malloc(len
* sizeof(*(punit
->orders
.list
)));
5132 punit
->orders
.length
= len
;
5134 = secfile_lookup_int_default(loading
->file
, 0,
5135 "%s.orders_index", unitstr
);
5136 punit
->orders
.repeat
5137 = secfile_lookup_bool_default(loading
->file
, FALSE
,
5138 "%s.orders_repeat", unitstr
);
5139 punit
->orders
.vigilant
5140 = secfile_lookup_bool_default(loading
->file
, FALSE
,
5141 "%s.orders_vigilant", unitstr
);
5142 punit
->server
.last_order_move_is_safe
5143 = secfile_lookup_bool_default(loading
->file
, FALSE
,
5144 "%s.orders_last_move_safe", unitstr
);
5147 = secfile_lookup_str_default(loading
->file
, "",
5148 "%s.orders_list", unitstr
);
5150 = secfile_lookup_str_default(loading
->file
, "",
5151 "%s.dir_list", unitstr
);
5153 = secfile_lookup_str_default(loading
->file
, "",
5154 "%s.activity_list", unitstr
);
5156 = secfile_lookup_str(loading
->file
, "%s.base_list", unitstr
);
5158 = secfile_lookup_str_default(loading
->file
, NULL
, "%s.road_list", unitstr
);
5160 punit
->has_orders
= TRUE
;
5161 for (j
= 0; j
< len
; j
++) {
5162 struct unit_order
*order
= &punit
->orders
.list
[j
];
5164 if (orders_unitstr
[j
] == '\0' || dir_unitstr
[j
] == '\0'
5165 || act_unitstr
[j
] == '\0') {
5166 log_sg("Invalid unit orders.");
5167 free_unit_orders(punit
);
5170 order
->order
= char2order(orders_unitstr
[j
]);
5171 order
->dir
= char2dir(dir_unitstr
[j
]);
5172 order
->activity
= char2activity(act_unitstr
[j
]);
5173 if (order
->order
== ORDER_LAST
5174 || (order
->order
== ORDER_MOVE
&& !direction8_is_valid(order
->dir
))
5175 || (order
->order
== ORDER_ACTIVITY
5176 && order
->activity
== ACTIVITY_LAST
)) {
5177 /* An invalid order. Just drop the orders for this unit. */
5178 free(punit
->orders
.list
);
5179 punit
->orders
.list
= NULL
;
5180 punit
->has_orders
= FALSE
;
5184 if (base_unitstr
&& base_unitstr
[j
] != '?') {
5185 base
= char2num(base_unitstr
[j
]);
5187 if (base
< 0 || base
>= loading
->base
.size
) {
5188 log_sg("Cannot find base %d for %s to build",
5189 base
, unit_rule_name(punit
));
5190 base
= base_number(get_base_by_gui_type(BASE_GUI_FORTRESS
,
5196 order
->base
= BASE_NONE
;
5199 if (road_unitstr
&& road_unitstr
[j
] != '?') {
5200 road
= char2num(road_unitstr
[j
]);
5202 if (road
< 0 || road
>= loading
->road
.size
) {
5203 log_sg("Cannot find road %d for %s to build",
5204 road
, unit_rule_name(punit
));
5210 order
->road
= ROAD_NONE
;
5213 if (order
->activity
== ACTIVITY_OLD_ROAD
) {
5214 order
->activity
= ACTIVITY_GEN_ROAD
;
5215 order
->road
= road_idx
;
5216 } else if (order
->activity
== ACTIVITY_OLD_RAILROAD
) {
5217 order
->activity
= ACTIVITY_GEN_ROAD
;
5218 order
->road
= rail_idx
;
5222 punit
->has_orders
= FALSE
;
5223 punit
->orders
.list
= NULL
;
5230 /*****************************************************************************
5231 Load the transport status of all units. This is seperated from the other
5232 code as all units must be known.
5233 *****************************************************************************/
5234 static void sg_load_player_units_transport(struct loaddata
*loading
,
5237 int nunits
, i
, plrno
= player_number(plr
);
5239 /* Check status and return if not OK (sg_success != TRUE). */
5242 /* Recheck the number of units for the player. This is a copied from
5243 * sg_load_player_units(). */
5244 sg_failure_ret(secfile_lookup_int(loading
->file
, &nunits
,
5245 "player%d.nunits", plrno
),
5246 "%s", secfile_error());
5247 if (!plr
->is_alive
&& nunits
> 0) {
5248 log_sg("'player%d.nunits' = %d for dead player!", plrno
, nunits
);
5249 nunits
= 0; /* Some old savegames may be buggy. */
5252 for (i
= 0; i
< nunits
; i
++) {
5253 int id_unit
, id_trans
;
5254 struct unit
*punit
, *ptrans
;
5256 id_unit
= secfile_lookup_int_default(loading
->file
, -1,
5259 punit
= player_unit_by_number(plr
, id_unit
);
5260 fc_assert_action(punit
!= NULL
, continue);
5262 id_trans
= secfile_lookup_int_default(loading
->file
, -1,
5263 "player%d.u%d.transported_by",
5265 if (id_trans
== -1) {
5266 /* Not transported. */
5270 ptrans
= game_unit_by_number(id_trans
);
5271 fc_assert_action(id_trans
== -1 || ptrans
!= NULL
, continue);
5274 fc_assert_action(unit_transport_load(punit
, ptrans
, TRUE
), continue);
5279 /****************************************************************************
5281 ****************************************************************************/
5282 static void sg_save_player_units(struct savedata
*saving
,
5287 /* Check status and return if not OK (sg_success != TRUE). */
5290 secfile_insert_int(saving
->file
, unit_list_size(plr
->units
),
5291 "player%d.nunits", player_number(plr
));
5293 unit_list_iterate(plr
->units
, punit
) {
5295 char dirbuf
[2] = " ";
5298 fc_snprintf(buf
, sizeof(buf
), "player%d.u%d", player_number(plr
), i
);
5299 dirbuf
[0] = dir2char(punit
->facing
);
5300 secfile_insert_int(saving
->file
, punit
->id
, "%s.id", buf
);
5302 index_to_native_pos(&nat_x
, &nat_y
, tile_index(unit_tile(punit
)));
5303 secfile_insert_int(saving
->file
, nat_x
, "%s.x", buf
);
5304 secfile_insert_int(saving
->file
, nat_y
, "%s.y", buf
);
5306 secfile_insert_str(saving
->file
, dirbuf
, "%s.facing", buf
);
5307 if (game
.info
.citizen_nationality
) {
5308 secfile_insert_int(saving
->file
, player_number(unit_nationality(punit
)),
5309 "%s.nationality", buf
);
5311 secfile_insert_int(saving
->file
, punit
->veteran
, "%s.veteran", buf
);
5312 secfile_insert_int(saving
->file
, punit
->hp
, "%s.hp", buf
);
5313 secfile_insert_int(saving
->file
, punit
->homecity
, "%s.homecity", buf
);
5314 secfile_insert_str(saving
->file
, unit_rule_name(punit
),
5315 "%s.type_by_name", buf
);
5317 secfile_insert_int(saving
->file
, punit
->activity
, "%s.activity", buf
);
5318 secfile_insert_int(saving
->file
, punit
->activity_count
,
5319 "%s.activity_count", buf
);
5320 if (punit
->activity_target
.type
== ATT_SPECIAL
) {
5321 secfile_insert_int(saving
->file
, punit
->activity_target
.obj
.spe
,
5322 "%s.activity_target", buf
);
5324 secfile_insert_int(saving
->file
, S_LAST
,
5325 "%s.activity_target", buf
);
5327 if (punit
->activity_target
.type
== ATT_BASE
) {
5328 secfile_insert_int(saving
->file
, punit
->activity_target
.obj
.base
,
5329 "%s.activity_base", buf
);
5331 secfile_insert_int(saving
->file
, BASE_NONE
,
5332 "%s.activity_base", buf
);
5334 if (punit
->activity_target
.type
== ATT_ROAD
) {
5335 secfile_insert_int(saving
->file
, punit
->activity_target
.obj
.road
,
5336 "%s.activity_road", buf
);
5338 secfile_insert_int(saving
->file
, ROAD_NONE
,
5339 "%s.activity_road", buf
);
5341 secfile_insert_int(saving
->file
, punit
->changed_from
,
5342 "%s.changed_from", buf
);
5343 secfile_insert_int(saving
->file
, punit
->changed_from_count
,
5344 "%s.changed_from_count", buf
);
5345 if (punit
->changed_from_target
.type
== ATT_SPECIAL
) {
5346 secfile_insert_int(saving
->file
, punit
->changed_from_target
.obj
.spe
,
5347 "%s.changed_from_target", buf
);
5349 secfile_insert_int(saving
->file
, S_LAST
,
5350 "%s.changed_from_target", buf
);
5352 if (punit
->changed_from_target
.type
== ATT_BASE
) {
5353 secfile_insert_int(saving
->file
, punit
->changed_from_target
.obj
.base
,
5354 "%s.changed_from_base", buf
);
5356 secfile_insert_int(saving
->file
, BASE_NONE
,
5357 "%s.changed_from_base", buf
);
5359 if (punit
->changed_from_target
.type
== ATT_ROAD
) {
5360 secfile_insert_int(saving
->file
, punit
->changed_from_target
.obj
.road
,
5361 "%s.changed_from_road", buf
);
5363 secfile_insert_int(saving
->file
, ROAD_NONE
,
5364 "%s.changed_from_road", buf
);
5366 secfile_insert_bool(saving
->file
, punit
->done_moving
,
5367 "%s.done_moving", buf
);
5368 secfile_insert_int(saving
->file
, punit
->moves_left
, "%s.moves", buf
);
5369 secfile_insert_int(saving
->file
, punit
->fuel
, "%s.fuel", buf
);
5370 secfile_insert_int(saving
->file
, punit
->server
.birth_turn
,
5372 secfile_insert_int(saving
->file
, punit
->battlegroup
,
5373 "%s.battlegroup", buf
);
5375 if (punit
->goto_tile
) {
5376 index_to_native_pos(&nat_x
, &nat_y
, tile_index(punit
->goto_tile
));
5377 secfile_insert_bool(saving
->file
, TRUE
, "%s.go", buf
);
5378 secfile_insert_int(saving
->file
, nat_x
, "%s.goto_x", buf
);
5379 secfile_insert_int(saving
->file
, nat_y
, "%s.goto_y", buf
);
5381 secfile_insert_bool(saving
->file
, FALSE
, "%s.go", buf
);
5382 /* Set this values to allow saving it as table. */
5383 secfile_insert_int(saving
->file
, 0, "%s.goto_x", buf
);
5384 secfile_insert_int(saving
->file
, 0, "%s.goto_y", buf
);
5387 secfile_insert_bool(saving
->file
, punit
->ai_controlled
,
5390 /* Save AI data of the unit. */
5391 CALL_FUNC_EACH_AI(unit_save
, saving
->file
, punit
, buf
);
5393 secfile_insert_int(saving
->file
, punit
->server
.ord_map
,
5395 secfile_insert_int(saving
->file
, punit
->server
.ord_city
,
5396 "%s.ord_city", buf
);
5397 secfile_insert_bool(saving
->file
, punit
->moved
, "%s.moved", buf
);
5398 secfile_insert_bool(saving
->file
, punit
->paradropped
,
5399 "%s.paradropped", buf
);
5400 secfile_insert_int(saving
->file
, unit_transport_get(punit
)
5401 ? unit_transport_get(punit
)->id
: -1,
5402 "%s.transported_by", buf
);
5404 if (punit
->has_orders
) {
5405 int len
= punit
->orders
.length
, j
;
5406 char orders_buf
[len
+ 1], dir_buf
[len
+ 1];
5407 char act_buf
[len
+ 1], base_buf
[len
+ 1];
5408 char road_buf
[len
+ 1];
5410 secfile_insert_int(saving
->file
, len
, "%s.orders_length", buf
);
5411 secfile_insert_int(saving
->file
, punit
->orders
.index
,
5412 "%s.orders_index", buf
);
5413 secfile_insert_bool(saving
->file
, punit
->orders
.repeat
,
5414 "%s.orders_repeat", buf
);
5415 secfile_insert_bool(saving
->file
, punit
->orders
.vigilant
,
5416 "%s.orders_vigilant", buf
);
5417 secfile_insert_bool(saving
->file
,
5418 punit
->server
.last_order_move_is_safe
,
5419 "%s.orders_last_move_safe", buf
);
5421 for (j
= 0; j
< len
; j
++) {
5422 orders_buf
[j
] = order2char(punit
->orders
.list
[j
].order
);
5427 switch (punit
->orders
.list
[j
].order
) {
5429 dir_buf
[j
] = dir2char(punit
->orders
.list
[j
].dir
);
5431 case ORDER_ACTIVITY
:
5432 if (punit
->orders
.list
[j
].activity
== ACTIVITY_BASE
) {
5433 base_buf
[j
] = num2char(punit
->orders
.list
[j
].base
);
5434 } else if (punit
->orders
.list
[j
].activity
== ACTIVITY_GEN_ROAD
) {
5435 road_buf
[j
] = num2char(punit
->orders
.list
[j
].road
);
5437 act_buf
[j
] = activity2char(punit
->orders
.list
[j
].activity
);
5440 case ORDER_BUILD_CITY
:
5442 case ORDER_BUILD_WONDER
:
5443 case ORDER_TRADE_ROUTE
:
5444 case ORDER_HOMECITY
:
5449 orders_buf
[len
] = dir_buf
[len
] = act_buf
[len
] = base_buf
[len
] = '\0';
5450 road_buf
[len
] = '\0';
5452 secfile_insert_str(saving
->file
, orders_buf
, "%s.orders_list", buf
);
5453 secfile_insert_str(saving
->file
, dir_buf
, "%s.dir_list", buf
);
5454 secfile_insert_str(saving
->file
, act_buf
, "%s.activity_list", buf
);
5455 secfile_insert_str(saving
->file
, base_buf
, "%s.base_list", buf
);
5456 secfile_insert_str(saving
->file
, road_buf
, "%s.road_list", buf
);
5458 /* Put all the same fields into the savegame - otherwise the
5459 * registry code can't correctly use a tabular format and the
5460 * savegame will be bigger. */
5461 secfile_insert_int(saving
->file
, 0, "%s.orders_length", buf
);
5462 secfile_insert_int(saving
->file
, 0, "%s.orders_index", buf
);
5463 secfile_insert_bool(saving
->file
, FALSE
, "%s.orders_repeat", buf
);
5464 secfile_insert_bool(saving
->file
, FALSE
, "%s.orders_vigilant", buf
);
5465 secfile_insert_bool(saving
->file
, FALSE
,
5466 "%s.orders_last_move_safe", buf
);
5467 secfile_insert_str(saving
->file
, "-", "%s.orders_list", buf
);
5468 secfile_insert_str(saving
->file
, "-", "%s.dir_list", buf
);
5469 secfile_insert_str(saving
->file
, "-", "%s.activity_list", buf
);
5470 secfile_insert_str(saving
->file
, "-", "%s.base_list", buf
);
5471 secfile_insert_str(saving
->file
, "-", "%s.road_list", buf
);
5475 } unit_list_iterate_end
;
5478 /****************************************************************************
5479 Load player (client) attributes data
5480 ****************************************************************************/
5481 static void sg_load_player_attributes(struct loaddata
*loading
,
5484 int plrno
= player_number(plr
);
5486 /* Check status and return if not OK (sg_success != TRUE). */
5489 /* Toss any existing attribute_block (should not exist) */
5490 if (plr
->attribute_block
.data
) {
5491 free(plr
->attribute_block
.data
);
5492 plr
->attribute_block
.data
= NULL
;
5495 /* This is a big heap of opaque data for the client, check everything! */
5496 plr
->attribute_block
.length
= secfile_lookup_int_default(
5497 loading
->file
, 0, "player%d.attribute_v2_block_length", plrno
);
5499 if (0 > plr
->attribute_block
.length
) {
5500 log_sg("player%d.attribute_v2_block_length=%d too small", plrno
,
5501 plr
->attribute_block
.length
);
5502 plr
->attribute_block
.length
= 0;
5503 } else if (MAX_ATTRIBUTE_BLOCK
< plr
->attribute_block
.length
) {
5504 log_sg("player%d.attribute_v2_block_length=%d too big (max %d)",
5505 plrno
, plr
->attribute_block
.length
, MAX_ATTRIBUTE_BLOCK
);
5506 plr
->attribute_block
.length
= 0;
5507 } else if (0 < plr
->attribute_block
.length
) {
5509 size_t actual_length
;
5514 secfile_lookup_int(loading
->file
, "ed_length
,
5515 "player%d.attribute_v2_block_length_quoted",
5516 plrno
), "%s", secfile_error());
5518 secfile_lookup_int(loading
->file
, &parts
,
5519 "player%d.attribute_v2_block_parts", plrno
),
5520 "%s", secfile_error());
5522 quoted
= fc_malloc(quoted_length
+ 1);
5524 plr
->attribute_block
.data
= fc_malloc(plr
->attribute_block
.length
);
5525 for (part_nr
= 0; part_nr
< parts
; part_nr
++) {
5526 const char *current
=
5527 secfile_lookup_str(loading
->file
,
5528 "player%d.attribute_v2_block_data.part%d",
5531 log_sg("attribute_v2_block_parts=%d actual=%d", parts
, part_nr
);
5534 log_debug("attribute_v2_block_length_quoted=%lu have=%lu part=%lu",
5535 (unsigned long) quoted_length
,
5536 (unsigned long) strlen(quoted
),
5537 (unsigned long) strlen(current
));
5538 fc_assert(strlen(quoted
) + strlen(current
) <= quoted_length
);
5539 strcat(quoted
, current
);
5541 fc_assert_msg(quoted_length
== strlen(quoted
),
5542 "attribute_v2_block_length_quoted=%lu actual=%lu",
5543 (unsigned long) quoted_length
,
5544 (unsigned long) strlen(quoted
));
5547 unquote_block(quoted
,
5548 plr
->attribute_block
.data
,
5549 plr
->attribute_block
.length
);
5550 fc_assert(actual_length
== plr
->attribute_block
.length
);
5555 /****************************************************************************
5556 Save player (client) attributes data.
5557 ****************************************************************************/
5558 static void sg_save_player_attributes(struct savedata
*saving
,
5561 int plrno
= player_number(plr
);
5563 /* Check status and return if not OK (sg_success != TRUE). */
5566 /* This is a big heap of opaque data from the client. Although the binary
5567 * format is not user editable, keep the lines short enough for debugging,
5568 * and hope that data compression will keep the file a reasonable size.
5569 * Note that the "quoted" format is a multiple of 3.
5571 #define PART_SIZE (3*256)
5572 #define PART_ADJUST (3)
5573 if (plr
->attribute_block
.data
) {
5574 char part
[PART_SIZE
+ PART_ADJUST
];
5576 int current_part_nr
;
5577 char *quoted
= quote_block(plr
->attribute_block
.data
,
5578 plr
->attribute_block
.length
);
5579 char *quoted_at
= strchr(quoted
, ':');
5580 size_t bytes_left
= strlen(quoted
);
5581 size_t bytes_at_colon
= 1 + (quoted_at
- quoted
);
5582 size_t bytes_adjust
= bytes_at_colon
% PART_ADJUST
;
5584 secfile_insert_int(saving
->file
, plr
->attribute_block
.length
,
5585 "player%d.attribute_v2_block_length", plrno
);
5586 secfile_insert_int(saving
->file
, bytes_left
,
5587 "player%d.attribute_v2_block_length_quoted", plrno
);
5589 /* Try to wring some compression efficiencies out of the "quoted" format.
5590 * The first line has a variable length decimal, mis-aligning triples.
5592 if ((bytes_left
- bytes_adjust
) > PART_SIZE
) {
5593 /* first line can be longer */
5594 parts
= 1 + (bytes_left
- bytes_adjust
- 1) / PART_SIZE
;
5599 secfile_insert_int(saving
->file
, parts
,
5600 "player%d.attribute_v2_block_parts", plrno
);
5603 size_t size_of_current_part
= PART_SIZE
+ bytes_adjust
;
5605 /* first line can be longer */
5606 memcpy(part
, quoted
, size_of_current_part
);
5607 part
[size_of_current_part
] = '\0';
5608 secfile_insert_str(saving
->file
, part
,
5609 "player%d.attribute_v2_block_data.part%d",
5611 bytes_left
-= size_of_current_part
;
5612 quoted_at
= "ed
[size_of_current_part
];
5613 current_part_nr
= 1;
5616 current_part_nr
= 0;
5619 for (; current_part_nr
< parts
; current_part_nr
++) {
5620 size_t size_of_current_part
= MIN(bytes_left
, PART_SIZE
);
5622 memcpy(part
, quoted_at
, size_of_current_part
);
5623 part
[size_of_current_part
] = '\0';
5624 secfile_insert_str(saving
->file
, part
,
5625 "player%d.attribute_v2_block_data.part%d",
5628 bytes_left
-= size_of_current_part
;
5629 quoted_at
= "ed_at
[size_of_current_part
];
5631 fc_assert(bytes_left
== 0);
5638 /****************************************************************************
5640 ****************************************************************************/
5641 static void sg_load_player_vision(struct loaddata
*loading
,
5644 int plrno
= player_number(plr
);
5646 secfile_lookup_int_default(loading
->file
, -1,
5647 "player%d.dc_total", plrno
);
5650 /* Check status and return if not OK (sg_success != TRUE). */
5653 if (!plr
->is_alive
) {
5654 /* Reveal all for dead players. */
5655 map_know_and_see_all(plr
);
5659 || -1 == total_ncities
5660 || FALSE
== game
.info
.fogofwar
5661 || !secfile_lookup_bool_default(loading
->file
, TRUE
,
5662 "game.save_private_map")) {
5665 * - fogged cities are not saved for any reason;
5666 * - a savegame with fog of war turned off;
5667 * - or game.save_private_map is not set to FALSE in the scenario /
5668 * savegame. The players private knowledge is set to be what he could
5669 * see without fog of war. */
5670 whole_map_iterate(ptile
) {
5671 if (map_is_known(ptile
, plr
)) {
5672 struct city
*pcity
= tile_city(ptile
);
5674 update_player_tile_last_seen(plr
, ptile
);
5675 update_player_tile_knowledge(plr
, ptile
);
5677 if (NULL
!= pcity
) {
5678 update_dumb_city(plr
, pcity
);
5681 } whole_map_iterate_end
;
5683 /* Nothing more to do; */
5687 /* Load player map (terrain). */
5688 LOAD_MAP_CHAR(ch
, ptile
,
5689 map_get_player_tile(ptile
, plr
)->terrain
5690 = char2terrain(ch
), loading
->file
,
5691 "player%d.map_t%04d", plrno
);
5693 /* Load player map (resources). */
5694 LOAD_MAP_CHAR(ch
, ptile
,
5695 map_get_player_tile(ptile
, plr
)->resource
5696 = char2resource(ch
), loading
->file
,
5697 "player%d.map_res%04d", plrno
);
5699 /* Load player map (specials). */
5700 halfbyte_iterate_special(j
, loading
->special
.size
) {
5701 LOAD_MAP_CHAR(ch
, ptile
,
5703 &map_get_player_tile(ptile
, plr
)->special
,
5704 &map_get_player_tile(ptile
, plr
)->roads
,
5705 ch
, loading
->special
.order
+ 4 * j
, FALSE
),
5706 loading
->file
, "player%d.map_spe%02d_%04d", plrno
, j
);
5707 } halfbyte_iterate_special_end
;
5709 /* Load player map (bases). */
5710 halfbyte_iterate_bases(j
, loading
->base
.size
) {
5711 LOAD_MAP_CHAR(ch
, ptile
,
5712 sg_bases_set(&map_get_player_tile(ptile
, plr
)->bases
,
5713 ch
, loading
->base
.order
+ 4 * j
),
5714 loading
->file
, "player%d.map_b%02d_%04d", plrno
, j
);
5715 } halfbyte_iterate_bases_end
;
5717 /* Load player map (roads). */
5718 if (loading
->version
>= 20) {
5719 /* 2.5.0 or newer */
5720 halfbyte_iterate_roads(j
, loading
->road
.size
) {
5721 LOAD_MAP_CHAR(ch
, ptile
,
5722 sg_roads_set(&map_get_player_tile(ptile
, plr
)->roads
,
5723 ch
, loading
->road
.order
+ 4 * j
),
5724 loading
->file
, "player%d.map_r%02d_%04d", plrno
, j
);
5725 } halfbyte_iterate_roads_end
;
5728 if (game
.server
.foggedborders
) {
5729 /* Load player map (border). */
5732 for (y
= 0; y
< map
.ysize
; y
++) {
5734 = secfile_lookup_str(loading
->file
, "player%d.map_owner%04d",
5736 const char *ptr
= buffer
;
5738 sg_failure_ret(NULL
!= buffer
,
5739 "Savegame corrupt - map line %d not found.", y
);
5740 for (x
= 0; x
< map
.xsize
; x
++) {
5741 char token
[TOKEN_SIZE
];
5743 struct tile
*ptile
= native_pos_to_tile(x
, y
);
5745 scanin(&ptr
, ",", token
, sizeof(token
));
5746 sg_failure_ret('\0' != token
[0],
5747 "Savegame corrupt - map size not correct.");
5748 if (strcmp(token
, "-") == 0) {
5749 map_get_player_tile(ptile
, plr
)->owner
= NULL
;
5753 sg_failure_ret(str_to_int(token
, &number
),
5754 "Savegame corrupt - got tile owner=%s in (%d, %d).",
5756 map_get_player_tile(ptile
, plr
)->owner
= player_by_number(number
);
5761 /* Load player map (update time). */
5762 for (i
= 0; i
< 4; i
++) {
5763 /* put 4-bit segments of 16-bit "updated" field */
5765 LOAD_MAP_CHAR(ch
, ptile
,
5766 map_get_player_tile(ptile
, plr
)->last_updated
5767 = ascii_hex2bin(ch
, i
),
5768 loading
->file
, "player%d.map_u%02d_%04d", plrno
, i
);
5770 LOAD_MAP_CHAR(ch
, ptile
,
5771 map_get_player_tile(ptile
, plr
)->last_updated
5772 |= ascii_hex2bin(ch
, i
),
5773 loading
->file
, "player%d.map_u%02d_%04d", plrno
, i
);
5777 /* Load player map known cities. */
5778 for (i
= 0; i
< total_ncities
; i
++) {
5779 struct vision_site
*pdcity
;
5781 fc_snprintf(buf
, sizeof(buf
), "player%d.dc%d", plrno
, i
);
5783 pdcity
= vision_site_new(0, NULL
, NULL
);
5784 if (sg_load_player_vision_city(loading
, plr
, pdcity
, buf
)) {
5785 change_playertile_site(map_get_player_tile(pdcity
->location
, plr
),
5787 identity_number_reserve(pdcity
->identity
);
5789 /* Error loading the data. */
5790 log_sg("Skipping seen city %d for player %d.", i
, plrno
);
5791 if (pdcity
!= NULL
) {
5792 vision_site_destroy(pdcity
);
5797 /* Repair inconsistent player maps. */
5798 whole_map_iterate(ptile
) {
5799 if (map_is_known_and_seen(ptile
, plr
, V_MAIN
)) {
5800 struct city
*pcity
= tile_city(ptile
);
5802 update_player_tile_knowledge(plr
, ptile
);
5803 reality_check_city(plr
, ptile
);
5805 if (NULL
!= pcity
) {
5806 update_dumb_city(plr
, pcity
);
5809 } whole_map_iterate_end
;
5812 /****************************************************************************
5813 Load data for one seen city. sg_save_player_vision_city() is not defined.
5814 ****************************************************************************/
5815 static bool sg_load_player_vision_city(struct loaddata
*loading
,
5817 struct vision_site
*pdcity
,
5818 const char *citystr
)
5825 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &nat_x
, "%s.x",
5827 FALSE
, "%s", secfile_error());
5828 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &nat_y
, "%s.y",
5830 FALSE
, "%s", secfile_error());
5831 pdcity
->location
= native_pos_to_tile(nat_x
, nat_y
);
5832 sg_warn_ret_val(NULL
!= pdcity
->location
, FALSE
,
5833 "%s invalid tile (%d,%d)", citystr
, nat_x
, nat_y
);
5835 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &id
, "%s.owner",
5837 FALSE
, "%s", secfile_error());
5838 pdcity
->owner
= player_by_number(id
);
5839 sg_warn_ret_val(NULL
!= pdcity
->owner
, FALSE
,
5840 "%s has invalid owner (%d); skipping.", citystr
, id
);
5842 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &pdcity
->identity
,
5844 FALSE
, "%s", secfile_error());
5845 sg_warn_ret_val(IDENTITY_NUMBER_ZERO
< pdcity
->identity
, FALSE
,
5846 "%s has invalid id (%d); skipping.", citystr
, id
);
5848 sg_warn_ret_val(secfile_lookup_int(loading
->file
, &size
,
5849 "%s.size", citystr
),
5850 FALSE
, "%s", secfile_error());
5851 city_size
= (citizens
)size
; /* set the correct type */
5852 sg_warn_ret_val(size
== (int)city_size
, FALSE
,
5853 "Invalid city size: %d; set to %d.", size
, city_size
);
5854 vision_site_size_set(pdcity
, city_size
);
5856 /* Initialise list of improvements */
5857 BV_CLR_ALL(pdcity
->improvements
);
5858 string
= secfile_lookup_str(loading
->file
, "%s.improvements", citystr
);
5859 sg_warn_ret_val(string
!= NULL
, FALSE
, "%s", secfile_error());
5860 sg_warn_ret_val(strlen(string
) == loading
->improvement
.size
, FALSE
,
5861 "Invalid length of '%s.improvements' (%lu ~= %lu).",
5862 citystr
, (unsigned long) strlen(string
),
5863 (unsigned long) loading
->improvement
.size
);
5864 for (i
= 0; i
< loading
->improvement
.size
; i
++) {
5865 sg_warn_ret_val(string
[i
] == '1' || string
[i
] == '0', FALSE
,
5866 "Undefined value '%c' within '%s.improvements'.",
5869 if (string
[i
] == '1') {
5870 struct impr_type
*pimprove
=
5871 improvement_by_rule_name(loading
->improvement
.order
[i
]);
5873 BV_SET(pdcity
->improvements
, improvement_index(pimprove
));
5878 /* Use the section as backup name. */
5879 sz_strlcpy(pdcity
->name
, secfile_lookup_str_default(loading
->file
, citystr
,
5880 "%s.name", citystr
));
5882 pdcity
->occupied
= secfile_lookup_bool_default(loading
->file
, FALSE
,
5883 "%s.occupied", citystr
);
5884 pdcity
->walls
= secfile_lookup_bool_default(loading
->file
, FALSE
,
5885 "%s.walls", citystr
);
5886 pdcity
->happy
= secfile_lookup_bool_default(loading
->file
, FALSE
,
5887 "%s.happy", citystr
);
5888 pdcity
->unhappy
= secfile_lookup_bool_default(loading
->file
, FALSE
,
5889 "%s.unhappy", citystr
);
5890 pdcity
->city_image
= secfile_lookup_int_default(loading
->file
, -100,
5891 "%s.city_image", citystr
);
5896 /****************************************************************************
5898 ****************************************************************************/
5899 static void sg_save_player_vision(struct savedata
*saving
,
5902 int i
, plrno
= player_number(plr
);
5904 /* Check status and return if not OK (sg_success != TRUE). */
5907 if (!game
.info
.fogofwar
|| !game
.server
.save_options
.save_private_map
) {
5908 /* The player can see all, there's no reason to save the private map. */
5912 if (!plr
->is_alive
) {
5913 /* Nothing to save. */
5917 /* Save the map (terrain). */
5918 SAVE_MAP_CHAR(ptile
,
5919 terrain2char(map_get_player_tile(ptile
, plr
)->terrain
),
5920 saving
->file
, "player%d.map_t%04d", plrno
);
5922 /* Save the map (resources). */
5923 SAVE_MAP_CHAR(ptile
,
5924 resource2char(map_get_player_tile(ptile
, plr
)->resource
),
5925 saving
->file
, "player%d.map_res%04d", plrno
);
5927 if (game
.server
.foggedborders
) {
5928 /* Save the map (borders). */
5931 for (y
= 0; y
< map
.ysize
; y
++) {
5932 char line
[map
.xsize
* TOKEN_SIZE
];
5935 for (x
= 0; x
< map
.xsize
; x
++) {
5936 char token
[TOKEN_SIZE
];
5937 struct tile
*ptile
= native_pos_to_tile(x
, y
);
5938 struct player_tile
*plrtile
= map_get_player_tile(ptile
, plr
);
5940 if (plrtile
== NULL
|| plrtile
->owner
== NULL
) {
5943 fc_snprintf(token
, sizeof(token
), "%d",
5944 player_number(plrtile
->owner
));
5946 strcat(line
, token
);
5947 if (x
< map
.xsize
) {
5951 secfile_insert_str(saving
->file
, line
, "player%d.map_owner%04d",
5956 /* Save the map (specials). */
5957 halfbyte_iterate_special(j
, S_LAST
) {
5958 enum tile_special_type mod
[4];
5961 for (l
= 0; l
< 4; l
++) {
5962 mod
[l
] = MIN(4 * j
+ l
, S_LAST
);
5964 SAVE_MAP_CHAR(ptile
,
5965 sg_special_get(map_get_player_tile(ptile
, plr
)->special
,
5967 "player%d.map_spe%02d_%04d", plrno
, j
);
5968 } halfbyte_iterate_special_end
;
5970 /* Save the map (bases). */
5971 halfbyte_iterate_bases(j
, game
.control
.num_base_types
) {
5975 for (l
= 0; l
< 4; l
++) {
5976 if (4 * j
+ 1 > game
.control
.num_base_types
) {
5983 SAVE_MAP_CHAR(ptile
,
5984 sg_bases_get(map_get_player_tile(ptile
, plr
)->bases
, mod
),
5985 saving
->file
, "player%d.map_b%02d_%04d", plrno
, j
);
5986 } halfbyte_iterate_bases_end
;
5988 /* Save the map (roads). */
5989 halfbyte_iterate_roads(j
, game
.control
.num_road_types
) {
5993 for (l
= 0; l
< 4; l
++) {
5994 if (4 * j
+ 1 > game
.control
.num_road_types
) {
6001 SAVE_MAP_CHAR(ptile
,
6002 sg_roads_get(map_get_player_tile(ptile
, plr
)->roads
, mod
),
6003 saving
->file
, "player%d.map_r%02d_%04d", plrno
, j
);
6004 } halfbyte_iterate_roads_end
;
6006 /* Save the map (update time). */
6007 for (i
= 0; i
< 4; i
++) {
6008 /* put 4-bit segments of 16-bit "updated" field */
6009 SAVE_MAP_CHAR(ptile
,
6011 map_get_player_tile(ptile
, plr
)->last_updated
, i
),
6012 saving
->file
, "player%d.map_u%02d_%04d", plrno
, i
);
6015 /* Save known cities. */
6017 whole_map_iterate(ptile
) {
6018 struct vision_site
*pdcity
= map_get_player_city(ptile
, plr
);
6019 char impr_buf
[MAX_NUM_ITEMS
+ 1];
6022 fc_snprintf(buf
, sizeof(buf
), "player%d.dc%d", plrno
, i
);
6024 if (NULL
!= pdcity
&& plr
!= vision_site_owner(pdcity
)) {
6027 index_to_native_pos(&nat_x
, &nat_y
, tile_index(ptile
));
6028 secfile_insert_int(saving
->file
, nat_y
, "%s.y", buf
);
6029 secfile_insert_int(saving
->file
, nat_x
, "%s.x", buf
);
6031 secfile_insert_int(saving
->file
, pdcity
->identity
, "%s.id", buf
);
6032 secfile_insert_int(saving
->file
, player_number(vision_site_owner(pdcity
)),
6035 secfile_insert_int(saving
->file
, vision_site_size_get(pdcity
),
6037 secfile_insert_bool(saving
->file
, pdcity
->occupied
,
6038 "%s.occupied", buf
);
6039 secfile_insert_bool(saving
->file
, pdcity
->walls
, "%s.walls", buf
);
6040 secfile_insert_bool(saving
->file
, pdcity
->happy
, "%s.happy", buf
);
6041 secfile_insert_bool(saving
->file
, pdcity
->unhappy
, "%s.unhappy", buf
);
6042 secfile_insert_int(saving
->file
, pdcity
->city_image
, "%s.city_image", buf
);
6044 /* Save improvement list as bitvector. Note that improvement order
6045 * is saved in savefile.improvement.order. */
6046 improvement_iterate(pimprove
) {
6047 impr_buf
[improvement_index(pimprove
)]
6048 = BV_ISSET(pdcity
->improvements
, improvement_index(pimprove
))
6050 } improvement_iterate_end
;
6051 impr_buf
[improvement_count()] = '\0';
6052 sg_failure_ret(strlen(impr_buf
) < sizeof(impr_buf
),
6053 "Invalid size of the improvement vector (%s.improvements: "
6054 "%lu < %lu).", buf
, (long unsigned int) strlen(impr_buf
),
6055 (long unsigned int) sizeof(impr_buf
));
6056 secfile_insert_str(saving
->file
, impr_buf
, "%s.improvements", buf
);
6057 secfile_insert_str(saving
->file
, pdcity
->name
, "%s.name", buf
);
6061 } whole_map_iterate_end
;
6063 secfile_insert_int(saving
->file
, i
, "player%d.dc_total", plrno
);
6066 /* =======================================================================
6067 * Load / save the event cache. Should be the last thing to do.
6068 * ======================================================================= */
6070 /****************************************************************************
6071 Load '[event_cache]'.
6072 ****************************************************************************/
6073 static void sg_load_event_cache(struct loaddata
*loading
)
6075 /* Check status and return if not OK (sg_success != TRUE). */
6078 event_cache_load(loading
->file
, "event_cache");
6081 /****************************************************************************
6082 Save '[event_cache]'.
6083 ****************************************************************************/
6084 static void sg_save_event_cache(struct savedata
*saving
)
6086 /* Check status and return if not OK (sg_success != TRUE). */
6089 if (saving
->scenario
) {
6090 /* Do _not_ save events in a scenario. */
6094 event_cache_save(saving
->file
, "event_cache");
6097 /* =======================================================================
6098 * Load / save the mapimg definitions.
6099 * ======================================================================= */
6101 /****************************************************************************
6103 ****************************************************************************/
6104 static void sg_load_mapimg(struct loaddata
*loading
)
6106 int mapdef_count
, i
;
6108 /* Check status and return if not OK (sg_success != TRUE). */
6111 /* Clear all defined map images. */
6112 while (mapimg_count() > 0) {
6116 mapdef_count
= secfile_lookup_int_default(loading
->file
, 0,
6118 log_verbose("Saved map image definitions: %d.", mapdef_count
);
6120 if (0 >= mapdef_count
) {
6124 for (i
= 0; i
< mapdef_count
; i
++) {
6127 p
= secfile_lookup_str(loading
->file
, "mapimg.mapdef%d", i
);
6129 log_verbose("[Mapimg %4d] Missing definition.", i
);
6133 if (!mapimg_define(p
, FALSE
)) {
6134 log_error("Invalid map image definition %4d: %s.", i
, p
);
6137 log_verbose("Mapimg %4d loaded.", i
);
6141 /****************************************************************************
6143 ****************************************************************************/
6144 static void sg_save_mapimg(struct savedata
*saving
)
6146 /* Check status and return if not OK (sg_success != TRUE). */
6149 secfile_insert_int(saving
->file
, mapimg_count(), "mapimg.count");
6150 if (mapimg_count() > 0) {
6153 for (i
= 0; i
< mapimg_count(); i
++) {
6154 char buf
[MAX_LEN_MAPDEF
];
6156 mapimg_id2str(i
, buf
, sizeof(buf
));
6157 secfile_insert_str(saving
->file
, buf
, "mapimg.mapdef%d", i
);
6162 /* =======================================================================
6163 * Sanity checks for loading / saving a game.
6164 * ======================================================================= */
6166 /****************************************************************************
6167 Sanity check for loaded game.
6168 ****************************************************************************/
6169 static void sg_load_sanitycheck(struct loaddata
*loading
)
6173 /* Check status and return if not OK (sg_success != TRUE). */
6176 if (game
.info
.is_new_game
) {
6177 /* Nothing to do for new games (or not started scenarios). */
6181 /* Old savegames may have maxplayers lower than current player count,
6183 players
= normal_player_count();
6184 if (game
.server
.max_players
< players
) {
6185 log_verbose("Max players lower than current players, fixing");
6186 game
.server
.max_players
= players
;
6189 /* Fix ferrying sanity */
6190 players_iterate(pplayer
) {
6191 unit_list_iterate_safe(pplayer
->units
, punit
) {
6192 if (!unit_transport_get(punit
)
6193 && !can_unit_exist_at_tile(punit
, unit_tile(punit
))) {
6194 log_sg("Removing %s unferried %s in %s at (%d, %d)",
6195 nation_rule_name(nation_of_player(pplayer
)),
6196 unit_rule_name(punit
),
6197 terrain_rule_name(unit_tile(punit
)->terrain
),
6198 TILE_XY(unit_tile(punit
)));
6199 bounce_unit(punit
, TRUE
);
6201 } unit_list_iterate_safe_end
;
6202 } players_iterate_end
;
6204 /* Fix stacking issues. We don't rely on the savegame preserving
6205 * alliance invariants (old savegames often did not) so if there are any
6206 * unallied units on the same tile we just bounce them. */
6207 players_iterate(pplayer
) {
6208 players_iterate(aplayer
) {
6209 resolve_unit_stacks(pplayer
, aplayer
, TRUE
);
6210 } players_iterate_end
;
6212 /* Backward compatibility: if we had any open-ended orders (pillage)
6213 * in the savegame, assign specific targets now */
6214 unit_list_iterate(pplayer
->units
, punit
) {
6215 unit_assign_specific_activity_target(punit
,
6217 &punit
->activity_target
);
6218 } unit_list_iterate_end
;
6219 } players_iterate_end
;
6221 /* Recalculate the potential buildings for each city. Has caused some
6222 * problems with game random state.
6223 * This also changes the game state if you save the game directly after
6224 * loading it and compare the results. */
6225 players_iterate(pplayer
) {
6226 bool saved_ai_control
= pplayer
->ai_controlled
;
6228 /* Recalculate for all players. */
6229 pplayer
->ai_controlled
= FALSE
;
6231 /* Building advisor needs data phase open in order to work */
6232 adv_data_phase_init(pplayer
, FALSE
);
6233 building_advisor(pplayer
);
6234 /* Close data phase again so it can be opened again when game starts. */
6235 adv_data_phase_done(pplayer
);
6237 pplayer
->ai_controlled
= saved_ai_control
;
6238 } players_iterate_end
;
6240 /* Check worked tiles map */
6242 if (loading
->worked_tiles
!= NULL
) {
6243 /* check the entire map for unused worked tiles */
6244 whole_map_iterate(ptile
) {
6245 if (loading
->worked_tiles
[ptile
->index
] != -1) {
6246 log_error("[city id: %d] Unused worked tile at (%d, %d).",
6247 loading
->worked_tiles
[ptile
->index
], TILE_XY(ptile
));
6249 } whole_map_iterate_end
;
6253 if (0 == strlen(server
.game_identifier
)
6254 || !is_base64url(server
.game_identifier
)) {
6255 /* This uses fc_rand(), so random state has to be initialized before. */
6256 randomize_base64url_string(server
.game_identifier
,
6257 sizeof(server
.game_identifier
));
6260 /* Restore game random state, just in case various initialization code
6261 * inexplicably altered the previously existing state. */
6262 if (!game
.info
.is_new_game
) {
6263 fc_rand_set_state(loading
->rstate
);
6265 /* Recalculate scores. */
6266 players_iterate(pplayer
) {
6267 calc_civ_score(pplayer
);
6268 } players_iterate_end
;
6271 /* At the end do the default sanity checks. */
6275 /****************************************************************************
6276 Sanity check for saved game.
6277 ****************************************************************************/
6278 static void sg_save_sanitycheck(struct savedata
*saving
)
6280 /* Check status and return if not OK (sg_success != TRUE). */
6284 /* =======================================================================
6285 * Compatibility functions for loading a game.
6286 * ======================================================================= */
6288 /****************************************************************************
6289 Translate savegame secfile data from 2.3.x to 2.4.0 format.
6290 ****************************************************************************/
6291 static void compat_load_020400(struct loaddata
*loading
)
6293 /* Check status and return if not OK (sg_success != TRUE). */
6296 log_debug("Upgrading data from savegame to version 2.4.0");
6298 /* Add the default player AI. */
6299 player_slots_iterate(pslot
) {
6300 int ncities
, i
, plrno
= player_slot_index(pslot
);
6302 if (NULL
== secfile_section_lookup(loading
->file
, "player%d", plrno
)) {
6306 secfile_insert_str(loading
->file
, default_ai_type_name(),
6307 "player%d.ai_type", player_slot_index(pslot
));
6309 /* Create dummy citizens informations. We do not know if citizens are
6310 * activated due to the fact that this information
6311 * (game.info.citizen_nationality) is not available, but adding the
6312 * information does no harm. */
6313 ncities
= secfile_lookup_int_default(loading
->file
, 0,
6314 "player%d.ncities", plrno
);
6316 for (i
= 0; i
< ncities
; i
++) {
6317 int size
= secfile_lookup_int_default(loading
->file
, 0,
6318 "player%d.c%d.size", plrno
, i
);
6320 secfile_insert_int(loading
->file
, size
,
6321 "player%d.c%d.citizen%d", plrno
, i
, plrno
);
6326 } player_slots_iterate_end
;
6328 /* Player colors are assigned at the end of player loading, as this
6329 * needs information not available here. */
6331 /* Deal with buggy known tiles information from 2.3.0/2.3.1 (and the
6332 * workaround in later 2.3.x); see gna bug #19029.
6333 * (The structure of this code is odd as it avoids relying on knowledge of
6334 * xsize/ysize, which haven't been extracted from the savefile yet.) */
6336 if (has_capability("knownv2",
6337 secfile_lookup_str(loading
->file
, "savefile.options"))) {
6338 /* This savefile contains known information in a sane format.
6339 * Just move any entries to where 2.4.x+ expect to find them. */
6340 struct section
*map
= secfile_section_by_name(loading
->file
, "map");
6342 entry_list_iterate(section_entries(map
), pentry
) {
6343 const char *name
= entry_name(pentry
);
6344 if (strncmp(name
, "kvb", 3) == 0) {
6345 /* Rename the "kvb..." entry to "k..." */
6346 char *name2
= fc_strdup(name
), *newname
= name2
+ 2;
6348 /* Savefile probably contains existing "k" entries, which are bogus
6349 * so we trash them */
6350 secfile_entry_delete(loading
->file
, "map.%s", newname
);
6351 entry_set_name(pentry
, newname
);
6354 } entry_list_iterate_end
;
6356 /* Could remove "knownv2" from savefile.options, but it's doing
6359 /* This savefile only contains known information in the broken
6360 * format. Try to recover it to a sane format. */
6361 /* MAX_NUM_PLAYER_SLOTS in 2.3.x was 128 */
6362 /* MAP_MAX_LINEAR_SIZE in 2.3.x was 512 */
6363 const int maxslots
= 128, maxmapsize
= 512;
6364 const int lines
= maxslots
/32;
6365 int xsize
= 0, y
, l
, j
, x
;
6366 unsigned int known_row_old
[lines
* maxmapsize
],
6367 known_row
[lines
* maxmapsize
];
6368 /* Process a map row at a time */
6369 for (y
= 0; y
< maxmapsize
; y
++) {
6370 /* Look for broken info to convert */
6372 memset(known_row_old
, 0, sizeof(known_row_old
));
6373 for (l
= 0; l
< lines
; l
++) {
6374 for (j
= 0; j
< 8; j
++) {
6376 secfile_lookup_str_default(loading
->file
, NULL
,
6377 "map.k%02d_%04d", l
* 8 + j
, y
);
6383 sg_failure_ret(xsize
== strlen(s
),
6384 "Inconsistent xsize in map.k%02d_%04d",
6386 for (x
= 0; x
< xsize
; x
++) {
6387 known_row_old
[l
* xsize
+ x
] |= ascii_hex2bin(s
[x
], j
);
6393 /* At least one entry found for this row. Let's hope they were
6395 /* Attempt to munge into sane format */
6397 memset(known_row
, 0, sizeof(known_row
));
6398 /* Iterate over possible player slots */
6399 for (p
= 0; p
< maxslots
; p
++) {
6401 for (x
= 0; x
< xsize
; x
++) {
6402 /* This test causes bit-shifts of >=32 (undefined behaviour), but
6403 * on common platforms, information happens not to be lost, just
6404 * oddly arranged. */
6405 if (known_row_old
[l
* xsize
+ x
] & (1u << (p
- l
* 8))) {
6406 known_row
[l
* xsize
+ x
] |= (1u << (p
- l
* 32));
6410 /* Save sane format back to memory representation of secfile for
6411 * real loading code to pick up */
6412 for (l
= 0; l
< lines
; l
++) {
6413 for (j
= 0; j
< 8; j
++) {
6414 /* Save info for all slots (not just used ones). It's only
6415 * memory, after all. */
6417 for (x
= 0; x
< xsize
; x
++) {
6418 row
[x
] = bin2ascii_hex(known_row
[l
* xsize
+ x
], j
);
6421 secfile_replace_str(loading
->file
, row
,
6422 "map.k%02d_%04d", l
* 8 + j
, y
);
6430 /* Server setting migration. */
6433 if (secfile_lookup_int(loading
->file
, &set_count
, "settings.set_count")) {
6434 int i
, new_opt
= set_count
;
6435 bool gamestart_valid
6436 = secfile_lookup_bool_default(loading
->file
, FALSE
,
6437 "settings.gamestart_valid");
6438 for (i
= 0; i
< set_count
; i
++) {
6440 = secfile_lookup_str(loading
->file
, "settings.set%d.name", i
);
6445 /* In 2.3.x and prior, saveturns=0 meant no turn-based saves.
6446 * This is now controlled by the "autosaves" setting. */
6447 if (!fc_strcasecmp("saveturns", name
)) {
6448 /* XXX: hardcodes details from GAME_AUTOSAVES_DEFAULT
6449 * and settings.c:autosaves_name() (but these defaults reflect
6450 * 2.3's behaviour). */
6451 const char *const nosave
= "GAMEOVER|QUITIDLE|INTERRUPT";
6452 const char *const save
= "TURN|GAMEOVER|QUITIDLE|INTERRUPT";
6455 if (secfile_lookup_int(loading
->file
, &nturns
,
6456 "settings.set%d.value", i
)) {
6458 /* Invent a new "autosaves" setting */
6459 secfile_insert_str(loading
->file
, nosave
,
6460 "settings.set%d.value", new_opt
);
6461 /* Pick something valid for saveturns */
6462 secfile_replace_int(loading
->file
, GAME_DEFAULT_SAVETURNS
,
6463 "settings.set%d.value", i
);
6465 secfile_insert_str(loading
->file
, save
,
6466 "settings.set%d.value", new_opt
);
6469 log_sg("Setting '%s': %s", name
, secfile_error());
6471 if (gamestart_valid
) {
6472 if (secfile_lookup_int(loading
->file
, &nturns
,
6473 "settings.set%d.gamestart", i
)) {
6475 /* Invent a new "autosaves" setting */
6476 secfile_insert_str(loading
->file
, nosave
,
6477 "settings.set%d.gamestart", new_opt
);
6478 /* Pick something valid for saveturns */
6479 secfile_replace_int(loading
->file
, GAME_DEFAULT_SAVETURNS
,
6480 "settings.set%d.gamestart", i
);
6482 secfile_insert_str(loading
->file
, save
,
6483 "settings.set%d.gamestart", new_opt
);
6486 log_sg("Setting '%s': %s", name
, secfile_error());
6489 } else if (!fc_strcasecmp("autosaves", name
)) {
6490 /* Sanity check. This won't trigger on an option we've just
6491 * invented, as the loop won't include it. */
6492 log_sg("Unexpected \"autosaves\" setting found in pre-2.4 "
6493 "savefile. It may have been overridden.");
6500 /****************************************************************************
6501 Callback to get name of old killcitizen setting bit.
6502 ****************************************************************************/
6503 static const char *killcitizen_enum_str(secfile_data_t data
, int bit
)
6517 /****************************************************************************
6518 Translate savegame secfile data from 2.4.x to 2.5.0 format.
6519 ****************************************************************************/
6520 static void compat_load_020500(struct loaddata
*loading
)
6522 const char *modname
[] = { "Road", "Railroad" };
6524 /* Check status and return if not OK (sg_success != TRUE). */
6527 log_debug("Upgrading data from savegame to version 2.5.0");
6529 secfile_insert_int(loading
->file
, 2, "savefile.roads_size");
6531 secfile_insert_str_vec(loading
->file
, modname
, 2,
6532 "savefile.roads_vector");
6534 /* Server setting migration. */
6538 if (secfile_lookup_int(loading
->file
, &set_count
, "settings.set_count")) {
6540 bool gamestart_valid
6541 = secfile_lookup_bool_default(loading
->file
, FALSE
,
6542 "settings.gamestart_valid");
6543 for (i
= 0; i
< set_count
; i
++) {
6545 = secfile_lookup_str(loading
->file
, "settings.set%d.name", i
);
6550 /* In 2.4.x and prior, "killcitizen" listed move types that
6551 * killed citizens after succesfull attack. Now killcitizen
6552 * is just boolean and classes affected are defined in ruleset. */
6553 if (!fc_strcasecmp("killcitizen", name
)) {
6556 if (secfile_lookup_enum_data(loading
->file
, &value
, TRUE
,
6557 killcitizen_enum_str
, NULL
,
6558 "settings.set%d.value", i
)) {
6559 /* Lowest bit of old killcitizen value indicates if
6560 * land units should kill citizens. We take that as
6561 * new boolean killcitizen value. */
6563 secfile_replace_bool(loading
->file
, TRUE
,
6564 "settings.set%d.value", i
);
6566 secfile_replace_bool(loading
->file
, FALSE
,
6567 "settings.set%d.value", i
);
6570 log_sg("Setting '%s': %s", name
, secfile_error());
6572 if (gamestart_valid
) {
6573 if (secfile_lookup_enum_data(loading
->file
, &value
, TRUE
,
6574 killcitizen_enum_str
, NULL
,
6575 "settings.set%d.gamestart", i
)) {
6576 /* Lowest bit of old killcitizen value indicates if
6577 * land units should kill citizens. We take that as
6578 * new boolean killcitizen value. */
6580 secfile_replace_bool(loading
->file
, TRUE
,
6581 "settings.set%d.gamestart", i
);
6583 secfile_replace_bool(loading
->file
, FALSE
,
6584 "settings.set%d.gamestart", i
);
6587 log_sg("Setting '%s': %s", name
, secfile_error());
6596 /****************************************************************************
6597 Compatibility functions for loaded game.
6599 This function is called at the beginning of loading a savegame. The data in
6600 loading->file should be change such, that the current loading functions can
6601 be executed without errors.
6602 ****************************************************************************/
6603 static void sg_load_compat(struct loaddata
*loading
)
6607 /* Check status and return if not OK (sg_success != TRUE). */
6610 loading
->version
= secfile_lookup_int_default(loading
->file
, -1,
6611 "savefile.version");
6613 sg_failure_ret(0 < loading
->version
, "Invalid savefile format version (%d).",
6615 if (loading
->version
> compat
[compat_current
].version
) {
6616 /* Debug build can (TRY TO!) load newer versions but ... */
6617 log_error("Savegame version newer than this build found (%d > %d). "
6618 "Trying to load the game nevertheless ...", loading
->version
,
6619 compat
[compat_current
].version
);
6622 sg_failure_ret(0 < loading
->version
6623 && loading
->version
<= compat
[compat_current
].version
,
6624 "Unknown savefile format version (%d).", loading
->version
);
6628 for (i
= 0; i
< compat_num
; i
++) {
6629 if (loading
->version
< compat
[i
].version
&& compat
[i
].load
!= NULL
) {
6630 log_normal(_("Run compatibility function for version: <%d "
6631 "(save file: %d; server: %d)."), compat
[i
].version
,
6632 loading
->version
, compat
[compat_current
].version
);
6633 compat
[i
].load(loading
);