Clarify character encoding arrangements, and stop claiming in various
[freeciv.git] / server / savegame2.c
blobad8d818729935854a342290955e374d4912f02dd
1 /**********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
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
21 of the savefile.
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 | |
44 | * delegation | |
45 | * citizens | |
46 | * save player color | |
47 | * "known" info format change | |
48 2.5.0 | 2.5.0 release (development) | 201./../.. | 20
49 | | |
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
55 loaded.
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:
61 * helper functions
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
73 and the event_cache).
75 Creating a savegame:
77 (nothing at the moment)
79 Loading a savegame:
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.
94 #ifdef HAVE_CONFIG_H
95 #include <fc_config.h>
96 #endif
98 #include <ctype.h>
99 #include <stdarg.h>
100 #include <stdio.h>
101 #include <stdlib.h>
102 #include <string.h>
104 /* utility */
105 #include "bitvector.h"
106 #include "fcintl.h"
107 #include "idex.h"
108 #include "log.h"
109 #include "mem.h"
110 #include "rand.h"
111 #include "registry.h"
112 #include "shared.h"
113 #include "support.h" /* bool type */
114 #include "timing.h"
116 /* common */
117 #include "ai.h"
118 #include "bitvector.h"
119 #include "capability.h"
120 #include "citizens.h"
121 #include "city.h"
122 #include "game.h"
123 #include "government.h"
124 #include "map.h"
125 #include "mapimg.h"
126 #include "movement.h"
127 #include "packets.h"
128 #include "research.h"
129 #include "rgbcolor.h"
130 #include "specialist.h"
131 #include "unit.h"
132 #include "unitlist.h"
134 /* server */
135 #include "aiiface.h"
136 #include "barbarian.h"
137 #include "citizenshand.h"
138 #include "citytools.h"
139 #include "cityturn.h"
140 #include "diplhand.h"
141 #include "maphand.h"
142 #include "meta.h"
143 #include "notify.h"
144 #include "plrhand.h"
145 #include "ruleset.h"
146 #include "sanitycheck.h"
147 #include "savegame.h"
148 #include "score.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 */
157 #include "advdata.h"
158 #include "advbuilding.h"
159 #include "infracache.h"
161 /* server/generator */
162 #include "mapgen.h"
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(...) \
175 if (!sg_success) { \
176 return; \
178 #define sg_check_ret_val(_val) \
179 if (!sg_success) { \
180 return _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__); \
190 return; \
192 #define sg_warn_ret_val(condition, _val, message, ...) \
193 if (!(condition)) { \
194 log_sg(message, ## __VA_ARGS__); \
195 return _val; \
198 #define sg_failure_ret(condition, message, ...) \
199 if (!(condition)) { \
200 sg_success = FALSE; \
201 log_sg(message, ## __VA_ARGS__); \
202 sg_check_ret(); \
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.
215 * Parameters:
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
221 * Example:
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.
251 * Parameters:
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
259 * Example:
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) { \
279 char buf[64]; \
280 fc_snprintf(buf, sizeof(buf), secpath, ## __VA_ARGS__, _nat_y); \
281 log_verbose("Line not found='%s'", buf); \
282 _printed_warning = TRUE; \
283 continue; \
284 } else if (strlen(_line) != map.xsize) { \
285 char buf[64]; \
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; \
290 continue; \
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); \
295 (SET_XY_CHAR); \
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) \
319 int b; \
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) \
329 int r; \
330 for(r = 0; 4 * r < (num_roads_types); r++) {
332 #define halfbyte_iterate_roads_end \
336 struct loaddata {
337 struct section_file *file;
338 const char *secfile_options;
339 int version;
341 /* loaded in sg_load_savefile(); needed in sg_load_player() */
342 struct {
343 const char **order;
344 size_t size;
345 } improvement;
346 /* loaded in sg_load_savefile(); needed in sg_load_player() */
347 struct {
348 const char **order;
349 size_t size;
350 } technology;
351 /* loaded in sg_load_savefile(); needed in sg_load_player() */
352 struct {
353 const char **order;
354 size_t size;
355 } trait;
356 /* loaded in sg_load_savefile(); needed in sg_load_map(), ... */
357 struct {
358 enum tile_special_type *order;
359 size_t size;
360 } special;
361 /* loaded in sg_load_savefile(); needed in sg_load_map(), ... */
362 struct {
363 struct base_type **order;
364 size_t size;
365 } base;
366 /* loaded in sg_load_savefile(); needed in sg_load_map(), ... */
367 struct {
368 struct road_type **order;
369 size_t size;
370 } road;
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() */
376 RANDOM_STATE rstate;
378 /* loaded in sg_load_map_worked(); needed in sg_load_player_cities() */
379 int *worked_tiles;
382 struct savedata {
383 struct section_file *file;
384 char secfile_options[512];
386 /* set by the caller */
387 const char *save_reason;
388 bool scenario;
390 /* Set in sg_save_game(); needed in sg_save_map_*(); ... */
391 bool save_players;
394 #define TOKEN_SIZE 10
396 #define log_worker log_verbose
398 static const char savefile_options_default[] =
399 " +version2";
400 /* The following savefile option are added if needed:
401 * - specials
402 * - riversoverlay
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,
412 bool scenario);
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,
418 bool scenario);
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,
429 int dest_length);
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,
464 const char *option);
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,
508 struct player *plr);
509 static void sg_load_player_cities(struct loaddata *loading,
510 struct player *plr);
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,
514 struct player *plr,
515 struct city *pcity,
516 const char *citystr);
517 static void sg_load_player_units(struct loaddata *loading,
518 struct player *plr);
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,
523 struct player *plr);
524 static void sg_load_player_attributes(struct loaddata *loading,
525 struct player *plr);
526 static void sg_load_player_vision(struct loaddata *loading,
527 struct player *plr);
528 static bool sg_load_player_vision_city(struct loaddata *loading,
529 struct player *plr,
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,
534 struct player *plr);
535 static void sg_save_player_cities(struct savedata *saving,
536 struct player *plr);
537 static void sg_save_player_units(struct savedata *saving,
538 struct player *plr);
539 static void sg_save_player_attributes(struct savedata *saving,
540 struct player *plr);
541 static void sg_save_player_vision(struct savedata *saving,
542 struct player *plr);
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 {
561 int version;
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) */
579 { 0, NULL },
580 /* version 1 and 2 is not used */
581 /* version 3: first savegame2 format, so no compat functions for translation
582 * from previous format */
583 { 3, NULL },
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);
606 #ifdef DEBUG_TIMERS
607 struct timer *loadtimer = timer_new(TIMER_CPU, TIMER_DEBUG);
608 timer_start(loadtimer);
609 #endif
611 savefile_options = secfile_lookup_str(file, "savefile.options");
613 if (!savefile_options) {
614 log_error("Missing savefile options. Can not load the savegame.");
615 return;
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);
623 } else {
624 /* load new format (freeciv 2.2.99 and newer) */
625 log_verbose("loading savefile in new format ...");
626 savegame2_load_real(file);
629 #ifdef DEBUG_TIMERS
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,
641 bool scenario)
643 fc_assert_ret(file != NULL);
645 #ifdef DEBUG_TIMERS
646 struct timer *savetimer = timer_new(TIMER_CPU, TIMER_DEBUG);
647 timer_start(savetimer);
648 #endif
650 log_verbose("saving game in new format ...");
651 savegame2_save_real(file, save_reason, scenario);
653 #ifdef DEBUG_TIMERS
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);
676 sg_success = TRUE;
678 /* Load the savegame data. */
679 /* [compat] */
680 sg_load_compat(loading);
681 /* [savefile] */
682 sg_load_savefile(loading);
683 /* [game] */
684 sg_load_game(loading);
685 /* [random] */
686 sg_load_random(loading);
687 /* [script] */
688 sg_load_script(loading);
689 /* [scenario] */
690 sg_load_scenario(loading);
691 /* [settings] */
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);
697 /* [player<i>] */
698 sg_load_players(loading);
699 /* [event_cache] */
700 sg_load_event_cache(loading);
701 /* [mapimg] */
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);
712 if (!sg_success) {
713 log_error("Failure loading savegame!");
714 game_reset();
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,
723 bool scenario)
725 struct savedata *saving;
727 /* initialise loading */
728 saving = savedata_new(file, save_reason, scenario);
729 sg_success = TRUE;
731 /* [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);
735 /* [savefile] */
736 sg_save_savefile(saving);
737 /* [game] */
738 sg_save_game(saving);
739 /* [random] */
740 sg_save_random(saving);
741 /* [script] */
742 sg_save_script(saving);
743 /* [settings] */
744 sg_save_settings(saving);
745 /* [map] */
746 sg_save_map(saving);
747 /* [player<i>] */
748 sg_save_players(saving);
749 /* [event_cache] */
750 sg_save_event_cache(saving);
751 /* [mapimg] */
752 sg_save_mapimg(saving);
754 /* Sanity checks for the saved game. */
755 sg_save_sanitycheck(saving);
757 /* deinitialise saving */
758 savedata_destroy(saving);
760 if (!sg_success) {
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;
791 return loading;
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);
827 free(loading);
830 /****************************************************************************
831 Create new savedata item for given file.
832 ****************************************************************************/
833 struct savedata *savedata_new(struct section_file *file,
834 const char *save_reason,
835 bool scenario)
837 struct savedata *saving = calloc(1, sizeof(*saving));
838 saving->file = file;
839 saving->secfile_options[0] = '\0';
841 saving->save_reason = save_reason;
842 saving->scenario = scenario;
844 saving->save_players = FALSE;
846 return saving;
849 /****************************************************************************
850 Free resources allocated for savedata item
851 ****************************************************************************/
852 void savedata_destroy(struct savedata *saving)
854 free(saving);
857 /* =======================================================================
858 * Helper functions.
859 * ======================================================================= */
861 /****************************************************************************
862 Returns an order for a character identifier. See also order2char.
863 ****************************************************************************/
864 static enum unit_orders char2order(char order)
866 switch (order) {
867 case 'm':
868 case 'M':
869 return ORDER_MOVE;
870 case 'w':
871 case 'W':
872 return ORDER_FULL_MP;
873 case 'b':
874 case 'B':
875 return ORDER_BUILD_CITY;
876 case 'a':
877 case 'A':
878 return ORDER_ACTIVITY;
879 case 'd':
880 case 'D':
881 return ORDER_DISBAND;
882 case 'u':
883 case 'U':
884 return ORDER_BUILD_WONDER;
885 case 't':
886 case 'T':
887 return ORDER_TRADE_ROUTE;
888 case 'h':
889 case 'H':
890 return ORDER_HOMECITY;
893 /* This can happen if the savegame is invalid. */
894 return ORDER_LAST;
897 /****************************************************************************
898 Returns a character identifier for an order. See also char2order.
899 ****************************************************************************/
900 static char order2char(enum unit_orders order)
902 switch (order) {
903 case ORDER_MOVE:
904 return 'm';
905 case ORDER_FULL_MP:
906 return 'w';
907 case ORDER_ACTIVITY:
908 return 'a';
909 case ORDER_BUILD_CITY:
910 return 'b';
911 case ORDER_DISBAND:
912 return 'd';
913 case ORDER_BUILD_WONDER:
914 return 'u';
915 case ORDER_TRADE_ROUTE:
916 return 't';
917 case ORDER_HOMECITY:
918 return 'h';
919 case ORDER_LAST:
920 break;
923 fc_assert(FALSE);
924 return '?';
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. */
933 switch (dir) {
934 case '1':
935 return DIR8_SOUTHWEST;
936 case '2':
937 return DIR8_SOUTH;
938 case '3':
939 return DIR8_SOUTHEAST;
940 case '4':
941 return DIR8_WEST;
942 case '6':
943 return DIR8_EAST;
944 case '7':
945 return DIR8_NORTHWEST;
946 case '8':
947 return DIR8_NORTH;
948 case '9':
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. */
962 switch (dir) {
963 case DIR8_NORTH:
964 return '8';
965 case DIR8_SOUTH:
966 return '2';
967 case DIR8_EAST:
968 return '6';
969 case DIR8_WEST:
970 return '4';
971 case DIR8_NORTHEAST:
972 return '9';
973 case DIR8_NORTHWEST:
974 return '7';
975 case DIR8_SOUTHEAST:
976 return '3';
977 case DIR8_SOUTHWEST:
978 return '1';
981 fc_assert(FALSE);
982 return '?';
985 /****************************************************************************
986 Returns a character identifier for an activity. See also char2activity.
987 ****************************************************************************/
988 static char activity2char(enum unit_activity activity)
990 switch (activity) {
991 case ACTIVITY_IDLE:
992 return 'w';
993 case ACTIVITY_POLLUTION:
994 return 'p';
995 case ACTIVITY_OLD_ROAD:
996 return 'r';
997 case ACTIVITY_MINE:
998 return 'm';
999 case ACTIVITY_IRRIGATE:
1000 return 'i';
1001 case ACTIVITY_FORTIFIED:
1002 return 'f';
1003 case ACTIVITY_FORTRESS:
1004 return 't';
1005 case ACTIVITY_SENTRY:
1006 return 's';
1007 case ACTIVITY_OLD_RAILROAD:
1008 return 'l';
1009 case ACTIVITY_PILLAGE:
1010 return 'e';
1011 case ACTIVITY_GOTO:
1012 return 'g';
1013 case ACTIVITY_EXPLORE:
1014 return 'x';
1015 case ACTIVITY_TRANSFORM:
1016 return 'o';
1017 case ACTIVITY_AIRBASE:
1018 return 'a';
1019 case ACTIVITY_FORTIFYING:
1020 return 'y';
1021 case ACTIVITY_FALLOUT:
1022 return 'u';
1023 case ACTIVITY_BASE:
1024 return 'b';
1025 case ACTIVITY_GEN_ROAD:
1026 return 'R';
1027 case ACTIVITY_CONVERT:
1028 return 'c';
1029 case ACTIVITY_UNKNOWN:
1030 case ACTIVITY_PATROL_UNUSED:
1031 return '?';
1032 case ACTIVITY_LAST:
1033 break;
1036 fc_assert(FALSE);
1037 return '?';
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) {
1051 return a;
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);
1066 size_t offset;
1067 int i;
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]);
1074 offset += 3;
1076 return buffer;
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,
1085 int dest_length)
1087 int i, length, parsed, tmp;
1088 char *endptr;
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);
1097 quoted++;
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;
1105 quoted += 3;
1107 return length;
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, ...)
1117 int i;
1118 const char *kind;
1119 const char *name;
1120 char path_str[1024];
1121 va_list ap;
1123 /* The first part of the registry path is taken from the varargs to the
1124 * function. */
1125 va_start(ap, path);
1126 fc_vsnprintf(path_str, sizeof(path_str), path, ap);
1127 va_end(ap);
1129 worklist_init(pwl);
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",
1139 path_str, i);
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,
1143 name);
1144 pwl->length = i;
1145 break;
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];
1159 int i;
1160 va_list ap;
1162 /* The first part of the registry path is taken from the varargs to the
1163 * function. */
1164 va_start(ap, path);
1165 fc_vsnprintf(path_str, sizeof(path_str), path, ap);
1166 va_end(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
1190 saved.
1191 ****************************************************************************/
1192 static void unit_ordering_calc(void)
1194 int j;
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) {
1202 j = 0;
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) {
1210 j = 0;
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
1219 values.
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,
1243 char ch,
1244 const enum tile_special_type *index,
1245 bool rivers_overlay)
1247 int i, bin;
1248 const char *pch = strchr(hex_chars, ch);
1250 if (!pch || ch == '\0') {
1251 log_sg("Unknown hex value: '%c' (%d)", ch, ch);
1252 bin = 0;
1253 } else {
1254 bin = pch - hex_chars;
1257 for (i = 0; i < 4; i++) {
1258 enum tile_special_type sp = index[i];
1260 if (sp == S_LAST) {
1261 continue;
1263 if (rivers_overlay && sp != S_OLD_RIVER) {
1264 continue;
1267 if (bin & (1 << i)) {
1268 if (sp == S_OLD_ROAD) {
1269 if (roads) {
1270 struct road_type *proad;
1272 proad = road_by_compat_special(ROCO_ROAD);
1273 if (proad) {
1274 BV_SET(*roads, road_index(proad));
1277 } else if (sp == S_OLD_RAILROAD) {
1278 if (roads) {
1279 struct road_type *proad;
1281 proad = road_by_compat_special(ROCO_RAILROAD);
1282 if (proad) {
1283 BV_SET(*roads, road_index(proad));
1286 } else if (sp == S_OLD_RIVER) {
1287 if (roads) {
1288 struct road_type *proad;
1290 proad = road_by_compat_special(ROCO_RIVER);
1291 if (proad) {
1292 BV_SET(*roads, road_index(proad));
1295 } else {
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)
1311 int i, bin = 0;
1313 for (i = 0; i < 4; i++) {
1314 enum tile_special_type sp = index[i];
1316 if (sp >= S_LAST) {
1317 break;
1319 if (contains_special(specials, sp)) {
1320 bin |= (1 << i);
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)
1336 int i, bin;
1337 const char *pch = strchr(hex_chars, ch);
1339 if (!pch || ch == '\0') {
1340 log_sg("Unknown hex value: '%c' (%d)", ch, ch);
1341 bin = 0;
1342 } else {
1343 bin = pch - hex_chars;
1346 for (i = 0; i < 4; i++) {
1347 struct base_type *pbase = index[i];
1349 if (pbase == NULL) {
1350 continue;
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)
1366 int i, bin = 0;
1368 for (i = 0; i < 4; i++) {
1369 int base = index[i];
1371 if (base < 0) {
1372 break;
1374 if (BV_ISSET(bases, base)) {
1375 bin |= (1 << i);
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)
1391 int i, bin;
1392 const char *pch = strchr(hex_chars, ch);
1394 if (!pch || ch == '\0') {
1395 log_sg("Unknown hex value: '%c' (%d)", ch, ch);
1396 bin = 0;
1397 } else {
1398 bin = pch - hex_chars;
1401 for (i = 0; i < 4; i++) {
1402 struct road_type *proad = index[i];
1404 if (proad == NULL) {
1405 continue;
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)
1421 int i, bin = 0;
1423 for (i = 0; i < 4; i++) {
1424 int road = index[i];
1426 if (road < 0) {
1427 break;
1429 if (BV_ISSET(roads, road)) {
1430 bin |= (1 << i);
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) {
1445 return NULL;
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)
1475 const char *pch;
1477 if (ch == ' ') {
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). */
1481 return 0;
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)) {
1497 return '?';
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)
1508 const char *pch;
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) {
1526 return T_UNKNOWN;
1528 terrain_type_iterate(pterrain) {
1529 if (pterrain->identifier == ch) {
1530 return pterrain;
1532 } terrain_type_iterate_end;
1534 log_fatal("Unknown terrain identifier '%c' in savegame.", ch);
1535 exit(EXIT_FAILURE);
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;
1546 } else {
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];
1559 const char* name;
1560 struct advance *padvance;
1562 fc_snprintf(path_with_name, sizeof(path_with_name),
1563 "%s_name", path);
1565 name = secfile_lookup_str(file, path_with_name, plrno);
1567 if (!name || name[0] == '\0') {
1568 /* used by researching_saved */
1569 return A_UNKNOWN;
1571 if (fc_strcasecmp(name, "A_FUTURE") == 0) {
1572 return A_FUTURE;
1574 if (fc_strcasecmp(name, "A_NONE") == 0) {
1575 return A_NONE;
1577 if (fc_strcasecmp(name, "A_UNSET") == 0) {
1578 return A_UNSET;
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];
1595 const char* name;
1597 fc_snprintf(path_with_name, sizeof(path_with_name),
1598 "%s_name", path);
1600 switch (tech) {
1601 case A_UNKNOWN: /* used by researching_saved */
1602 name = "";
1603 break;
1604 case A_NONE:
1605 name = "A_NONE";
1606 break;
1607 case A_UNSET:
1608 name = "A_UNSET";
1609 break;
1610 case A_FUTURE:
1611 name = "A_FUTURE";
1612 break;
1613 default:
1614 name = advance_rule_name(advance_by_number(tech));
1615 break;
1618 secfile_insert_str(file, name, path_with_name, plrno);
1621 /* =======================================================================
1622 * Load / save savefile data.
1623 * ======================================================================= */
1625 /****************************************************************************
1626 Load '[savefile]'.
1627 ****************************************************************************/
1628 static void sg_load_savefile(struct loaddata *loading)
1630 /* Check status and return if not OK (sg_success != TRUE). */
1631 sg_check_ret();
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");
1641 /* Load ruleset. */
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",
1663 secfile_error());
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",
1676 secfile_error());
1679 /* Load traits. */
1680 loading->trait.size
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",
1689 secfile_error());
1692 /* Load specials. */
1693 loading->special.size
1694 = secfile_lookup_int_default(loading->file, 0,
1695 "savefile.specials_size");
1697 const char **modname;
1698 size_t nmod;
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",
1705 secfile_error());
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;
1727 } else {
1728 loading->special.order[j] = special_by_rule_name(modname[j]);
1731 free(modname);
1732 for (; j < nmod; j++) {
1733 loading->special.order[j] = S_LAST;
1737 /* Load bases. */
1738 loading->base.size
1739 = secfile_lookup_int_default(loading->file, 0,
1740 "savefile.bases_size");
1741 if (loading->base.size) {
1742 const char **modname;
1743 size_t nmod;
1744 int j;
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",
1750 secfile_error());
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]);
1761 free(modname);
1762 for (; j < nmod; j++) {
1763 loading->base.order[j] = NULL;
1767 /* Load roads. */
1768 loading->road.size
1769 = secfile_lookup_int_default(loading->file, 0,
1770 "savefile.roads_size");
1771 if (loading->road.size) {
1772 const char **modname;
1773 size_t nmod;
1774 int j;
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",
1780 secfile_error());
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]);
1791 free(modname);
1792 for (; j < nmod; j++) {
1793 loading->road.order[j] = NULL;
1798 /****************************************************************************
1799 Save '[savefile]'.
1800 ****************************************************************************/
1801 static void sg_save_savefile(struct savedata *saving)
1803 /* Check status and return if not OK (sg_success != TRUE). */
1804 sg_check_ret();
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
1815 * savefile. */
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;
1855 int i = 0;
1856 int j;
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,
1865 ACTIVITY_LAST,
1866 "savefile.activities_vector");
1867 free(modname);
1870 /* Save trait order in savegame. */
1871 secfile_insert_int(saving->file, TRAIT_COUNT,
1872 "savefile.trait_size");
1874 const char **modname;
1875 enum trait tr;
1876 int j;
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");
1886 free(modname);
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");
1901 free(modname);
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;
1909 int i = 0;
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");
1920 free(modname);
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;
1928 int i = 0;
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");
1939 free(modname);
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,
1947 const char *option)
1949 /* Check status and return if not OK (sg_success != TRUE). */
1950 sg_check_ret();
1952 if (option == NULL) {
1953 /* no additional option */
1954 return;
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 /****************************************************************************
1967 Load '[game]'.
1968 ****************************************************************************/
1969 static void sg_load_game(struct loaddata *loading)
1971 int game_version;
1972 const char *string;
1974 /* Check status and return if not OK (sg_success != TRUE). */
1975 sg_check_ret();
1977 /* Load version. */
1978 game_version
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, "",
2021 "game.serverid"));
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,
2035 "game.phase_mode");
2036 game.server.phase_mode_stored
2037 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_PHASE_MODE,
2038 "game.phase_mode_stored");
2039 game.info.phase
2040 = secfile_lookup_int_default(loading->file, 0,
2041 "game.phase");
2042 game.server.scoreturn
2043 = secfile_lookup_int_default(loading->file,
2044 game.info.turn + GAME_DEFAULT_SCORETURN,
2045 "game.scoreturn");
2047 game.server.timeoutint
2048 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_TIMEOUTINT,
2049 "game.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,
2055 "game.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");
2063 game.info.turn
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");
2072 game.info.heating
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");
2079 game.info.cooling
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 /****************************************************************************
2089 Save '[game]'.
2090 ****************************************************************************/
2091 static void sg_save_game(struct savedata *saving)
2093 int game_version;
2094 const char *user_message;
2095 enum server_states srv_state;
2097 /* Check status and return if not OK (sg_success != TRUE). */
2098 sg_check_ret();
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;
2108 } else {
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,
2130 "game.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,
2134 "game.phase");
2135 secfile_insert_int(saving->file, game.server.scoreturn,
2136 "game.scoreturn");
2138 secfile_insert_int(saving->file, game.server.timeoutint,
2139 "game.timeoutint");
2140 secfile_insert_int(saving->file, game.server.timeoutintinc,
2141 "game.timeoutintinc");
2142 secfile_insert_int(saving->file, game.server.timeoutinc,
2143 "game.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,
2157 "game.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,
2164 "game.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;
2172 } else {
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 /****************************************************************************
2184 Load '[random]'.
2185 ****************************************************************************/
2186 static void sg_load_random(struct loaddata *loading)
2188 /* Check status and return if not OK (sg_success != TRUE). */
2189 sg_check_ret();
2191 if (secfile_lookup_bool_default(loading->file, FALSE, "random.save")) {
2192 const char *string;
2193 int i;
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);
2212 } else {
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. */
2219 init_game_seed();
2220 loading->rstate = fc_rand_state();
2224 /****************************************************************************
2225 Save '[random]'.
2226 ****************************************************************************/
2227 static void sg_save_random(struct savedata *saving)
2229 /* Check status and return if not OK (sg_success != TRUE). */
2230 sg_check_ret();
2232 if (fc_rand_is_init() && game.server.save_options.save_random) {
2233 int i;
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++) {
2244 char vec[100];
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);
2253 } else {
2254 secfile_insert_bool(saving->file, FALSE, "random.save");
2258 /* =======================================================================
2259 * Load / save lua script data.
2260 * ======================================================================= */
2262 /****************************************************************************
2263 Load '[script]'.
2264 ****************************************************************************/
2265 static void sg_load_script(struct loaddata *loading)
2267 /* Check status and return if not OK (sg_success != TRUE). */
2268 sg_check_ret();
2270 script_server_state_load(loading->file);
2273 /****************************************************************************
2274 Save '[script]'.
2275 ****************************************************************************/
2276 static void sg_save_script(struct savedata *saving)
2278 /* Check status and return if not OK (sg_success != TRUE). */
2279 sg_check_ret();
2281 script_server_state_save(saving->file);
2284 /* =======================================================================
2285 * Load / save scenario data.
2286 * ======================================================================= */
2288 /****************************************************************************
2289 Load '[scenario]'.
2290 ****************************************************************************/
2291 static void sg_load_scenario(struct loaddata *loading)
2293 const char *buf;
2295 /* Check status and return if not OK (sg_success != TRUE). */
2296 sg_check_ret();
2298 if (NULL == secfile_section_lookup(loading->file, "scenario")) {
2299 /* Nothing to do. */
2300 return;
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")) {
2307 return;
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);
2318 } else {
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 "
2331 "players are %s).",
2332 server_states_name(loading->server_state),
2333 game.scenario.players ? "saved" : "not saved");
2334 } else {
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. */
2341 aifill(0);
2345 /****************************************************************************
2346 Save '[scenario]'.
2347 ****************************************************************************/
2348 static void sg_save_scenario(struct savedata *saving)
2350 /* Check status and return if not OK (sg_success != TRUE). */
2351 sg_check_ret();
2353 if (!saving->scenario || !game.scenario.is_scenario) {
2354 secfile_insert_bool(saving->file, FALSE, "scenario.is_scenario");
2355 return;
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 /****************************************************************************
2372 Load '[settings]'.
2373 ****************************************************************************/
2374 static void sg_load_settings(struct loaddata *loading)
2376 /* Check status and return if not OK (sg_success != TRUE). */
2377 sg_check_ret();
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 /****************************************************************************
2388 Save [settings].
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). */
2395 sg_check_ret();
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 /****************************************************************************
2412 Load '[map'].
2413 ****************************************************************************/
2414 static void sg_load_map(struct loaddata *loading)
2416 /* Check status and return if not OK (sg_success != TRUE). */
2417 sg_check_ret();
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. */
2427 /* Load tiles. */
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. */
2452 return;
2455 if (S_S_INITIAL == loading->server_state) {
2456 /* Nothing more to do if it is not a scenario but in initial state. */
2457 return;
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 /****************************************************************************
2475 Save 'map'.
2476 ****************************************************************************/
2477 static void sg_save_map(struct savedata *saving)
2479 /* Check status and return if not OK (sg_success != TRUE). */
2480 sg_check_ret();
2482 secfile_insert_bool(saving->file, map.server.have_huts, "map.have_huts");
2484 if (map_is_empty()) {
2485 /* No map. */
2486 return;
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);
2501 } else {
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). */
2518 sg_check_ret();
2520 /* Initialize the map for the current topology. 'map.xsize' and
2521 * 'map.ysize' must be set. */
2522 map_init_topology();
2524 /* Allocate map. */
2525 map_allocate();
2527 /* get the terrain type */
2528 LOAD_MAP_CHAR(ch, ptile, ptile->terrain = char2terrain(ch), loading->file,
2529 "map.t%04d");
2530 assign_continent_numbers();
2532 /* Check for special tile sprites. */
2533 whole_map_iterate(ptile) {
2534 const char *spec_sprite;
2535 const char *label;
2536 int nat_x, nat_y;
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",
2540 nat_x, nat_y);
2541 label = secfile_lookup_str_default(loading->file, NULL, "map.label_%d_%d",
2542 nat_x, nat_y);
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 /****************************************************************************
2553 Save all map tiles
2554 ****************************************************************************/
2555 static void sg_save_map_tiles(struct savedata *saving)
2557 /* Check status and return if not OK (sg_success != TRUE). */
2558 sg_check_ret();
2560 /* Save the terrain type. */
2561 SAVE_MAP_CHAR(ptile, terrain2char(ptile->terrain), saving->file,
2562 "map.t%04d");
2564 /* Save special tile sprites. */
2565 whole_map_iterate(ptile) {
2566 int nat_x, nat_y;
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 /****************************************************************************
2581 Load bases to map
2582 ****************************************************************************/
2583 static void sg_load_map_tiles_bases(struct loaddata *loading)
2585 /* Check status and return if not OK (sg_success != TRUE). */
2586 sg_check_ret();
2588 /* Load bases. */
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). */
2602 sg_check_ret();
2604 /* Save bases. */
2605 halfbyte_iterate_bases(j, game.control.num_base_types) {
2606 int mod[4];
2607 int l;
2609 for (l = 0; l < 4; l++) {
2610 if (4 * j + 1 > game.control.num_base_types) {
2611 mod[l] = -1;
2612 } else {
2613 mod[l] = 4 * j + l;
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 /****************************************************************************
2622 Load roads to map
2623 ****************************************************************************/
2624 static void sg_load_map_tiles_roads(struct loaddata *loading)
2626 /* Check status and return if not OK (sg_success != TRUE). */
2627 sg_check_ret();
2629 /* Load roads. */
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). */
2643 sg_check_ret();
2645 /* Save roads. */
2646 halfbyte_iterate_roads(j, game.control.num_road_types) {
2647 int mod[4];
2648 int l;
2650 for (l = 0; l < 4; l++) {
2651 if (4 * j + 1 > game.control.num_road_types) {
2652 mod[l] = -1;
2653 } else {
2654 mod[l] = 4 * j + l;
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). */
2669 sg_check_ret();
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,
2688 rivers_overlay),
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). */
2700 sg_check_ret();
2702 halfbyte_iterate_special(j, S_LAST) {
2703 enum tile_special_type mod[4];
2704 int l;
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;
2710 } else {
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). */
2726 sg_check_ret();
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) {
2734 continue;
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). */
2752 sg_check_ret();
2754 SAVE_MAP_CHAR(ptile, resource2char(ptile->resource), saving->file,
2755 "map.res%04d");
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;
2766 struct tile *ptile;
2767 const char SEPARATOR = '#';
2768 const char *nation_names;
2769 int nat_x, nat_y;
2770 bool exclude;
2771 int i, startpos_count;
2773 /* Check status and return if not OK (sg_success != TRUE). */
2774 sg_check_ret();
2776 startpos_count
2777 = secfile_lookup_int_default(loading->file, 0, "map.startpos_count");
2779 if (0 == startpos_count) {
2780 /* Nothing to do. */
2781 return;
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);
2789 continue;
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);
2796 continue;
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) {
2812 start++;
2813 if ((end = strchr(start, SEPARATOR))) {
2814 *end = '\0';
2817 pnation = nation_by_rule_name(start);
2818 if (NO_NATION_SELECTED != pnation) {
2819 if (exclude) {
2820 startpos_disallow(psp, pnation);
2821 } else {
2822 startpos_allow(psp, pnation);
2824 } else {
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)
2851 struct tile *ptile;
2852 const char SEPARATOR = '#';
2853 int i = 0;
2855 /* Check status and return if not OK (sg_success != TRUE). */
2856 sg_check_ret();
2858 if (!game.server.save_options.save_starts) {
2859 return;
2862 secfile_insert_int(saving->file, map_startpos_count(),
2863 "map.startpos_count");
2865 map_startpos_iterate(psp) {
2866 int nat_x, nat_y;
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);
2878 } else {
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));
2887 } else {
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);
2895 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)
2906 int x, y;
2907 struct player *owner = NULL;
2908 struct tile *claimer = NULL;
2910 /* Check status and return if not OK (sg_success != TRUE). */
2911 sg_check_ret();
2913 if (game.info.is_new_game) {
2914 /* No owner/source information for a new game / scenario. */
2915 return;
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];
2933 int number;
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) {
2940 owner = NULL;
2941 } else {
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) {
2951 claimer = NULL;
2952 } else {
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)
2968 int x, y;
2970 /* Check status and return if not OK (sg_success != TRUE). */
2971 sg_check_ret();
2973 if (saving->scenario && !saving->save_players) {
2974 /* Nothing to do for a scenario without saved players. */
2975 return;
2978 /* Store owner and ownership source as plain numbers. */
2979 for (y = 0; y < map.ysize; y++) {
2980 char line[map.xsize * TOKEN_SIZE];
2982 line[0] = '\0';
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) {
2988 strcpy(token, "-");
2989 } else {
2990 fc_snprintf(token, sizeof(token), "%d",
2991 player_number(tile_owner(ptile)));
2993 strcat(line, token);
2994 if (x + 1 < map.xsize) {
2995 strcat(line, ",");
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];
3004 line[0] = '\0';
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) {
3010 strcpy(token, "-");
3011 } else {
3012 fc_snprintf(token, sizeof(token), "%d", tile_index(ptile->claimer));
3014 strcat(line, token);
3015 if (x + 1 < map.xsize) {
3016 strcat(line, ",");
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)
3028 int x, y;
3030 /* Check status and return if not OK (sg_success != TRUE). */
3031 sg_check_ret();
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];
3048 int number;
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) {
3055 number = -1;
3056 } else {
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)
3072 int x, y;
3074 /* Check status and return if not OK (sg_success != TRUE). */
3075 sg_check_ret();
3077 if (saving->scenario && !saving->save_players) {
3078 /* Nothing to do for a scenario without saved players. */
3079 return;
3082 /* additionally save the tiles worked by the cities */
3083 for (y = 0; y < map.ysize; y++) {
3084 char line[map.xsize * TOKEN_SIZE];
3086 line[0] = '\0';
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) {
3093 strcpy(token, "-");
3094 } else {
3095 fc_snprintf(token, sizeof(token), "%d", pcity->id);
3097 strcat(line, token);
3098 if (x < map.xsize) {
3099 strcat(line, ",");
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). */
3112 sg_check_ret();
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);
3135 break;
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;
3158 FC_FREE(known);
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). */
3168 sg_check_ret();
3170 if (!saving->save_players) {
3171 secfile_insert_bool(saving->file, FALSE, "game.save_known");
3172 return;
3173 } else {
3174 int lines = player_slot_max_used_number()/32 + 1;
3176 secfile_insert_bool(saving->file, game.server.save_options.save_known,
3177 "game.save_known");
3178 if (game.server.save_options.save_known) {
3179 int j, p, l, i;
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
3183 * hex. */
3185 whole_map_iterate(ptile) {
3186 players_iterate(pplayer) {
3187 if (map_is_known(ptile, pplayer)) {
3188 p = player_index(pplayer);
3189 l = p / 32;
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);
3206 break;
3212 FC_FREE(known);
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
3222 * defined.
3223 * ======================================================================= */
3225 /****************************************************************************
3226 Load '[player]' (basic data).
3227 ****************************************************************************/
3228 static void sg_load_players_basic(struct loaddata *loading)
3230 int i, k, nplayers;
3231 const char *string;
3232 bool shuffle_loaded = TRUE;
3234 /* Check status and return if not OK (sg_success != TRUE). */
3235 sg_check_ret();
3237 if (S_S_INITIAL == loading->server_state
3238 || game.info.is_new_game) {
3239 /* Nothing more to do. */
3240 return;
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]);
3259 if (pimprove) {
3260 game.info.great_wonder_owners[improvement_index(pimprove)]
3261 = WONDER_DESTROYED;
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",
3282 pslot_id)) {
3283 continue;
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",
3293 pslot_id)) {
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.",
3298 pslot_id);
3299 /* This will be fixed up later */
3300 } else {
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,
3309 prgbcolor);
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) {
3326 int team;
3327 struct team_slot *tslot = NULL;
3329 sg_failure_ret(secfile_lookup_int(loading->file, &team,
3330 "player%d.team_no",
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
3343 * a list
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++){
3364 int shuffle
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;
3372 break;
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;
3377 break;
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;
3392 shuffle_index++;
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!");
3399 #ifdef DEBUG
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;
3407 #endif /* DEBUG */
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). */
3417 shuffle_players();
3421 /****************************************************************************
3422 Load '[player]'.
3423 ****************************************************************************/
3424 static void sg_load_players(struct loaddata *loading)
3426 /* Check status and return if not OK (sg_success != TRUE). */
3427 sg_check_ret();
3429 if (game.info.is_new_game) {
3430 /* Nothing to do. */
3431 return;
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. */
3441 sg_check_ret();
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));
3449 } else {
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,
3479 TRUE)
3480 || (player_invention_state(pplayer, presearch->tech_goal)
3481 == TECH_KNOWN))) {
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,
3501 NOT_A_BARBARIAN));
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,
3513 DS_ALLIANCE);
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. */
3539 sg_check_ret();
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 /****************************************************************************
3590 Save '[player]'.
3591 ****************************************************************************/
3592 static void sg_save_players(struct savedata *saving)
3594 /* Check status and return if not OK (sg_success != TRUE). */
3595 sg_check_ret();
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
3600 * INITIAL state. */
3601 return;
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';
3615 } else {
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. */
3629 int i = 0;
3630 shuffled_players_iterate(pplayer) {
3631 secfile_insert_int(saving->file, player_number(pplayer),
3632 "players.shuffled_player_%d", i);
3633 i++;
3634 } shuffled_players_iterate_end;
3637 /* Sort units. */
3638 unit_ordering_calc();
3640 /* Save players. */
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,
3654 struct player *plr)
3656 int i, plrno = player_number(plr);
3657 const char *string;
3658 struct government *gov;
3659 struct player_research *research;
3661 /* Check status and return if not OK (sg_success != TRUE). */
3662 sg_check_ret();
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",
3674 plrno));
3675 string = secfile_lookup_str_default(loading->file, "",
3676 "player%d.delegation_username",
3677 plrno);
3678 /* Defaults to no delegation. */
3679 if (strlen(string)) {
3680 player_delegation_set(plr, string);
3683 /* Nation */
3684 string = secfile_lookup_str(loading->file, "player%d.nation", plrno);
3685 player_set_nation(plr, nation_by_rule_name(string));
3687 /* Government */
3688 string = secfile_lookup_str(loading->file, "player%d.government_name",
3689 plrno);
3690 gov = government_by_rule_name(string);
3691 sg_failure_ret(gov != NULL, "Player%d: unsupported government \"%s\".",
3692 plrno, string);
3693 plr->government = gov;
3695 /* Target government */
3696 string = secfile_lookup_str(loading->file,
3697 "player%d.target_government_name", plrno);
3698 if (string) {
3699 plr->target_government = government_by_rule_name(string);
3700 } else {
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) {
3721 char buf[32];
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);
3728 ds->type =
3729 secfile_lookup_int_default(loading->file, DS_WAR, "%s.type", buf);
3730 ds->max_state =
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);
3735 ds->turns_left =
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",
3745 buf)) {
3746 BV_SET(plr->real_embassy, i);
3748 /* 'gives_shared_vision' is loaded in sg_load_players() as all cities
3749 * must be known. */
3750 } players_iterate_end;
3752 /* load ai data */
3753 players_iterate(aplayer) {
3754 char buf[32];
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. */
3788 int city_style;
3790 string = secfile_lookup_str(loading->file, "player%d.city_style_by_name",
3791 plrno);
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));
3797 city_style = 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);
3851 research->got_tech
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'.",
3864 string[i], plrno)
3866 if (string[i] == '1') {
3867 struct advance *padvance =
3868 advance_by_rule_name(loading->technology.order[i]);
3869 if (padvance) {
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;
3901 char prefix[32];
3902 const char *st;
3903 int ei;
3905 fc_snprintf(prefix, sizeof(prefix), "player%d.spaceship", plrno);
3906 spaceship_init(ship);
3907 sg_failure_ret(secfile_lookup_int(loading->file,
3908 &ei,
3909 "%s.state", prefix),
3910 "%s", secfile_error());
3911 ship->state = ei;
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,
3924 "%s.fuel", prefix),
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],
3944 prefix)
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 */
3962 if (string) {
3963 int k;
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]);
3976 if (pimprove) {
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,
3988 struct player *plr)
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). */
3994 sg_check_ret();
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);
4004 } else {
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)
4014 : "",
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) {
4041 char buf[32];
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,
4050 "%s.type", buf);
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),
4062 "%s.embassy", buf);
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);
4069 /* save ai data */
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)
4117 ? '1' : '0';
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);
4123 /* Save traits */
4125 enum trait tr;
4126 int j;
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",
4150 plrno);
4151 if (ship->state != SSHIP_NONE) {
4152 char buf[32];
4153 char st[NUM_SS_STRUCTURALS+1];
4154 int i;
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,
4163 "%s.modules", buf);
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';
4175 st[i] = '\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';
4190 } else {
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 /****************************************************************************
4201 Load city data
4202 ****************************************************************************/
4203 static void sg_load_player_cities(struct loaddata *loading,
4204 struct player *plr)
4206 int ncities, i, plrno = player_number(plr);
4208 /* Check status and return if not OK (sg_success != TRUE). */
4209 sg_check_ret();
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);
4217 ncities = 0;
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++) {
4227 char buf[32];
4228 struct city *pcity;
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;
4282 int nat_x, nat_y;
4283 citizens size;
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);
4306 if (NULL != past) {
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) {
4318 sg_warn_ret_val(
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());
4341 pcity->airlift =
4342 secfile_lookup_int_default(loading->file, 0, "%s.airlift", citystr);
4343 pcity->was_happy =
4344 secfile_lookup_bool_default(loading->file, FALSE, "%s.was_happy",
4345 citystr);
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());
4358 pcity->rapture =
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",
4366 citystr);
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;
4375 pcity->did_sell =
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",
4383 citystr);
4384 name = secfile_lookup_str(loading->file, "%s.currently_building_name",
4385 citystr);
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",
4392 citystr);
4393 name = secfile_lookup_str(loading->file, "%s.changed_from_name",
4394 citystr);
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",
4412 citystr);
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'.",
4431 string[i], citystr)
4433 if (string[i] == '1') {
4434 struct impr_type *pimprove =
4435 improvement_by_rule_name(loading->improvement.order[i]);
4436 if (pimprove) {
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
4448 * tiles map */
4450 int radius_sq
4451 = secfile_lookup_int_default(loading->file, -1, "%s.city_radius_sq",
4452 citystr);
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);
4458 workers++;
4460 #ifdef DEBUG
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;
4464 #endif /* DEBUG */
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);
4480 } else {
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));
4486 /* repair 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);
4492 if (0 != repair) {
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);
4498 /* repair pcity */
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",
4509 citystr, i)) {
4510 BV_SET(pcity->city_options, i);
4514 CALL_FUNC_EACH_AI(city_load, loading->file, pcity, citystr);
4516 return TRUE;
4519 /****************************************************************************
4520 Load nationality data for one city.
4521 ****************************************************************************/
4522 static void sg_load_player_city_citizens(struct loaddata *loading,
4523 struct player *plr,
4524 struct city *pcity,
4525 const char *citystr)
4527 if (game.info.citizen_nationality) {
4528 citizens size;
4530 citizens_init(pcity);
4531 player_slots_iterate(pslot) {
4532 int nationality;
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));
4540 continue;
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;
4550 /* Sanity check. */
4551 size = citizens_count(pcity);
4552 if (size != city_size_get(pcity)) {
4553 if (size != 0) {
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 /****************************************************************************
4568 Save cities data
4569 ****************************************************************************/
4570 static void sg_save_player_cities(struct savedata *saving,
4571 struct player *plr)
4573 int wlist_max_length = 0;
4574 int i = 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). */
4579 sg_check_ret();
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];
4615 char buf[32];
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",
4638 buf, j);
4641 secfile_insert_int(saving->file, pcity->food_stock, "%s.food_stock",
4642 buf);
4643 secfile_insert_int(saving->file, pcity->shield_stock, "%s.shield_stock",
4644 buf);
4646 secfile_insert_int(saving->file, pcity->airlift, "%s.airlift",
4647 buf);
4648 secfile_insert_bool(saving->file, pcity->was_happy, "%s.was_happy",
4649 buf);
4650 secfile_insert_int(saving->file, pcity->turn_plague, "%s.turn_plague",
4651 buf);
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",
4658 buf);
4659 if (pcity->turn_founded == game.info.turn) {
4660 j = -1; /* undocumented hack */
4661 } else {
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
4693 * city map. */
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'
4704 : '1';
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",
4714 buf);
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;
4734 i++;
4735 } city_list_iterate_end;
4738 /****************************************************************************
4739 Load unit data
4740 ****************************************************************************/
4741 static void sg_load_player_units(struct loaddata *loading,
4742 struct player *plr)
4744 int nunits, i, plrno = player_number(plr);
4746 /* Check status and return if not OK (sg_success != TRUE). */
4747 sg_check_ret();
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++) {
4758 struct unit *punit;
4759 struct city *pcity;
4760 const char *name;
4761 char buf[32];
4762 struct unit_type *type;
4763 struct tile *ptile;
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)
4820 int j;
4821 enum unit_activity activity;
4822 int nat_x, nat_y;
4823 enum tile_special_type target;
4824 struct base_type *pbase = NULL;
4825 struct road_type *proad = NULL;
4826 struct tile *ptile;
4827 int base;
4828 int road;
4829 int ei;
4830 const char *facing_str;
4831 enum tile_special_type cfspe;
4832 int natnbr;
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);
4846 facing_str
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;
4857 } else {
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,
4865 player_number(plr),
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());
4885 activity = ei;
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];
4907 } else {
4908 target = S_LAST;
4912 if (target == S_OLD_ROAD) {
4913 target = S_LAST;
4914 proad = road_by_compat_special(ROCO_ROAD);
4915 } else if (target == S_OLD_RAILROAD) {
4916 target = S_LAST;
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) {
4953 if (pbase) {
4954 set_unit_activity_base(punit, base_number(pbase));
4955 } else {
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) {
4961 if (proad) {
4962 set_unit_activity_road(punit, road_number(proad));
4963 } else {
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);
4980 } else {
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);
4988 } else {
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);
4999 cfspe =
5000 secfile_lookup_int_default(loading->file, S_LAST,
5001 "%s.changed_from_target", unitstr);
5002 base =
5003 secfile_lookup_int_default(loading->file, -1,
5004 "%s.changed_from_base", unitstr);
5005 road =
5006 secfile_lookup_int_default(loading->file, -1,
5007 "%s.changed_from_road", unitstr);
5009 if (road == -1) {
5010 if (cfspe == S_OLD_ROAD) {
5011 proad = road_by_compat_special(ROCO_ROAD);
5012 if (proad) {
5013 road = road_index(proad);
5015 } else if (cfspe == S_OLD_RAILROAD) {
5016 proad = road_by_compat_special(ROCO_RAILROAD);
5017 if (proad) {
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]);
5029 } else {
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;
5049 punit->veteran
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;
5059 punit->done_moving
5060 = secfile_lookup_bool_default(loading->file, (punit->moves_left == 0),
5061 "%s.done_moving", unitstr);
5062 punit->battlegroup
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)) {
5068 int nat_x, nat_y;
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);
5078 } else {
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);
5102 punit->moved
5103 = secfile_lookup_bool_default(loading->file, FALSE, "%s.moved", unitstr);
5104 punit->paradropped
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);
5125 if (len > 0) {
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;
5133 punit->orders.index
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);
5146 orders_unitstr
5147 = secfile_lookup_str_default(loading->file, "",
5148 "%s.orders_list", unitstr);
5149 dir_unitstr
5150 = secfile_lookup_str_default(loading->file, "",
5151 "%s.dir_list", unitstr);
5152 act_unitstr
5153 = secfile_lookup_str_default(loading->file, "",
5154 "%s.activity_list", unitstr);
5155 base_unitstr
5156 = secfile_lookup_str(loading->file, "%s.base_list", unitstr);
5157 road_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);
5168 break;
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;
5181 break;
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,
5191 NULL, NULL));
5194 order->base = base;
5195 } else {
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));
5205 road = 0;
5208 order->road = road;
5209 } else {
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;
5221 } else {
5222 punit->has_orders = FALSE;
5223 punit->orders.list = NULL;
5227 return TRUE;
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,
5235 struct player *plr)
5237 int nunits, i, plrno = player_number(plr);
5239 /* Check status and return if not OK (sg_success != TRUE). */
5240 sg_check_ret();
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,
5257 "player%d.u%d.id",
5258 plrno, i);
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",
5264 plrno, i);
5265 if (id_trans == -1) {
5266 /* Not transported. */
5267 continue;
5270 ptrans = game_unit_by_number(id_trans);
5271 fc_assert_action(id_trans == -1 || ptrans != NULL, continue);
5273 if (ptrans) {
5274 fc_assert_action(unit_transport_load(punit, ptrans, TRUE), continue);
5279 /****************************************************************************
5280 Save unit data
5281 ****************************************************************************/
5282 static void sg_save_player_units(struct savedata *saving,
5283 struct player *plr)
5285 int i = 0;
5287 /* Check status and return if not OK (sg_success != TRUE). */
5288 sg_check_ret();
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) {
5294 char buf[32];
5295 char dirbuf[2] = " ";
5296 int nat_x, nat_y;
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);
5323 } else {
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);
5330 } else {
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);
5337 } else {
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);
5348 } else {
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);
5355 } else {
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);
5362 } else {
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,
5371 "%s.born", buf);
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);
5380 } else {
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,
5388 "%s.ai", buf);
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,
5394 "%s.ord_map", buf);
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);
5423 dir_buf[j] = '?';
5424 act_buf[j] = '?';
5425 base_buf[j] = '?';
5426 road_buf[j] = '?';
5427 switch (punit->orders.list[j].order) {
5428 case ORDER_MOVE:
5429 dir_buf[j] = dir2char(punit->orders.list[j].dir);
5430 break;
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);
5438 break;
5439 case ORDER_FULL_MP:
5440 case ORDER_BUILD_CITY:
5441 case ORDER_DISBAND:
5442 case ORDER_BUILD_WONDER:
5443 case ORDER_TRADE_ROUTE:
5444 case ORDER_HOMECITY:
5445 case ORDER_LAST:
5446 break;
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);
5457 } else {
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);
5474 i++;
5475 } unit_list_iterate_end;
5478 /****************************************************************************
5479 Load player (client) attributes data
5480 ****************************************************************************/
5481 static void sg_load_player_attributes(struct loaddata *loading,
5482 struct player *plr)
5484 int plrno = player_number(plr);
5486 /* Check status and return if not OK (sg_success != TRUE). */
5487 sg_check_ret();
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) {
5508 int part_nr, parts;
5509 size_t actual_length;
5510 int quoted_length;
5511 char *quoted;
5513 sg_failure_ret(
5514 secfile_lookup_int(loading->file, &quoted_length,
5515 "player%d.attribute_v2_block_length_quoted",
5516 plrno), "%s", secfile_error());
5517 sg_failure_ret(
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);
5523 quoted[0] = '\0';
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",
5529 plrno, part_nr);
5530 if (!current) {
5531 log_sg("attribute_v2_block_parts=%d actual=%d", parts, part_nr);
5532 break;
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));
5546 actual_length =
5547 unquote_block(quoted,
5548 plr->attribute_block.data,
5549 plr->attribute_block.length);
5550 fc_assert(actual_length == plr->attribute_block.length);
5551 free(quoted);
5555 /****************************************************************************
5556 Save player (client) attributes data.
5557 ****************************************************************************/
5558 static void sg_save_player_attributes(struct savedata *saving,
5559 struct player *plr)
5561 int plrno = player_number(plr);
5563 /* Check status and return if not OK (sg_success != TRUE). */
5564 sg_check_ret();
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];
5575 int parts;
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;
5595 } else {
5596 parts = 1;
5599 secfile_insert_int(saving->file, parts,
5600 "player%d.attribute_v2_block_parts", plrno);
5602 if (parts > 1) {
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",
5610 plrno, 0);
5611 bytes_left -= size_of_current_part;
5612 quoted_at = &quoted[size_of_current_part];
5613 current_part_nr = 1;
5614 } else {
5615 quoted_at = quoted;
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",
5626 plrno,
5627 current_part_nr);
5628 bytes_left -= size_of_current_part;
5629 quoted_at = &quoted_at[size_of_current_part];
5631 fc_assert(bytes_left == 0);
5632 free(quoted);
5634 #undef PART_ADJUST
5635 #undef PART_SIZE
5638 /****************************************************************************
5639 Load vision data
5640 ****************************************************************************/
5641 static void sg_load_player_vision(struct loaddata *loading,
5642 struct player *plr)
5644 int plrno = player_number(plr);
5645 int total_ncities =
5646 secfile_lookup_int_default(loading->file, -1,
5647 "player%d.dc_total", plrno);
5648 int i;
5650 /* Check status and return if not OK (sg_success != TRUE). */
5651 sg_check_ret();
5653 if (!plr->is_alive) {
5654 /* Reveal all for dead players. */
5655 map_know_and_see_all(plr);
5658 if (!plr->is_alive
5659 || -1 == total_ncities
5660 || FALSE == game.info.fogofwar
5661 || !secfile_lookup_bool_default(loading->file, TRUE,
5662 "game.save_private_map")) {
5663 /* We have:
5664 * - a dead player;
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; */
5684 return;
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,
5702 sg_special_set(
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). */
5730 int x, y;
5732 for (y = 0; y < map.ysize; y++) {
5733 const char *buffer
5734 = secfile_lookup_str(loading->file, "player%d.map_owner%04d",
5735 plrno, y);
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];
5742 int number;
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;
5750 continue;
5753 sg_failure_ret(str_to_int(token, &number),
5754 "Savegame corrupt - got tile owner=%s in (%d, %d).",
5755 token, x, y);
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 */
5764 if (i == 0) {
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);
5769 } else {
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;
5780 char buf[32];
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),
5786 pdcity);
5787 identity_number_reserve(pdcity->identity);
5788 } else {
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,
5816 struct player *plr,
5817 struct vision_site *pdcity,
5818 const char *citystr)
5820 const char *string;
5821 int i, id, size;
5822 citizens city_size;
5823 int nat_x, nat_y;
5825 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_x, "%s.x",
5826 citystr),
5827 FALSE, "%s", secfile_error());
5828 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_y, "%s.y",
5829 citystr),
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",
5836 citystr),
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,
5843 "%s.id", citystr),
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'.",
5867 string[i], citystr)
5869 if (string[i] == '1') {
5870 struct impr_type *pimprove =
5871 improvement_by_rule_name(loading->improvement.order[i]);
5872 if (pimprove) {
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);
5893 return TRUE;
5896 /****************************************************************************
5897 Save vision data
5898 ****************************************************************************/
5899 static void sg_save_player_vision(struct savedata *saving,
5900 struct player *plr)
5902 int i, plrno = player_number(plr);
5904 /* Check status and return if not OK (sg_success != TRUE). */
5905 sg_check_ret();
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. */
5909 return;
5912 if (!plr->is_alive) {
5913 /* Nothing to save. */
5914 return;
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). */
5929 int x, y;
5931 for (y = 0; y < map.ysize; y++) {
5932 char line[map.xsize * TOKEN_SIZE];
5934 line[0] = '\0';
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) {
5941 strcpy(token, "-");
5942 } else {
5943 fc_snprintf(token, sizeof(token), "%d",
5944 player_number(plrtile->owner));
5946 strcat(line, token);
5947 if (x < map.xsize) {
5948 strcat(line, ",");
5951 secfile_insert_str(saving->file, line, "player%d.map_owner%04d",
5952 plrno, y);
5956 /* Save the map (specials). */
5957 halfbyte_iterate_special(j, S_LAST) {
5958 enum tile_special_type mod[4];
5959 int l;
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,
5966 mod), saving->file,
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) {
5972 int mod[4];
5973 int l;
5975 for (l = 0; l < 4; l++) {
5976 if (4 * j + 1 > game.control.num_base_types) {
5977 mod[l] = -1;
5978 } else {
5979 mod[l] = 4 * j + l;
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) {
5990 int mod[4];
5991 int l;
5993 for (l = 0; l < 4; l++) {
5994 if (4 * j + 1 > game.control.num_road_types) {
5995 mod[l] = -1;
5996 } else {
5997 mod[l] = 4 * j + l;
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,
6010 bin2ascii_hex(
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. */
6016 i = 0;
6017 whole_map_iterate(ptile) {
6018 struct vision_site *pdcity = map_get_player_city(ptile, plr);
6019 char impr_buf[MAX_NUM_ITEMS + 1];
6020 char buf[32];
6022 fc_snprintf(buf, sizeof(buf), "player%d.dc%d", plrno, i);
6024 if (NULL != pdcity && plr != vision_site_owner(pdcity)) {
6025 int nat_x, nat_y;
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)),
6033 "%s.owner", buf);
6035 secfile_insert_int(saving->file, vision_site_size_get(pdcity),
6036 "%s.size", buf);
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))
6049 ? '1' : '0';
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);
6059 i++;
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). */
6076 sg_check_ret();
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). */
6087 sg_check_ret();
6089 if (saving->scenario) {
6090 /* Do _not_ save events in a scenario. */
6091 return;
6094 event_cache_save(saving->file, "event_cache");
6097 /* =======================================================================
6098 * Load / save the mapimg definitions.
6099 * ======================================================================= */
6101 /****************************************************************************
6102 Load '[mapimg]'.
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). */
6109 sg_check_ret();
6111 /* Clear all defined map images. */
6112 while (mapimg_count() > 0) {
6113 mapimg_delete(0);
6116 mapdef_count = secfile_lookup_int_default(loading->file, 0,
6117 "mapimg.count");
6118 log_verbose("Saved map image definitions: %d.", mapdef_count);
6120 if (0 >= mapdef_count) {
6121 return;
6124 for (i = 0; i < mapdef_count; i++) {
6125 const char *p;
6127 p = secfile_lookup_str(loading->file, "mapimg.mapdef%d", i);
6128 if (NULL == p) {
6129 log_verbose("[Mapimg %4d] Missing definition.", i);
6130 continue;
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 /****************************************************************************
6142 Save '[mapimg]'.
6143 ****************************************************************************/
6144 static void sg_save_mapimg(struct savedata *saving)
6146 /* Check status and return if not OK (sg_success != TRUE). */
6147 sg_check_ret();
6149 secfile_insert_int(saving->file, mapimg_count(), "mapimg.count");
6150 if (mapimg_count() > 0) {
6151 int i;
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)
6171 int players;
6173 /* Check status and return if not OK (sg_success != TRUE). */
6174 sg_check_ret();
6176 if (game.info.is_new_game) {
6177 /* Nothing to do for new games (or not started scenarios). */
6178 return;
6181 /* Old savegames may have maxplayers lower than current player count,
6182 * fix. */
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,
6216 &punit->activity,
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 */
6241 #ifdef DEBUG
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;
6251 #endif /* DEBUG */
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. */
6272 sanity_check();
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). */
6281 sg_check_ret();
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). */
6294 sg_check_ret();
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)) {
6303 continue;
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);
6315 if (ncities > 0) {
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);
6319 if (size > 0) {
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");
6341 if (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;
6347 *newname = 'k';
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);
6352 FC_FREE(name2);
6354 } entry_list_iterate_end;
6356 /* Could remove "knownv2" from savefile.options, but it's doing
6357 * no harm there. */
6358 } else {
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 */
6371 bool found = FALSE;
6372 memset(known_row_old, 0, sizeof(known_row_old));
6373 for (l = 0; l < lines; l++) {
6374 for (j = 0; j < 8; j++) {
6375 const char *s =
6376 secfile_lookup_str_default(loading->file, NULL,
6377 "map.k%02d_%04d", l * 8 + j, y);
6378 if (s) {
6379 found = TRUE;
6380 if (xsize == 0) {
6381 xsize = strlen(s);
6383 sg_failure_ret(xsize == strlen(s),
6384 "Inconsistent xsize in map.k%02d_%04d",
6385 l * 8 + j, y);
6386 for (x = 0; x < xsize; x++) {
6387 known_row_old[l * xsize + x] |= ascii_hex2bin(s[x], j);
6392 if (found) {
6393 /* At least one entry found for this row. Let's hope they were
6394 * all there. */
6395 /* Attempt to munge into sane format */
6396 int p;
6397 memset(known_row, 0, sizeof(known_row));
6398 /* Iterate over possible player slots */
6399 for (p = 0; p < maxslots; p++) {
6400 l = p / 32;
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. */
6416 char row[xsize+1];
6417 for (x = 0; x < xsize; x++) {
6418 row[x] = bin2ascii_hex(known_row[l * xsize + x], j);
6420 row[xsize] = '\0';
6421 secfile_replace_str(loading->file, row,
6422 "map.k%02d_%04d", l * 8 + j, y);
6430 /* Server setting migration. */
6432 int set_count;
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++) {
6439 const char *name
6440 = secfile_lookup_str(loading->file, "settings.set%d.name", i);
6441 if (!name) {
6442 continue;
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";
6453 int nturns;
6455 if (secfile_lookup_int(loading->file, &nturns,
6456 "settings.set%d.value", i)) {
6457 if (nturns == 0) {
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);
6464 } else {
6465 secfile_insert_str(loading->file, save,
6466 "settings.set%d.value", new_opt);
6468 } else {
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)) {
6474 if (nturns == 0) {
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);
6481 } else {
6482 secfile_insert_str(loading->file, save,
6483 "settings.set%d.gamestart", new_opt);
6485 } else {
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)
6505 switch (bit) {
6506 case UMT_LAND:
6507 return "LAND";
6508 case UMT_SEA:
6509 return "SEA";
6510 case UMT_BOTH:
6511 return "BOTH";
6514 return NULL;
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). */
6525 sg_check_ret();
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. */
6536 int set_count;
6538 if (secfile_lookup_int(loading->file, &set_count, "settings.set_count")) {
6539 int i;
6540 bool gamestart_valid
6541 = secfile_lookup_bool_default(loading->file, FALSE,
6542 "settings.gamestart_valid");
6543 for (i = 0; i < set_count; i++) {
6544 const char *name
6545 = secfile_lookup_str(loading->file, "settings.set%d.name", i);
6546 if (!name) {
6547 continue;
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)) {
6554 int value;
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. */
6562 if (value & 0x1) {
6563 secfile_replace_bool(loading->file, TRUE,
6564 "settings.set%d.value", i);
6565 } else {
6566 secfile_replace_bool(loading->file, FALSE,
6567 "settings.set%d.value", i);
6569 } else {
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. */
6579 if (value & 0x1) {
6580 secfile_replace_bool(loading->file, TRUE,
6581 "settings.set%d.gamestart", i);
6582 } else {
6583 secfile_replace_bool(loading->file, FALSE,
6584 "settings.set%d.gamestart", i);
6586 } else {
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)
6605 int i;
6607 /* Check status and return if not OK (sg_success != TRUE). */
6608 sg_check_ret();
6610 loading->version = secfile_lookup_int_default(loading->file, -1,
6611 "savefile.version");
6612 #ifdef DEBUG
6613 sg_failure_ret(0 < loading->version, "Invalid savefile format version (%d).",
6614 loading->version);
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);
6621 #else
6622 sg_failure_ret(0 < loading->version
6623 && loading->version <= compat[compat_current].version,
6624 "Unknown savefile format version (%d).", loading->version);
6625 #endif /* DEBUG */
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);