Remove hard limitation that AI wonder cities never build settlers
[freeciv.git] / server / savegame2.c
blobdf3fe99c6994b3e39091ef3242576c33530a51cf
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 Structure of this file:
25 - The main functions are savegame2_load() and savegame2_save(). Within
26 former function the savegame version is tested and the requested savegame version is
27 loaded.
29 - The real work is done by savegame2_load_real() and savegame2_save_real().
30 This function call all submodules (settings, players, etc.)
32 - The remaining part of this file is split into several sections:
33 * helper functions
34 * save / load functions for all submodules (and their subsubmodules)
36 - If possible, all functions for load / save submodules should exit in
37 pairs named sg_load_<submodule> and sg_save_<submodule>. If one is not
38 needed please add a comment why.
40 - The submodules can be further divided as:
41 sg_load_<submodule>_<subsubmodule>
43 - If needed (due to static variables in the *.c files) these functions
44 can be located in the corresponding source files (as done for the settings
45 and the event_cache).
47 Creating a savegame:
49 (nothing at the moment)
51 Loading a savegame:
53 - The status of the process is saved within the static variable
54 'sg_success'. This variable is set to TRUE within savegame2_load_real().
55 If you encounter an error use sg_failure_*() to set it to FALSE and
56 return an error message. Furthermore, sg_check_* should be used at the
57 start of each (submodule) function to return if previous functions failed.
59 - While the loading process dependencies between different modules exits.
60 They can be handled within the struct loaddata *loading which is used as
61 first argument for all sg_load_*() function. Please indicate the
62 dependencies within the definition of this struct.
66 #ifdef HAVE_CONFIG_H
67 #include <fc_config.h>
68 #endif
70 #include <ctype.h>
71 #include <stdarg.h>
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
76 /* utility */
77 #include "bitvector.h"
78 #include "fcintl.h"
79 #include "idex.h"
80 #include "log.h"
81 #include "mem.h"
82 #include "rand.h"
83 #include "registry.h"
84 #include "shared.h"
85 #include "support.h" /* bool type */
86 #include "timing.h"
88 /* common */
89 #include "achievements.h"
90 #include "ai.h"
91 #include "bitvector.h"
92 #include "capability.h"
93 #include "citizens.h"
94 #include "city.h"
95 #include "game.h"
96 #include "government.h"
97 #include "map.h"
98 #include "mapimg.h"
99 #include "movement.h"
100 #include "multipliers.h"
101 #include "packets.h"
102 #include "research.h"
103 #include "rgbcolor.h"
104 #include "specialist.h"
105 #include "unit.h"
106 #include "unitlist.h"
107 #include "version.h"
109 /* server */
110 #include "barbarian.h"
111 #include "citizenshand.h"
112 #include "citytools.h"
113 #include "cityturn.h"
114 #include "diplhand.h"
115 #include "maphand.h"
116 #include "meta.h"
117 #include "notify.h"
118 #include "plrhand.h"
119 #include "report.h"
120 #include "ruleset.h"
121 #include "sanitycheck.h"
122 #include "savecompat.h"
123 #include "savegame.h"
124 #include "score.h"
125 #include "settings.h"
126 #include "spacerace.h"
127 #include "srv_main.h"
128 #include "stdinhand.h"
129 #include "techtools.h"
130 #include "unittools.h"
132 /* server/advisors */
133 #include "advdata.h"
134 #include "advbuilding.h"
135 #include "infracache.h"
137 /* server/generator */
138 #include "mapgen.h"
139 #include "utilities.h"
141 /* server/scripting */
142 #include "script_server.h"
144 /* ai */
145 #include "aitraits.h"
146 #include "difficulty.h"
148 #include "savegame2.h"
150 extern bool sg_success;
152 #ifdef FREECIV_TESTMATIC
153 #define SAVE_DUMMY_TURN_CHANGE_TIME 1
154 #endif
157 * This loops over the entire map to save data. It collects all the data of
158 * a line using GET_XY_CHAR and then executes the macro SECFILE_INSERT_LINE.
160 * Parameters:
161 * ptile: current tile within the line (used by GET_XY_CHAR)
162 * GET_XY_CHAR: macro returning the map character for each position
163 * secfile: a secfile struct
164 * secpath, ...: path as used for sprintf() with arguments; the last item
165 * will be the the y coordinate
166 * Example:
167 * SAVE_MAP_CHAR(ptile, terrain2char(ptile->terrain), file, "map.t%04d");
169 #define SAVE_MAP_CHAR(ptile, GET_XY_CHAR, secfile, secpath, ...) \
171 char _line[game.map.xsize + 1]; \
172 int _nat_x, _nat_y; \
174 for (_nat_y = 0; _nat_y < game.map.ysize; _nat_y++) { \
175 for (_nat_x = 0; _nat_x < game.map.xsize; _nat_x++) { \
176 struct tile *ptile = native_pos_to_tile(_nat_x, _nat_y); \
177 fc_assert_action(ptile != NULL, continue); \
178 _line[_nat_x] = (GET_XY_CHAR); \
179 sg_failure_ret(fc_isprint(_line[_nat_x] & 0x7f), \
180 "Trying to write invalid map data at position " \
181 "(%d, %d) for path %s: '%c' (%d)", _nat_x, _nat_y, \
182 secpath, _line[_nat_x], _line[_nat_x]); \
184 _line[game.map.xsize] = '\0'; \
185 secfile_insert_str(secfile, _line, secpath, ## __VA_ARGS__, _nat_y); \
190 * This loops over the entire map to load data. It inputs a line of data
191 * using the macro SECFILE_LOOKUP_LINE and then loops using the macro
192 * SET_XY_CHAR to load each char into the map at (map_x, map_y). Internal
193 * variables ch, map_x, map_y, nat_x, and nat_y are allocated within the
194 * macro but definable by the caller.
196 * Parameters:
197 * ch: a variable to hold a char (data for a single position,
198 * used by SET_XY_CHAR)
199 * ptile: current tile within the line (used by SET_XY_CHAR)
200 * SET_XY_CHAR: macro to load the map character at each (map_x, map_y)
201 * secfile: a secfile struct
202 * secpath, ...: path as used for sprintf() with arguments; the last item
203 * will be the the y coordinate
204 * Example:
205 * LOAD_MAP_CHAR(ch, ptile,
206 * map_get_player_tile(ptile, plr)->terrain
207 * = char2terrain(ch), file, "player%d.map_t%04d", plrno);
209 * Note: some (but not all) of the code this is replacing used to skip over
210 * lines that did not exist. This allowed for backward-compatibility.
211 * We could add another parameter that specified whether it was OK to
212 * skip the data, but there's not really much advantage to exiting
213 * early in this case. Instead, we let any map data type to be empty,
214 * and just print an informative warning message about it.
216 #define LOAD_MAP_CHAR(ch, ptile, SET_XY_CHAR, secfile, secpath, ...) \
218 int _nat_x, _nat_y; \
219 bool _printed_warning = FALSE; \
220 for (_nat_y = 0; _nat_y < game.map.ysize; _nat_y++) { \
221 const char *_line = secfile_lookup_str(secfile, secpath, \
222 ## __VA_ARGS__, _nat_y); \
223 if (NULL == _line) { \
224 char buf[64]; \
225 fc_snprintf(buf, sizeof(buf), secpath, ## __VA_ARGS__, _nat_y); \
226 log_verbose("Line not found='%s'", buf); \
227 _printed_warning = TRUE; \
228 continue; \
229 } else if (strlen(_line) != game.map.xsize) { \
230 char buf[64]; \
231 fc_snprintf(buf, sizeof(buf), secpath, ## __VA_ARGS__, _nat_y); \
232 log_verbose("Line too short (expected %d got %lu)='%s'", \
233 game.map.xsize, (unsigned long) strlen(_line), buf); \
234 _printed_warning = TRUE; \
235 continue; \
237 for (_nat_x = 0; _nat_x < game.map.xsize; _nat_x++) { \
238 const char ch = _line[_nat_x]; \
239 struct tile *ptile = native_pos_to_tile(_nat_x, _nat_y); \
240 (SET_XY_CHAR); \
243 if (_printed_warning) { \
244 /* TRANS: Minor error message. */ \
245 log_sg(_("Saved game contains incomplete map data. This can" \
246 " happen with old saved games, or it may indicate an" \
247 " invalid saved game file. Proceed at your own risk.")); \
251 /* Iterate on the extras half-bytes */
252 #define halfbyte_iterate_extras(e, num_extras_types) \
254 int e; \
255 for(e = 0; 4 * e < (num_extras_types); e++) {
257 #define halfbyte_iterate_extras_end \
261 /* Iterate on the specials half-bytes */
262 #define halfbyte_iterate_special(s, num_specials_types) \
264 enum tile_special_type s; \
265 for(s = 0; 4 * s < (num_specials_types); s++) {
267 #define halfbyte_iterate_special_end \
271 /* Iterate on the bases half-bytes */
272 #define halfbyte_iterate_bases(b, num_bases_types) \
274 int b; \
275 for(b = 0; 4 * b < (num_bases_types); b++) {
277 #define halfbyte_iterate_bases_end \
281 /* Iterate on the roads half-bytes */
282 #define halfbyte_iterate_roads(r, num_roads_types) \
284 int r; \
285 for(r = 0; 4 * r < (num_roads_types); r++) {
287 #define halfbyte_iterate_roads_end \
291 struct savedata {
292 struct section_file *file;
293 char secfile_options[512];
295 /* set by the caller */
296 const char *save_reason;
297 bool scenario;
299 /* Set in sg_save_game(); needed in sg_save_map_*(); ... */
300 bool save_players;
303 #define TOKEN_SIZE 10
305 #define log_worker log_verbose
307 static const char savefile_options_default[] =
308 " +version2";
309 /* The following savefile option are added if needed:
310 * - specials
311 * - riversoverlay
312 * See also calls to sg_save_savefile_options(). */
314 static const char num_chars[] =
315 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-+";
317 static void savegame2_load_real(struct section_file *file);
318 static void savegame2_save_real(struct section_file *file,
319 const char *save_reason,
320 bool scenario);
321 static struct loaddata *loaddata_new(struct section_file *file);
322 static void loaddata_destroy(struct loaddata *loading);
324 static struct savedata *savedata_new(struct section_file *file,
325 const char *save_reason,
326 bool scenario);
327 static void savedata_destroy(struct savedata *saving);
329 static enum unit_orders char2order(char order);
330 static char order2char(enum unit_orders order);
331 static enum direction8 char2dir(char dir);
332 static char dir2char(enum direction8 dir);
333 static char activity2char(enum unit_activity activity);
334 static enum unit_activity char2activity(char activity);
335 static char *quote_block(const void *const data, int length);
336 static int unquote_block(const char *const quoted_, void *dest,
337 int dest_length);
338 static void worklist_load(struct section_file *file, struct worklist *pwl,
339 const char *path, ...);
340 static void worklist_save(struct section_file *file,
341 const struct worklist *pwl,
342 int max_length, const char *path, ...);
343 static void unit_ordering_calc(void);
344 static void unit_ordering_apply(void);
345 static void sg_extras_set(bv_extras *extras, char ch, struct extra_type **idx);
346 static char sg_extras_get(bv_extras extras, const int *idx);
347 static void sg_special_set(struct tile *ptile, bv_extras *extras, char ch,
348 const enum tile_special_type *idx,
349 bool rivers_overlay);
350 static void sg_bases_set(bv_extras *extras, char ch, struct base_type **idx);
351 static void sg_roads_set(bv_extras *extras, char ch, struct road_type **idx);
352 static struct resource *char2resource(char c);
353 static char resource2char(const struct resource *presource);
354 static char num2char(unsigned int num);
355 static int char2num(char ch);
356 static struct terrain *char2terrain(char ch);
357 static char terrain2char(const struct terrain *pterrain);
358 static Tech_type_id technology_load(struct section_file *file,
359 const char* path, int plrno);
360 static void technology_save(struct section_file *file,
361 const char* path, int plrno, Tech_type_id tech);
363 static void sg_load_ruleset(struct loaddata *loading);
364 static void sg_load_savefile(struct loaddata *loading);
365 static void sg_save_savefile(struct savedata *saving);
366 static void sg_save_savefile_options(struct savedata *saving,
367 const char *option);
369 static void sg_load_game(struct loaddata *loading);
370 static void sg_save_game(struct savedata *saving);
372 static void sg_load_ruledata(struct loaddata *loading);
373 static void sg_save_ruledata(struct savedata *saving);
375 static void sg_load_random(struct loaddata *loading);
376 static void sg_save_random(struct savedata *saving);
378 static void sg_load_script(struct loaddata *loading);
379 static void sg_save_script(struct savedata *saving);
381 static void sg_load_scenario(struct loaddata *loading);
382 static void sg_save_scenario(struct savedata *saving);
384 static void sg_load_settings(struct loaddata *loading);
385 static void sg_save_settings(struct savedata *saving);
387 static void sg_load_map(struct loaddata *loading);
388 static void sg_save_map(struct savedata *saving);
389 static void sg_load_map_tiles(struct loaddata *loading);
390 static void sg_save_map_tiles(struct savedata *saving);
391 static void sg_load_map_tiles_extras(struct loaddata *loading);
392 static void sg_save_map_tiles_extras(struct savedata *saving);
393 static void sg_load_map_tiles_bases(struct loaddata *loading);
394 static void sg_load_map_tiles_roads(struct loaddata *loading);
395 static void sg_load_map_tiles_specials(struct loaddata *loading,
396 bool rivers_overlay);
397 static void sg_load_map_tiles_resources(struct loaddata *loading);
398 static void sg_save_map_tiles_resources(struct savedata *saving);
400 static void sg_load_map_startpos(struct loaddata *loading);
401 static void sg_save_map_startpos(struct savedata *saving);
402 static void sg_load_map_owner(struct loaddata *loading);
403 static void sg_save_map_owner(struct savedata *saving);
404 static void sg_load_map_worked(struct loaddata *loading);
405 static void sg_save_map_worked(struct savedata *saving);
406 static void sg_load_map_known(struct loaddata *loading);
407 static void sg_save_map_known(struct savedata *saving);
409 static void sg_load_players_basic(struct loaddata *loading);
410 static void sg_load_players(struct loaddata *loading);
411 static void sg_load_player_main(struct loaddata *loading,
412 struct player *plr);
413 static void sg_load_player_cities(struct loaddata *loading,
414 struct player *plr);
415 static bool sg_load_player_city(struct loaddata *loading, struct player *plr,
416 struct city *pcity, const char *citystr);
417 static void sg_load_player_city_citizens(struct loaddata *loading,
418 struct player *plr,
419 struct city *pcity,
420 const char *citystr);
421 static void sg_load_player_units(struct loaddata *loading,
422 struct player *plr);
423 static bool sg_load_player_unit(struct loaddata *loading,
424 struct player *plr, struct unit *punit,
425 const char *unitstr);
426 static void sg_load_player_units_transport(struct loaddata *loading,
427 struct player *plr);
428 static void sg_load_player_attributes(struct loaddata *loading,
429 struct player *plr);
430 static void sg_load_player_vision(struct loaddata *loading,
431 struct player *plr);
432 static bool sg_load_player_vision_city(struct loaddata *loading,
433 struct player *plr,
434 struct vision_site *pdcity,
435 const char *citystr);
436 static void sg_save_players(struct savedata *saving);
437 static void sg_save_player_main(struct savedata *saving,
438 struct player *plr);
439 static void sg_save_player_cities(struct savedata *saving,
440 struct player *plr);
441 static void sg_save_player_units(struct savedata *saving,
442 struct player *plr);
443 static void sg_save_player_attributes(struct savedata *saving,
444 struct player *plr);
445 static void sg_save_player_vision(struct savedata *saving,
446 struct player *plr);
448 static void sg_load_researches(struct loaddata *loading);
449 static void sg_save_researches(struct savedata *saving);
451 static void sg_load_event_cache(struct loaddata *loading);
452 static void sg_save_event_cache(struct savedata *saving);
454 static void sg_save_treaties(struct savedata *saving);
456 static void sg_load_treaties(struct loaddata *loading);
458 static void sg_load_history(struct loaddata *loading);
459 static void sg_save_history(struct savedata *saving);
461 static void sg_load_mapimg(struct loaddata *loading);
462 static void sg_save_mapimg(struct savedata *saving);
464 static void sg_load_sanitycheck(struct loaddata *loading);
465 static void sg_save_sanitycheck(struct savedata *saving);
468 /****************************************************************************
469 Main entry point for loading a game.
470 Called only in ./server/stdinhand.c:load_command().
471 The entire ruleset is always sent afterwards->
472 ****************************************************************************/
473 void savegame2_load(struct section_file *file)
475 const char *savefile_options;
477 fc_assert_ret(file != NULL);
479 #ifdef DEBUG_TIMERS
480 struct timer *loadtimer = timer_new(TIMER_CPU, TIMER_DEBUG);
481 timer_start(loadtimer);
482 #endif
484 savefile_options = secfile_lookup_str(file, "savefile.options");
486 if (!savefile_options) {
487 log_error("Missing savefile options. Can not load the savegame.");
488 return;
491 if (!has_capabilities("+version2", savefile_options)) {
492 /* load old format (freeciv 2.2.x) */
493 log_verbose("loading savefile in old format ...");
494 secfile_allow_digital_boolean(file, TRUE);
495 legacy_game_load(file);
496 } else {
497 /* load new format (freeciv 2.2.99 and newer) */
498 log_verbose("loading savefile in new format ...");
499 savegame2_load_real(file);
502 #ifdef DEBUG_TIMERS
503 timer_stop(loadtimer);
504 log_debug("Loading secfile in %.3f seconds.", timer_read_seconds(loadtimer));
505 timer_destroy(loadtimer);
506 #endif /* DEBUG_TIMERS */
509 /****************************************************************************
510 Main entry point for saving a game.
511 Called only in ./server/srv_main.c:save_game().
512 ****************************************************************************/
513 void savegame2_save(struct section_file *file, const char *save_reason,
514 bool scenario)
516 fc_assert_ret(file != NULL);
518 #ifdef DEBUG_TIMERS
519 struct timer *savetimer = timer_new(TIMER_CPU, TIMER_DEBUG);
520 timer_start(savetimer);
521 #endif
523 log_verbose("saving game in new format ...");
524 savegame2_save_real(file, save_reason, scenario);
526 #ifdef DEBUG_TIMERS
527 timer_stop(savetimer);
528 log_debug("Creating secfile in %.3f seconds.", timer_read_seconds(savetimer));
529 timer_destroy(savetimer);
530 #endif /* DEBUG_TIMERS */
533 /* =======================================================================
534 * Basic load / save functions.
535 * ======================================================================= */
537 /****************************************************************************
538 Really loading the savegame.
539 ****************************************************************************/
540 static void savegame2_load_real(struct section_file *file)
542 struct loaddata *loading;
543 bool was_send_city_suppressed, was_send_tile_suppressed;
545 /* initialise loading */
546 was_send_city_suppressed = send_city_suppression(TRUE);
547 was_send_tile_suppressed = send_tile_suppression(TRUE);
548 loading = loaddata_new(file);
549 sg_success = TRUE;
551 /* Load the savegame data. */
552 /* Set up correct ruleset */
553 sg_load_ruleset(loading);
554 /* [compat] */
555 sg_load_compat(loading);
556 /* [savefile] */
557 sg_load_savefile(loading);
558 /* [game] */
559 sg_load_game(loading);
560 /* [scenario] */
561 sg_load_scenario(loading);
562 /* [random] */
563 sg_load_random(loading);
564 /* [script] */
565 sg_load_script(loading);
566 /* [settings] */
567 sg_load_settings(loading);
568 /* [ruldata] */
569 sg_load_ruledata(loading);
570 /* [players] (basic data) */
571 sg_load_players_basic(loading);
572 /* [map]; needs width and height loaded by [settings] */
573 sg_load_map(loading);
574 /* [research] */
575 sg_load_researches(loading);
576 /* [player<i>] */
577 sg_load_players(loading);
578 /* [event_cache] */
579 sg_load_event_cache(loading);
580 /* [treaties] */
581 sg_load_treaties(loading);
582 /* [history] */
583 sg_load_history(loading);
584 /* [mapimg] */
585 sg_load_mapimg(loading);
587 /* Sanity checks for the loaded game. */
588 sg_load_sanitycheck(loading);
590 /* deinitialise loading */
591 loaddata_destroy(loading);
592 send_tile_suppression(was_send_tile_suppressed);
593 send_city_suppression(was_send_city_suppressed);
595 if (!sg_success) {
596 log_error("Failure loading savegame!");
597 game_reset();
601 /****************************************************************************
602 Really save the game to a file.
603 ****************************************************************************/
604 static void savegame2_save_real(struct section_file *file,
605 const char *save_reason,
606 bool scenario)
608 struct savedata *saving;
610 /* initialise loading */
611 saving = savedata_new(file, save_reason, scenario);
612 sg_success = TRUE;
614 /* [scenario] */
615 /* This should be first section so scanning through all scenarios just for
616 * names and descriptions would go faster. */
617 sg_save_scenario(saving);
618 /* [savefile] */
619 sg_save_savefile(saving);
620 /* [game] */
621 sg_save_game(saving);
622 /* [random] */
623 sg_save_random(saving);
624 /* [script] */
625 sg_save_script(saving);
626 /* [settings] */
627 sg_save_settings(saving);
628 /* [ruledata] */
629 sg_save_ruledata(saving);
630 /* [map] */
631 sg_save_map(saving);
632 /* [player<i>] */
633 sg_save_players(saving);
634 /* [research] */
635 sg_save_researches(saving);
636 /* [event_cache] */
637 sg_save_event_cache(saving);
638 /* [treaty<i>] */
639 sg_save_treaties(saving);
640 /* [history] */
641 sg_save_history(saving);
642 /* [mapimg] */
643 sg_save_mapimg(saving);
645 /* Sanity checks for the saved game. */
646 sg_save_sanitycheck(saving);
648 /* deinitialise saving */
649 savedata_destroy(saving);
651 if (!sg_success) {
652 log_error("Failure saving savegame!");
656 /****************************************************************************
657 Create new loaddata item for given section file.
658 ****************************************************************************/
659 static struct loaddata *loaddata_new(struct section_file *file)
661 struct loaddata *loading = calloc(1, sizeof(*loading));
662 loading->file = file;
663 loading->secfile_options = NULL;
665 loading->improvement.order = NULL;
666 loading->improvement.size = -1;
667 loading->technology.order = NULL;
668 loading->technology.size = -1;
669 loading->trait.order = NULL;
670 loading->trait.size = -1;
671 loading->extra.order = NULL;
672 loading->extra.size = -1;
673 loading->multiplier.order = NULL;
674 loading->multiplier.size = -1;
675 loading->special.order = NULL;
676 loading->special.size = -1;
677 loading->base.order = NULL;
678 loading->base.size = -1;
679 loading->road.order = NULL;
680 loading->road.size = -1;
681 loading->specialist.order = NULL;
682 loading->specialist.size = -1;
683 loading->ds_t.order = NULL;
684 loading->ds_t.size = -1;
686 loading->server_state = S_S_INITIAL;
687 loading->rstate = fc_rand_state();
688 loading->worked_tiles = NULL;
690 return loading;
693 /****************************************************************************
694 Free resources allocated for loaddata item.
695 ****************************************************************************/
696 static void loaddata_destroy(struct loaddata *loading)
698 if (loading->improvement.order != NULL) {
699 free(loading->improvement.order);
702 if (loading->technology.order != NULL) {
703 free(loading->technology.order);
706 if (loading->trait.order != NULL) {
707 free(loading->trait.order);
710 if (loading->extra.order != NULL) {
711 free(loading->extra.order);
714 if (loading->multiplier.order != NULL) {
715 free(loading->multiplier.order);
718 if (loading->special.order != NULL) {
719 free(loading->special.order);
722 if (loading->base.order != NULL) {
723 free(loading->base.order);
726 if (loading->road.order != NULL) {
727 free(loading->road.order);
730 if (loading->specialist.order != NULL) {
731 free(loading->specialist.order);
734 if (loading->ds_t.order != NULL) {
735 free(loading->ds_t.order);
738 if (loading->worked_tiles != NULL) {
739 free(loading->worked_tiles);
742 free(loading);
745 /****************************************************************************
746 Create new savedata item for given file.
747 ****************************************************************************/
748 static struct savedata *savedata_new(struct section_file *file,
749 const char *save_reason,
750 bool scenario)
752 struct savedata *saving = calloc(1, sizeof(*saving));
753 saving->file = file;
754 saving->secfile_options[0] = '\0';
756 saving->save_reason = save_reason;
757 saving->scenario = scenario;
759 saving->save_players = FALSE;
761 return saving;
764 /****************************************************************************
765 Free resources allocated for savedata item
766 ****************************************************************************/
767 static void savedata_destroy(struct savedata *saving)
769 free(saving);
772 /* =======================================================================
773 * Helper functions.
774 * ======================================================================= */
776 /****************************************************************************
777 Returns an order for a character identifier. See also order2char.
778 ****************************************************************************/
779 static enum unit_orders char2order(char order)
781 switch (order) {
782 case 'm':
783 case 'M':
784 return ORDER_MOVE;
785 case 'w':
786 case 'W':
787 return ORDER_FULL_MP;
788 case 'b':
789 case 'B':
790 return ORDER_BUILD_CITY;
791 case 'a':
792 case 'A':
793 return ORDER_ACTIVITY;
794 case 'd':
795 case 'D':
796 return ORDER_DISBAND;
797 case 'u':
798 case 'U':
799 return ORDER_BUILD_WONDER;
800 case 't':
801 case 'T':
802 return ORDER_TRADE_ROUTE;
803 case 'h':
804 case 'H':
805 return ORDER_HOMECITY;
806 case 'x':
807 case 'X':
808 return ORDER_ACTION_MOVE;
811 /* This can happen if the savegame is invalid. */
812 return ORDER_LAST;
815 /****************************************************************************
816 Returns a character identifier for an order. See also char2order.
817 ****************************************************************************/
818 static char order2char(enum unit_orders order)
820 switch (order) {
821 case ORDER_MOVE:
822 return 'm';
823 case ORDER_FULL_MP:
824 return 'w';
825 case ORDER_ACTIVITY:
826 return 'a';
827 case ORDER_BUILD_CITY:
828 return 'b';
829 case ORDER_DISBAND:
830 return 'd';
831 case ORDER_BUILD_WONDER:
832 return 'u';
833 case ORDER_TRADE_ROUTE:
834 return 't';
835 case ORDER_HOMECITY:
836 return 'h';
837 case ORDER_ACTION_MOVE:
838 return 'x';
839 case ORDER_LAST:
840 break;
843 fc_assert(FALSE);
844 return '?';
847 /****************************************************************************
848 Returns a direction for a character identifier. See also dir2char.
849 ****************************************************************************/
850 static enum direction8 char2dir(char dir)
852 /* Numberpad values for the directions. */
853 switch (dir) {
854 case '1':
855 return DIR8_SOUTHWEST;
856 case '2':
857 return DIR8_SOUTH;
858 case '3':
859 return DIR8_SOUTHEAST;
860 case '4':
861 return DIR8_WEST;
862 case '6':
863 return DIR8_EAST;
864 case '7':
865 return DIR8_NORTHWEST;
866 case '8':
867 return DIR8_NORTH;
868 case '9':
869 return DIR8_NORTHEAST;
872 /* This can happen if the savegame is invalid. */
873 return direction8_invalid();
876 /****************************************************************************
877 Returns a character identifier for a direction. See also char2dir.
878 ****************************************************************************/
879 static char dir2char(enum direction8 dir)
881 /* Numberpad values for the directions. */
882 switch (dir) {
883 case DIR8_NORTH:
884 return '8';
885 case DIR8_SOUTH:
886 return '2';
887 case DIR8_EAST:
888 return '6';
889 case DIR8_WEST:
890 return '4';
891 case DIR8_NORTHEAST:
892 return '9';
893 case DIR8_NORTHWEST:
894 return '7';
895 case DIR8_SOUTHEAST:
896 return '3';
897 case DIR8_SOUTHWEST:
898 return '1';
901 fc_assert(FALSE);
902 return '?';
905 /****************************************************************************
906 Returns a character identifier for an activity. See also char2activity.
907 ****************************************************************************/
908 static char activity2char(enum unit_activity activity)
910 switch (activity) {
911 case ACTIVITY_IDLE:
912 return 'w';
913 case ACTIVITY_POLLUTION:
914 return 'p';
915 case ACTIVITY_OLD_ROAD:
916 return 'r';
917 case ACTIVITY_MINE:
918 return 'm';
919 case ACTIVITY_IRRIGATE:
920 return 'i';
921 case ACTIVITY_FORTIFIED:
922 return 'f';
923 case ACTIVITY_FORTRESS:
924 return 't';
925 case ACTIVITY_SENTRY:
926 return 's';
927 case ACTIVITY_OLD_RAILROAD:
928 return 'l';
929 case ACTIVITY_PILLAGE:
930 return 'e';
931 case ACTIVITY_GOTO:
932 return 'g';
933 case ACTIVITY_EXPLORE:
934 return 'x';
935 case ACTIVITY_TRANSFORM:
936 return 'o';
937 case ACTIVITY_AIRBASE:
938 return 'a';
939 case ACTIVITY_FORTIFYING:
940 return 'y';
941 case ACTIVITY_FALLOUT:
942 return 'u';
943 case ACTIVITY_BASE:
944 return 'b';
945 case ACTIVITY_GEN_ROAD:
946 return 'R';
947 case ACTIVITY_CONVERT:
948 return 'c';
949 case ACTIVITY_UNKNOWN:
950 case ACTIVITY_PATROL_UNUSED:
951 return '?';
952 case ACTIVITY_LAST:
953 break;
956 fc_assert(FALSE);
957 return '?';
960 /****************************************************************************
961 Returns an activity for a character identifier. See also activity2char.
962 ****************************************************************************/
963 static enum unit_activity char2activity(char activity)
965 enum unit_activity a;
967 for (a = 0; a < ACTIVITY_LAST; a++) {
968 char achar = activity2char(a);
970 if (activity == achar) {
971 return a;
975 /* This can happen if the savegame is invalid. */
976 return ACTIVITY_LAST;
979 /****************************************************************************
980 Quote the memory block denoted by data and length so it consists only of
981 " a-f0-9:". The returned string has to be freed by the caller using free().
982 ****************************************************************************/
983 static char *quote_block(const void *const data, int length)
985 char *buffer = fc_malloc(length * 3 + 10);
986 size_t offset;
987 int i;
989 sprintf(buffer, "%d:", length);
990 offset = strlen(buffer);
992 for (i = 0; i < length; i++) {
993 sprintf(buffer + offset, "%02x ", ((unsigned char *) data)[i]);
994 offset += 3;
996 return buffer;
999 /****************************************************************************
1000 Unquote a string. The unquoted data is written into dest. If the unquoted
1001 data will be larger than dest_length the function aborts. It returns the
1002 actual length of the unquoted block.
1003 ****************************************************************************/
1004 static int unquote_block(const char *const quoted_, void *dest,
1005 int dest_length)
1007 int i, length, parsed, tmp;
1008 char *endptr;
1009 const char *quoted = quoted_;
1011 parsed = sscanf(quoted, "%d", &length);
1012 fc_assert_ret_val(1 == parsed, 0);
1014 if (length > dest_length) {
1015 return 0;
1017 quoted = strchr(quoted, ':');
1018 fc_assert_ret_val(quoted != NULL, 0);
1019 quoted++;
1021 for (i = 0; i < length; i++) {
1022 tmp = strtol(quoted, &endptr, 16);
1023 fc_assert_ret_val((endptr - quoted) == 2, 0);
1024 fc_assert_ret_val(*endptr == ' ', 0);
1025 fc_assert_ret_val((tmp & 0xff) == tmp, 0);
1026 ((unsigned char *) dest)[i] = tmp;
1027 quoted += 3;
1029 return length;
1032 /****************************************************************************
1033 Load the worklist elements specified by path to the worklist pointed to
1034 by 'pwl'. 'pwl' should be a pointer to an existing worklist.
1035 ****************************************************************************/
1036 static void worklist_load(struct section_file *file, struct worklist *pwl,
1037 const char *path, ...)
1039 int i;
1040 const char *kind;
1041 const char *name;
1042 char path_str[1024];
1043 va_list ap;
1045 /* The first part of the registry path is taken from the varargs to the
1046 * function. */
1047 va_start(ap, path);
1048 fc_vsnprintf(path_str, sizeof(path_str), path, ap);
1049 va_end(ap);
1051 worklist_init(pwl);
1052 pwl->length = secfile_lookup_int_default(file, 0,
1053 "%s.wl_length", path_str);
1055 for (i = 0; i < pwl->length; i++) {
1056 kind = secfile_lookup_str(file, "%s.wl_kind%d", path_str, i);
1058 /* We lookup the production value by name. An invalid entry isn't a
1059 * fatal error; we just truncate the worklist. */
1060 name = secfile_lookup_str_default(file, "-", "%s.wl_value%d",
1061 path_str, i);
1062 pwl->entries[i] = universal_by_rule_name(kind, name);
1063 if (pwl->entries[i].kind == universals_n_invalid()) {
1064 log_sg("%s.wl_value%d: unknown \"%s\" \"%s\".", path_str, i, kind,
1065 name);
1066 pwl->length = i;
1067 break;
1072 /****************************************************************************
1073 Save the worklist elements specified by path from the worklist pointed to
1074 by 'pwl'. 'pwl' should be a pointer to an existing worklist.
1075 ****************************************************************************/
1076 static void worklist_save(struct section_file *file,
1077 const struct worklist *pwl,
1078 int max_length, const char *path, ...)
1080 char path_str[1024];
1081 int i;
1082 va_list ap;
1084 /* The first part of the registry path is taken from the varargs to the
1085 * function. */
1086 va_start(ap, path);
1087 fc_vsnprintf(path_str, sizeof(path_str), path, ap);
1088 va_end(ap);
1090 secfile_insert_int(file, pwl->length, "%s.wl_length", path_str);
1092 for (i = 0; i < pwl->length; i++) {
1093 const struct universal *entry = pwl->entries + i;
1094 secfile_insert_str(file, universal_type_rule_name(entry),
1095 "%s.wl_kind%d", path_str, i);
1096 secfile_insert_str(file, universal_rule_name(entry),
1097 "%s.wl_value%d", path_str, i);
1100 fc_assert_ret(max_length <= MAX_LEN_WORKLIST);
1102 /* We want to keep savegame in tabular format, so each line has to be
1103 * of equal length. Fill table up to maximum worklist size. */
1104 for (i = pwl->length ; i < max_length; i++) {
1105 secfile_insert_str(file, "", "%s.wl_kind%d", path_str, i);
1106 secfile_insert_str(file, "", "%s.wl_value%d", path_str, i);
1110 /****************************************************************************
1111 Assign values to ord_city and ord_map for each unit, so the values can be
1112 saved.
1113 ****************************************************************************/
1114 static void unit_ordering_calc(void)
1116 int j;
1118 players_iterate(pplayer) {
1119 /* to avoid junk values for unsupported units: */
1120 unit_list_iterate(pplayer->units, punit) {
1121 punit->server.ord_city = 0;
1122 } unit_list_iterate_end;
1123 city_list_iterate(pplayer->cities, pcity) {
1124 j = 0;
1125 unit_list_iterate(pcity->units_supported, punit) {
1126 punit->server.ord_city = j++;
1127 } unit_list_iterate_end;
1128 } city_list_iterate_end;
1129 } players_iterate_end;
1131 whole_map_iterate(ptile) {
1132 j = 0;
1133 unit_list_iterate(ptile->units, punit) {
1134 punit->server.ord_map = j++;
1135 } unit_list_iterate_end;
1136 } whole_map_iterate_end;
1139 /****************************************************************************
1140 For each city and tile, sort unit lists according to ord_city and ord_map
1141 values.
1142 ****************************************************************************/
1143 static void unit_ordering_apply(void)
1145 players_iterate(pplayer) {
1146 city_list_iterate(pplayer->cities, pcity) {
1147 unit_list_sort_ord_city(pcity->units_supported);
1149 city_list_iterate_end;
1150 } players_iterate_end;
1152 whole_map_iterate(ptile) {
1153 unit_list_sort_ord_map(ptile->units);
1154 } whole_map_iterate_end;
1157 /****************************************************************************
1158 Helper function for loading extras from a savegame.
1160 'ch' gives the character loaded from the savegame. Extras are packed
1161 in four to a character in hex notation. 'index' is a mapping of
1162 savegame bit -> base bit.
1163 ****************************************************************************/
1164 static void sg_extras_set(bv_extras *extras, char ch, struct extra_type **idx)
1166 int i, bin;
1167 const char *pch = strchr(hex_chars, ch);
1169 if (!pch || ch == '\0') {
1170 log_sg("Unknown hex value: '%c' (%d)", ch, ch);
1171 bin = 0;
1172 } else {
1173 bin = pch - hex_chars;
1176 for (i = 0; i < 4; i++) {
1177 struct extra_type *pextra = idx[i];
1179 if (pextra == NULL) {
1180 continue;
1182 if ((bin & (1 << i))
1183 && (game.map.server.have_huts || !is_extra_caused_by(pextra, EC_HUT))) {
1184 BV_SET(*extras, extra_index(pextra));
1189 /****************************************************************************
1190 Helper function for saving extras into a savegame.
1192 Extras are packed in four to a character in hex notation. 'index'
1193 specifies which set of extras are included in this character.
1194 ****************************************************************************/
1195 static char sg_extras_get(bv_extras extras, const int *idx)
1197 int i, bin = 0;
1199 for (i = 0; i < 4; i++) {
1200 int extra = idx[i];
1202 if (extra < 0) {
1203 break;
1206 if (BV_ISSET(extras, extra)) {
1207 bin |= (1 << i);
1211 return hex_chars[bin];
1214 /****************************************************************************
1215 Complicated helper function for loading specials from a savegame.
1217 'ch' gives the character loaded from the savegame. Specials are packed
1218 in four to a character in hex notation. 'index' is a mapping of
1219 savegame bit -> special bit. S_LAST is used to mark unused savegame bits.
1220 ****************************************************************************/
1221 static void sg_special_set(struct tile *ptile, bv_extras *extras, char ch,
1222 const enum tile_special_type *idx,
1223 bool rivers_overlay)
1225 int i, bin;
1226 const char *pch = strchr(hex_chars, ch);
1228 if (!pch || ch == '\0') {
1229 log_sg("Unknown hex value: '%c' (%d)", ch, ch);
1230 bin = 0;
1231 } else {
1232 bin = pch - hex_chars;
1235 for (i = 0; i < 4; i++) {
1236 enum tile_special_type sp = idx[i];
1238 if (sp == S_LAST) {
1239 continue;
1241 if (rivers_overlay && sp != S_OLD_RIVER) {
1242 continue;
1245 if (sp == S_HUT && !game.map.server.have_huts) {
1246 /* It would be logical to have this in the saving side -
1247 * really not saving the huts in the first place, BUT
1248 * 1) They have been saved by older versions, so we
1249 * have to deal with such savegames.
1250 * 2) This makes scenario author less likely to lose
1251 * one's work completely after carefully placing huts
1252 * and then saving with 'have_huts' disabled. */
1253 continue;
1256 if (bin & (1 << i)) {
1257 if (sp == S_OLD_ROAD) {
1258 struct road_type *proad;
1260 proad = road_by_compat_special(ROCO_ROAD);
1261 if (proad) {
1262 BV_SET(*extras, extra_index(road_extra_get(proad)));
1264 } else if (sp == S_OLD_RAILROAD) {
1265 struct road_type *proad;
1267 proad = road_by_compat_special(ROCO_RAILROAD);
1268 if (proad) {
1269 BV_SET(*extras, extra_index(road_extra_get(proad)));
1271 } else if (sp == S_OLD_RIVER) {
1272 struct road_type *proad;
1274 proad = road_by_compat_special(ROCO_RIVER);
1275 if (proad) {
1276 BV_SET(*extras, extra_index(road_extra_get(proad)));
1278 } else {
1279 struct extra_type *pextra = NULL;
1280 enum extra_cause cause = EC_COUNT;
1282 /* Converting from old hardcoded specials to as sensible extra as we can */
1283 switch (sp) {
1284 case S_IRRIGATION:
1285 case S_FARMLAND:
1286 /* If old savegame has both irrigation and farmland, EC_IRRIGATION
1287 * gets applied twice, which hopefully has the correct result. */
1288 cause = EC_IRRIGATION;
1289 break;
1290 case S_MINE:
1291 cause = EC_MINE;
1292 break;
1293 case S_POLLUTION:
1294 cause = EC_POLLUTION;
1295 break;
1296 case S_HUT:
1297 cause = EC_HUT;
1298 break;
1299 case S_FALLOUT:
1300 cause = EC_FALLOUT;
1301 break;
1302 default:
1303 pextra = extra_type_by_rule_name(special_rule_name(sp));
1304 break;
1307 if (cause != EC_COUNT) {
1308 struct tile *vtile = tile_virtual_new(ptile);
1310 /* Do not let the extras already set to the real tile mess with setup
1311 * of the player tiles if that's what we're doing. */
1312 vtile->extras = *extras;
1314 /* It's ok not to know which player or which unit originally built the extra -
1315 * in the rules used when specials were saved these could not have made any
1316 * difference. */
1317 pextra = next_extra_for_tile(vtile, cause, NULL, NULL);
1319 tile_virtual_destroy(vtile);
1322 if (pextra) {
1323 BV_SET(*extras, extra_index(pextra));
1330 /****************************************************************************
1331 Helper function for loading bases from a savegame.
1333 'ch' gives the character loaded from the savegame. Bases are packed
1334 in four to a character in hex notation. 'index' is a mapping of
1335 savegame bit -> base bit.
1336 ****************************************************************************/
1337 static void sg_bases_set(bv_extras *extras, char ch, struct base_type **idx)
1339 int i, bin;
1340 const char *pch = strchr(hex_chars, ch);
1342 if (!pch || ch == '\0') {
1343 log_sg("Unknown hex value: '%c' (%d)", ch, ch);
1344 bin = 0;
1345 } else {
1346 bin = pch - hex_chars;
1349 for (i = 0; i < 4; i++) {
1350 struct base_type *pbase = idx[i];
1352 if (pbase == NULL) {
1353 continue;
1355 if (bin & (1 << i)) {
1356 BV_SET(*extras, extra_index(base_extra_get(pbase)));
1361 /****************************************************************************
1362 Helper function for loading roads from a savegame.
1364 'ch' gives the character loaded from the savegame. Roads are packed
1365 in four to a character in hex notation. 'index' is a mapping of
1366 savegame bit -> road bit.
1367 ****************************************************************************/
1368 static void sg_roads_set(bv_extras *extras, char ch, struct road_type **idx)
1370 int i, bin;
1371 const char *pch = strchr(hex_chars, ch);
1373 if (!pch || ch == '\0') {
1374 log_sg("Unknown hex value: '%c' (%d)", ch, ch);
1375 bin = 0;
1376 } else {
1377 bin = pch - hex_chars;
1380 for (i = 0; i < 4; i++) {
1381 struct road_type *proad = idx[i];
1383 if (proad == NULL) {
1384 continue;
1386 if (bin & (1 << i)) {
1387 BV_SET(*extras, extra_index(road_extra_get(proad)));
1392 /****************************************************************************
1393 Return the resource for the given identifier.
1394 ****************************************************************************/
1395 static struct resource *char2resource(char c)
1397 /* speed common values */
1398 if (c == RESOURCE_NULL_IDENTIFIER
1399 || c == RESOURCE_NONE_IDENTIFIER) {
1400 return NULL;
1402 return resource_by_identifier(c);
1405 /****************************************************************************
1406 Return the identifier for the given resource.
1407 ****************************************************************************/
1408 static char resource2char(const struct resource *presource)
1410 return presource ? presource->identifier : RESOURCE_NONE_IDENTIFIER;
1413 /****************************************************************************
1414 Converts number in to single character. This works to values up to ~70.
1415 ****************************************************************************/
1416 static char num2char(unsigned int num)
1418 if (num >= strlen(num_chars)) {
1419 return '?';
1422 return num_chars[num];
1425 /****************************************************************************
1426 Converts single character into numerical value. This is not hex conversion.
1427 ****************************************************************************/
1428 static int char2num(char ch)
1430 const char *pch;
1432 pch = strchr(num_chars, ch);
1434 sg_failure_ret_val(NULL != pch, 0,
1435 "Unknown ascii value for num: '%c' %d", ch, ch);
1437 return pch - num_chars;
1440 /****************************************************************************
1441 Dereferences the terrain character. See terrains[].identifier
1442 example: char2terrain('a') => T_ARCTIC
1443 ****************************************************************************/
1444 static struct terrain *char2terrain(char ch)
1446 /* terrain_by_identifier plus fatal error */
1447 if (ch == TERRAIN_UNKNOWN_IDENTIFIER) {
1448 return T_UNKNOWN;
1450 terrain_type_iterate(pterrain) {
1451 if (pterrain->identifier_load == ch) {
1452 return pterrain;
1454 } terrain_type_iterate_end;
1456 log_fatal("Unknown terrain identifier '%c' in savegame.", ch);
1457 exit(EXIT_FAILURE);
1460 /****************************************************************************
1461 References the terrain character. See terrains[].identifier
1462 example: terrain2char(T_ARCTIC) => 'a'
1463 ****************************************************************************/
1464 static char terrain2char(const struct terrain *pterrain)
1466 if (pterrain == T_UNKNOWN) {
1467 return TERRAIN_UNKNOWN_IDENTIFIER;
1468 } else {
1469 return pterrain->identifier;
1473 /*****************************************************************************
1474 Load technology from path_name and if doesn't exist (because savegame
1475 is too old) load from path.
1476 *****************************************************************************/
1477 static Tech_type_id technology_load(struct section_file *file,
1478 const char* path, int plrno)
1480 char path_with_name[128];
1481 const char* name;
1482 struct advance *padvance;
1484 fc_snprintf(path_with_name, sizeof(path_with_name),
1485 "%s_name", path);
1487 name = secfile_lookup_str(file, path_with_name, plrno);
1489 if (!name || name[0] == '\0') {
1490 /* used by researching_saved */
1491 return A_UNKNOWN;
1493 if (fc_strcasecmp(name, "A_FUTURE") == 0) {
1494 return A_FUTURE;
1496 if (fc_strcasecmp(name, "A_NONE") == 0) {
1497 return A_NONE;
1499 if (fc_strcasecmp(name, "A_UNSET") == 0) {
1500 return A_UNSET;
1503 padvance = advance_by_rule_name(name);
1504 sg_failure_ret_val(NULL != padvance, A_NONE,
1505 "%s: unknown technology \"%s\".", path_with_name, name);
1507 return advance_number(padvance);
1510 /*****************************************************************************
1511 Save technology in secfile entry called path_name.
1512 *****************************************************************************/
1513 static void technology_save(struct section_file *file,
1514 const char* path, int plrno, Tech_type_id tech)
1516 char path_with_name[128];
1517 const char* name;
1519 fc_snprintf(path_with_name, sizeof(path_with_name),
1520 "%s_name", path);
1522 switch (tech) {
1523 case A_UNKNOWN: /* used by researching_saved */
1524 name = "";
1525 break;
1526 case A_NONE:
1527 name = "A_NONE";
1528 break;
1529 case A_UNSET:
1530 name = "A_UNSET";
1531 break;
1532 case A_FUTURE:
1533 name = "A_FUTURE";
1534 break;
1535 default:
1536 name = advance_rule_name(advance_by_number(tech));
1537 break;
1540 secfile_insert_str(file, name, path_with_name, plrno);
1543 /* =======================================================================
1544 * Load / save savefile data.
1545 * ======================================================================= */
1547 /****************************************************************************
1548 Set up correct ruleset for the savegame
1549 ****************************************************************************/
1550 static void sg_load_ruleset(struct loaddata *loading)
1552 /* Load ruleset. */
1553 sz_strlcpy(game.server.rulesetdir,
1554 secfile_lookup_str_default(loading->file, GAME_DEFAULT_RULESETDIR,
1555 "savefile.rulesetdir"));
1556 if (!strcmp("default", game.server.rulesetdir)) {
1557 int version;
1559 version = secfile_lookup_int_default(loading->file, -1, "savefile.version");
1560 if (version >= 30) {
1561 /* Here 'default' really means current default.
1562 * Saving happens with real ruleset name, so savegames containing this
1563 * are special scenarios. */
1564 sz_strlcpy(game.server.rulesetdir, GAME_DEFAULT_RULESETDIR);
1565 } else {
1566 /* 'default' is the old name of the classic ruleset */
1567 sz_strlcpy(game.server.rulesetdir, "classic");
1570 if (!load_rulesets(NULL, TRUE, FALSE)) {
1571 /* Failed to load correct ruleset */
1572 sg_failure_ret(FALSE, _("Failed to load ruleset"));
1576 /****************************************************************************
1577 Load '[savefile]'.
1578 ****************************************************************************/
1579 static void sg_load_savefile(struct loaddata *loading)
1581 int i;
1582 const char *terr_name;
1584 /* Check status and return if not OK (sg_success != TRUE). */
1585 sg_check_ret();
1587 /* Load savefile options. */
1588 loading->secfile_options
1589 = secfile_lookup_str(loading->file, "savefile.options");
1591 /* We don't need these entries, but read them anyway to avoid
1592 * warnings about unread secfile entries. */
1593 (void) secfile_entry_by_path(loading->file, "savefile.reason");
1594 (void) secfile_entry_by_path(loading->file, "savefile.revision");
1596 /* In case of savegame2.c saves, missing entry means savegame older than support
1597 * for saving last_updated by turn. So this must default to TRUE. */
1598 game.server.last_updated_year = secfile_lookup_bool_default(loading->file, TRUE,
1599 "savefile.last_updated_as_year");
1601 /* Load improvements. */
1602 loading->improvement.size
1603 = secfile_lookup_int_default(loading->file, 0,
1604 "savefile.improvement_size");
1605 if (loading->improvement.size) {
1606 loading->improvement.order
1607 = secfile_lookup_str_vec(loading->file, &loading->improvement.size,
1608 "savefile.improvement_vector");
1609 sg_failure_ret(loading->improvement.size != 0,
1610 "Failed to load improvement order: %s",
1611 secfile_error());
1614 /* Load technologies. */
1615 loading->technology.size
1616 = secfile_lookup_int_default(loading->file, 0,
1617 "savefile.technology_size");
1618 if (loading->technology.size) {
1619 loading->technology.order
1620 = secfile_lookup_str_vec(loading->file, &loading->technology.size,
1621 "savefile.technology_vector");
1622 sg_failure_ret(loading->technology.size != 0,
1623 "Failed to load technology order: %s",
1624 secfile_error());
1627 /* Load traits. */
1628 loading->trait.size
1629 = secfile_lookup_int_default(loading->file, 0,
1630 "savefile.trait_size");
1631 if (loading->trait.size) {
1632 loading->trait.order
1633 = secfile_lookup_str_vec(loading->file, &loading->trait.size,
1634 "savefile.trait_vector");
1635 sg_failure_ret(loading->trait.size != 0,
1636 "Failed to load trait order: %s",
1637 secfile_error());
1640 /* Load extras. */
1641 loading->extra.size
1642 = secfile_lookup_int_default(loading->file, 0,
1643 "savefile.extras_size");
1644 if (loading->extra.size) {
1645 const char **modname;
1646 size_t nmod;
1647 int j;
1649 modname = secfile_lookup_str_vec(loading->file, &loading->extra.size,
1650 "savefile.extras_vector");
1651 sg_failure_ret(loading->extra.size != 0,
1652 "Failed to load extras order: %s",
1653 secfile_error());
1654 sg_failure_ret(!(game.control.num_extra_types < loading->extra.size),
1655 "Number of extras defined by the ruleset (= %d) are "
1656 "lower than the number in the savefile (= %d).",
1657 game.control.num_extra_types, (int)loading->extra.size);
1658 /* make sure that the size of the array is divisible by 4 */
1659 nmod = 4 * ((loading->extra.size + 3) / 4);
1660 loading->extra.order = fc_calloc(nmod, sizeof(*loading->extra.order));
1661 for (j = 0; j < loading->extra.size; j++) {
1662 loading->extra.order[j] = extra_type_by_rule_name(modname[j]);
1664 free(modname);
1665 for (; j < nmod; j++) {
1666 loading->extra.order[j] = NULL;
1670 /* Load multipliers. */
1671 loading->multiplier.size
1672 = secfile_lookup_int_default(loading->file, 0,
1673 "savefile.multipliers_size");
1674 if (loading->multiplier.size) {
1675 const char **modname;
1676 int j;
1678 modname = secfile_lookup_str_vec(loading->file, &loading->multiplier.size,
1679 "savefile.multipliers_vector");
1680 sg_failure_ret(loading->multiplier.size != 0,
1681 "Failed to load multipliers order: %s",
1682 secfile_error());
1683 /* It's OK for the set of multipliers in the savefile to differ
1684 * from those in the ruleset. */
1685 loading->multiplier.order = fc_calloc(loading->multiplier.size,
1686 sizeof(*loading->multiplier.order));
1687 for (j = 0; j < loading->multiplier.size; j++) {
1688 loading->multiplier.order[j] = multiplier_by_rule_name(modname[j]);
1689 if (!loading->multiplier.order[j]) {
1690 log_verbose("Multiplier \"%s\" in savegame but not in ruleset, "
1691 "discarding", modname[j]);
1694 free(modname);
1697 /* Load specials. */
1698 loading->special.size
1699 = secfile_lookup_int_default(loading->file, 0,
1700 "savefile.specials_size");
1701 if (loading->special.size) {
1702 const char **modname;
1703 size_t nmod;
1704 enum tile_special_type j;
1706 modname = secfile_lookup_str_vec(loading->file, &loading->special.size,
1707 "savefile.specials_vector");
1708 sg_failure_ret(loading->special.size != 0,
1709 "Failed to load specials order: %s",
1710 secfile_error());
1711 /* make sure that the size of the array is divisible by 4 */
1712 /* Allocating extra 4 slots, just a couple of bytes,
1713 * in case of special.size being divisible by 4 already is intentional.
1714 * Added complexity would cost those couple of bytes in code size alone,
1715 * and we actually need at least one slot immediately after last valid
1716 * one. That's where S_LAST is (or was in version that saved the game)
1717 * and in some cases S_LAST gets written to savegame, at least as
1718 * activity target special when activity targets some base or road
1719 * instead. By having current S_LAST in that index allows us to map
1720 * that old S_LAST to current S_LAST, just like any real special within
1721 * special.size gets mapped. */
1722 nmod = loading->special.size + (4 - (loading->special.size % 4));
1723 loading->special.order = fc_calloc(nmod,
1724 sizeof(*loading->special.order));
1725 for (j = 0; j < loading->special.size; j++) {
1726 if (!strcasecmp("Road", modname[j])) {
1727 loading->special.order[j] = S_OLD_ROAD;
1728 } else if (!strcasecmp("Railroad", modname[j])) {
1729 loading->special.order[j] = S_OLD_RAILROAD;
1730 } else if (!strcasecmp("River", modname[j])) {
1731 loading->special.order[j] = S_OLD_RIVER;
1732 } else {
1733 loading->special.order[j] = special_by_rule_name(modname[j]);
1736 free(modname);
1737 for (; j < nmod; j++) {
1738 loading->special.order[j] = S_LAST;
1742 /* Load bases. */
1743 loading->base.size
1744 = secfile_lookup_int_default(loading->file, 0,
1745 "savefile.bases_size");
1746 if (loading->base.size) {
1747 const char **modname;
1748 size_t nmod;
1749 int j;
1751 modname = secfile_lookup_str_vec(loading->file, &loading->base.size,
1752 "savefile.bases_vector");
1753 sg_failure_ret(loading->base.size != 0,
1754 "Failed to load bases order: %s",
1755 secfile_error());
1756 /* make sure that the size of the array is divisible by 4 */
1757 nmod = 4 * ((loading->base.size + 3) / 4);
1758 loading->base.order = fc_calloc(nmod, sizeof(*loading->base.order));
1759 for (j = 0; j < loading->base.size; j++) {
1760 struct extra_type *pextra = extra_type_by_rule_name(modname[j]);
1762 sg_failure_ret(pextra != NULL
1763 || game.control.num_base_types >= loading->base.size,
1764 "Unknown base type %s in savefile.",
1765 modname[j]);
1767 if (pextra != NULL) {
1768 loading->base.order[j] = extra_base_get(pextra);
1769 } else {
1770 loading->base.order[j] = NULL;
1773 free(modname);
1774 for (; j < nmod; j++) {
1775 loading->base.order[j] = NULL;
1779 /* Load roads. */
1780 loading->road.size
1781 = secfile_lookup_int_default(loading->file, 0,
1782 "savefile.roads_size");
1783 if (loading->road.size) {
1784 const char **modname;
1785 size_t nmod;
1786 int j;
1788 modname = secfile_lookup_str_vec(loading->file, &loading->road.size,
1789 "savefile.roads_vector");
1790 sg_failure_ret(loading->road.size != 0,
1791 "Failed to load roads order: %s",
1792 secfile_error());
1793 sg_failure_ret(!(game.control.num_road_types < loading->road.size),
1794 "Number of roads defined by the ruleset (= %d) are "
1795 "lower than the number in the savefile (= %d).",
1796 game.control.num_road_types, (int)loading->road.size);
1797 /* make sure that the size of the array is divisible by 4 */
1798 nmod = 4 * ((loading->road.size + 3) / 4);
1799 loading->road.order = fc_calloc(nmod, sizeof(*loading->road.order));
1800 for (j = 0; j < loading->road.size; j++) {
1801 struct extra_type *pextra = extra_type_by_rule_name(modname[j]);
1803 if (pextra != NULL) {
1804 loading->road.order[j] = extra_road_get(pextra);
1805 } else {
1806 loading->road.order[j] = NULL;
1809 free(modname);
1810 for (; j < nmod; j++) {
1811 loading->road.order[j] = NULL;
1815 /* Load specialists. */
1816 loading->specialist.size
1817 = secfile_lookup_int_default(loading->file, 0,
1818 "savefile.specialists_size");
1819 if (loading->specialist.size) {
1820 const char **modname;
1821 size_t nmod;
1822 int j;
1824 modname = secfile_lookup_str_vec(loading->file, &loading->specialist.size,
1825 "savefile.specialists_vector");
1826 sg_failure_ret(loading->specialist.size != 0,
1827 "Failed to load specialists order: %s",
1828 secfile_error());
1829 sg_failure_ret(!(game.control.num_specialist_types < loading->specialist.size),
1830 "Number of specialists defined by the ruleset (= %d) are "
1831 "lower than the number in the savefile (= %d).",
1832 game.control.num_specialist_types, (int)loading->specialist.size);
1833 /* make sure that the size of the array is divisible by 4 */
1834 /* That's not really needed with specialists at the moment, but done this way
1835 * for consistency with other types, and to be prepared for the time it needs
1836 * to be this way. */
1837 nmod = 4 * ((loading->specialist.size + 3) / 4);
1838 loading->specialist.order = fc_calloc(nmod, sizeof(*loading->specialist.order));
1839 for (j = 0; j < loading->specialist.size; j++) {
1840 loading->specialist.order[j] = specialist_by_rule_name(modname[j]);
1842 free(modname);
1843 for (; j < nmod; j++) {
1844 loading->specialist.order[j] = NULL;
1848 /* Load diplomatic state type order. */
1849 loading->ds_t.size
1850 = secfile_lookup_int_default(loading->file, 0,
1851 "savefile.diplstate_type_size");
1853 sg_failure_ret(loading->ds_t.size > 0,
1854 "Failed to load diplomatic state type order: %s",
1855 secfile_error());
1857 if (loading->ds_t.size) {
1858 const char **modname;
1859 int j;
1861 modname = secfile_lookup_str_vec(loading->file, &loading->ds_t.size,
1862 "savefile.diplstate_type_vector");
1864 loading->ds_t.order = fc_calloc(loading->ds_t.size,
1865 sizeof(*loading->ds_t.order));
1867 for (j = 0; j < loading->ds_t.size; j++) {
1868 loading->ds_t.order[j] = diplstate_type_by_name(modname[j],
1869 fc_strcasecmp);
1872 free(modname);
1875 terrain_type_iterate(pterr) {
1876 pterr->identifier_load = '\0';
1877 } terrain_type_iterate_end;
1879 i = 0;
1880 while ((terr_name = secfile_lookup_str_default(loading->file, NULL,
1881 "savefile.terrident%d.name", i)) != NULL) {
1882 struct terrain *pterr = terrain_by_rule_name(terr_name);
1884 if (pterr != NULL) {
1885 const char *iptr = secfile_lookup_str_default(loading->file, NULL,
1886 "savefile.terrident%d.identifier", i);
1888 pterr->identifier_load = *iptr;
1889 } else {
1890 log_error("Identifier for unknown terrain type %s.", terr_name);
1892 i++;
1895 terrain_type_iterate(pterr) {
1896 terrain_type_iterate(pterr2) {
1897 if (pterr != pterr2 && pterr->identifier_load != '\0') {
1898 sg_failure_ret((pterr->identifier_load != pterr2->identifier_load),
1899 "%s and %s share a saved identifier",
1900 terrain_rule_name(pterr), terrain_rule_name(pterr2));
1902 } terrain_type_iterate_end;
1903 } terrain_type_iterate_end;
1906 /****************************************************************************
1907 Save '[savefile]'.
1908 ****************************************************************************/
1909 static void sg_save_savefile(struct savedata *saving)
1911 int i;
1913 /* Check status and return if not OK (sg_success != TRUE). */
1914 sg_check_ret();
1916 /* Save savefile options. */
1917 sg_save_savefile_options(saving, savefile_options_default);
1919 secfile_insert_int(saving->file, current_compat_ver(), "savefile.version");
1921 /* Save reason of the savefile generation. */
1922 secfile_insert_str(saving->file, saving->save_reason, "savefile.reason");
1924 /* Save as accurate freeciv revision information as possible */
1925 secfile_insert_str(saving->file, freeciv_datafile_version(), "savefile.revision");
1927 /* Save rulesetdir at this point as this ruleset is required by this
1928 * savefile. */
1929 secfile_insert_str(saving->file, game.server.rulesetdir, "savefile.rulesetdir");
1931 if (game.control.version[0] != '\0') {
1932 /* Current ruleset has version information, save it.
1933 * This is never loaded, but exist in savegame file only for debugging purposes. */
1934 secfile_insert_str(saving->file, game.control.version, "savefile.rulesetversion");
1937 secfile_insert_bool(saving->file, game.server.last_updated_year,
1938 "savefile.last_updated_as_year");
1940 /* Save improvement order in savegame, so we are not dependent on ruleset
1941 * order. If the game isn't started improvements aren't loaded so we can
1942 * not save the order. */
1943 secfile_insert_int(saving->file, improvement_count(),
1944 "savefile.improvement_size");
1945 if (improvement_count() > 0) {
1946 const char* buf[improvement_count()];
1948 improvement_iterate(pimprove) {
1949 buf[improvement_index(pimprove)] = improvement_rule_name(pimprove);
1950 } improvement_iterate_end;
1952 secfile_insert_str_vec(saving->file, buf, improvement_count(),
1953 "savefile.improvement_vector");
1956 /* Save technology order in savegame, so we are not dependent on ruleset
1957 * order. If the game isn't started advances aren't loaded so we can not
1958 * save the order. */
1959 secfile_insert_int(saving->file, game.control.num_tech_types,
1960 "savefile.technology_size");
1961 if (game.control.num_tech_types > 0) {
1962 const char* buf[game.control.num_tech_types];
1964 buf[A_NONE] = "A_NONE";
1965 advance_iterate(A_FIRST, a) {
1966 buf[advance_index(a)] = advance_rule_name(a);
1967 } advance_iterate_end;
1968 secfile_insert_str_vec(saving->file, buf, game.control.num_tech_types,
1969 "savefile.technology_vector");
1972 /* Save activities order in the savegame. */
1973 secfile_insert_int(saving->file, ACTIVITY_LAST,
1974 "savefile.activities_size");
1975 if (ACTIVITY_LAST > 0) {
1976 const char **modname;
1977 int j;
1979 i = 0;
1981 modname = fc_calloc(ACTIVITY_LAST, sizeof(*modname));
1983 for (j = 0; j < ACTIVITY_LAST; j++) {
1984 modname[i++] = unit_activity_name(j);
1987 secfile_insert_str_vec(saving->file, modname,
1988 ACTIVITY_LAST,
1989 "savefile.activities_vector");
1990 free(modname);
1993 /* Save specialists order in the savegame. */
1994 secfile_insert_int(saving->file, specialist_count(),
1995 "savefile.specialists_size");
1997 const char **modname;
1999 i = 0;
2000 modname = fc_calloc(specialist_count(), sizeof(*modname));
2002 specialist_type_iterate(sp) {
2003 modname[i++] = specialist_rule_name(specialist_by_number(sp));
2004 } specialist_type_iterate_end;
2006 secfile_insert_str_vec(saving->file, modname, specialist_count(),
2007 "savefile.specialists_vector");
2009 free(modname);
2012 /* Save trait order in savegame. */
2013 secfile_insert_int(saving->file, TRAIT_COUNT,
2014 "savefile.trait_size");
2016 const char **modname;
2017 enum trait tr;
2018 int j;
2020 modname = fc_calloc(TRAIT_COUNT, sizeof(*modname));
2022 for (tr = trait_begin(), j = 0; tr != trait_end(); tr = trait_next(tr), j++) {
2023 modname[j] = trait_name(tr);
2026 secfile_insert_str_vec(saving->file, modname, TRAIT_COUNT,
2027 "savefile.trait_vector");
2028 free(modname);
2031 /* Save extras order in the savegame. */
2032 secfile_insert_int(saving->file, game.control.num_extra_types,
2033 "savefile.extras_size");
2034 if (game.control.num_extra_types > 0) {
2035 const char **modname;
2037 i = 0;
2038 modname = fc_calloc(game.control.num_extra_types, sizeof(*modname));
2040 extra_type_iterate(pextra) {
2041 modname[i++] = extra_rule_name(pextra);
2042 } extra_type_iterate_end;
2044 secfile_insert_str_vec(saving->file, modname,
2045 game.control.num_extra_types,
2046 "savefile.extras_vector");
2047 free(modname);
2050 /* Save multipliers order in the savegame. */
2051 secfile_insert_int(saving->file, multiplier_count(),
2052 "savefile.multipliers_size");
2053 if (multiplier_count() > 0) {
2054 const char **modname;
2056 i = 0;
2057 modname = fc_calloc(multiplier_count(), sizeof(*modname));
2059 multipliers_iterate(pmul) {
2060 modname[multiplier_index(pmul)] = multiplier_rule_name(pmul);
2061 } multipliers_iterate_end;
2063 secfile_insert_str_vec(saving->file, modname,
2064 multiplier_count(),
2065 "savefile.multipliers_vector");
2066 free(modname);
2069 /* Save diplstate type order in the savegame. */
2070 secfile_insert_int(saving->file, DS_LAST,
2071 "savefile.diplstate_type_size");
2072 if (DS_LAST > 0) {
2073 const char **modname;
2074 int j;
2076 i = 0;
2077 modname = fc_calloc(DS_LAST, sizeof(*modname));
2079 for (j = 0; j < DS_LAST; j++) {
2080 modname[i++] = diplstate_type_name(j);
2083 secfile_insert_str_vec(saving->file, modname,
2084 DS_LAST,
2085 "savefile.diplstate_type_vector");
2086 free(modname);
2089 /* Save city_option order in the savegame. */
2090 secfile_insert_int(saving->file, CITYO_LAST,
2091 "savefile.city_options_size");
2092 if (CITYO_LAST > 0) {
2093 const char **modname;
2094 int j;
2096 i = 0;
2097 modname = fc_calloc(CITYO_LAST, sizeof(*modname));
2099 for (j = 0; j < CITYO_LAST; j++) {
2100 modname[i++] = city_options_name(j);
2103 secfile_insert_str_vec(saving->file, modname,
2104 CITYO_LAST,
2105 "savefile.city_options_vector");
2106 free(modname);
2109 /* Save terrain character mapping in the savegame. */
2110 i = 0;
2111 terrain_type_iterate(pterr) {
2112 char buf[2];
2114 secfile_insert_str(saving->file, terrain_rule_name(pterr), "savefile.terrident%d.name", i);
2115 buf[0] = terrain_identifier(pterr);
2116 buf[1] = '\0';
2117 secfile_insert_str(saving->file, buf, "savefile.terrident%d.identifier", i++);
2118 } terrain_type_iterate_end;
2121 /****************************************************************************
2122 Save options for this savegame. sg_load_savefile_options() is not defined.
2123 ****************************************************************************/
2124 static void sg_save_savefile_options(struct savedata *saving,
2125 const char *option)
2127 /* Check status and return if not OK (sg_success != TRUE). */
2128 sg_check_ret();
2130 if (option == NULL) {
2131 /* no additional option */
2132 return;
2135 sz_strlcat(saving->secfile_options, option);
2136 secfile_replace_str(saving->file, saving->secfile_options,
2137 "savefile.options");
2140 /* =======================================================================
2141 * Load / save game status.
2142 * ======================================================================= */
2144 /****************************************************************************
2145 Load '[ruledata]'.
2146 ****************************************************************************/
2147 static void sg_load_ruledata(struct loaddata *loading)
2149 int i;
2150 const char *name;
2152 for (i = 0;
2153 (name = secfile_lookup_str_default(loading->file, NULL,
2154 "ruledata.government%d.name", i));
2155 i++) {
2156 struct government *gov = government_by_rule_name(name);
2158 if (gov != NULL) {
2159 gov->changed_to_times = secfile_lookup_int_default(loading->file, 0,
2160 "ruledata.government%d.changes", i);
2165 /****************************************************************************
2166 Load '[game]'.
2167 ****************************************************************************/
2168 static void sg_load_game(struct loaddata *loading)
2170 int game_version;
2171 const char *string;
2172 const char *level;
2173 int i;
2175 /* Check status and return if not OK (sg_success != TRUE). */
2176 sg_check_ret();
2178 /* Load version. */
2179 game_version
2180 = secfile_lookup_int_default(loading->file, 0, "game.version");
2181 /* We require at least version 2.2.99 */
2182 sg_failure_ret(20299 <= game_version, "Saved game is too old, at least "
2183 "version 2.2.99 required.");
2185 /* Load server state. */
2186 string = secfile_lookup_str_default(loading->file, "S_S_INITIAL",
2187 "game.server_state");
2188 loading->server_state = server_states_by_name(string, strcmp);
2189 if (!server_states_is_valid(loading->server_state)) {
2190 /* Don't take any risk! */
2191 loading->server_state = S_S_INITIAL;
2194 string = secfile_lookup_str_default(loading->file,
2195 default_meta_patches_string(),
2196 "game.meta_patches");
2197 set_meta_patches_string(string);
2198 game.server.meta_info.user_message_set
2199 = secfile_lookup_bool_default(loading->file, FALSE,
2200 "game.meta_usermessage");
2201 if (game.server.meta_info.user_message_set) {
2202 string = secfile_lookup_str_default(loading->file,
2203 default_meta_message_string(),
2204 "game.meta_message");
2205 set_user_meta_message_string(string);
2208 if (0 == strcmp(DEFAULT_META_SERVER_ADDR, srvarg.metaserver_addr)) {
2209 /* Do not overwrite this if the user requested a specific metaserver
2210 * from the command line (option --Metaserver). */
2211 sz_strlcpy(srvarg.metaserver_addr,
2212 secfile_lookup_str_default(loading->file,
2213 DEFAULT_META_SERVER_ADDR,
2214 "game.meta_server"));
2217 if ('\0' == srvarg.serverid[0]) {
2218 /* Do not overwrite this if the user requested a specific metaserver
2219 * from the command line (option --serverid). */
2220 sz_strlcpy(srvarg.serverid,
2221 secfile_lookup_str_default(loading->file, "",
2222 "game.serverid"));
2224 sz_strlcpy(server.game_identifier,
2225 secfile_lookup_str_default(loading->file, "", "game.id"));
2226 /* We are not checking game_identifier legality just yet.
2227 * That's done when we are sure that rand seed has been initialized,
2228 * so that we can generate new game_identifier, if needed.
2229 * See sq_load_sanitycheck(). */
2231 level = secfile_lookup_str_default(loading->file, NULL,
2232 "game.level");
2233 if (level != NULL) {
2234 game.info.skill_level = ai_level_by_name(level, fc_strcasecmp);
2235 } else {
2236 game.info.skill_level = ai_level_invalid();
2239 if (!ai_level_is_valid(game.info.skill_level)) {
2240 game.info.skill_level
2241 = ai_level_convert(secfile_lookup_int_default(loading->file,
2242 GAME_HARDCODED_DEFAULT_SKILL_LEVEL,
2243 "game.skill_level"));
2245 game.info.phase_mode
2246 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_PHASE_MODE,
2247 "game.phase_mode");
2248 game.server.phase_mode_stored
2249 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_PHASE_MODE,
2250 "game.phase_mode_stored");
2251 game.info.phase
2252 = secfile_lookup_int_default(loading->file, 0,
2253 "game.phase");
2254 game.server.scoreturn
2255 = secfile_lookup_int_default(loading->file,
2256 game.info.turn + GAME_DEFAULT_SCORETURN,
2257 "game.scoreturn");
2259 game.server.timeoutint
2260 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_TIMEOUTINT,
2261 "game.timeoutint");
2262 game.server.timeoutintinc
2263 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_TIMEOUTINTINC,
2264 "game.timeoutintinc");
2265 game.server.timeoutinc
2266 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_TIMEOUTINC,
2267 "game.timeoutinc");
2268 game.server.timeoutincmult
2269 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_TIMEOUTINCMULT,
2270 "game.timeoutincmult");
2271 game.server.timeoutcounter
2272 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_TIMEOUTCOUNTER,
2273 "game.timeoutcounter");
2275 game.info.turn
2276 = secfile_lookup_int_default(loading->file, 0, "game.turn");
2277 sg_failure_ret(secfile_lookup_int(loading->file, &game.info.year,
2278 "game.year"), "%s", secfile_error());
2279 game.info.year_0_hack
2280 = secfile_lookup_bool_default(loading->file, FALSE, "game.year_0_hack");
2282 game.info.globalwarming
2283 = secfile_lookup_int_default(loading->file, 0, "game.globalwarming");
2284 game.info.heating
2285 = secfile_lookup_int_default(loading->file, 0, "game.heating");
2286 game.info.warminglevel
2287 = secfile_lookup_int_default(loading->file, 0, "game.warminglevel");
2289 game.info.nuclearwinter
2290 = secfile_lookup_int_default(loading->file, 0, "game.nuclearwinter");
2291 game.info.cooling
2292 = secfile_lookup_int_default(loading->file, 0, "game.cooling");
2293 game.info.coolinglevel
2294 = secfile_lookup_int_default(loading->file, 0, "game.coolinglevel");
2296 /* Global advances. */
2297 string = secfile_lookup_str_default(loading->file, NULL,
2298 "game.global_advances");
2299 if (string != NULL) {
2300 sg_failure_ret(strlen(string) == loading->technology.size,
2301 "Invalid length of 'game.global_advances' (%lu ~= %lu).",
2302 (unsigned long) strlen(string),
2303 (unsigned long) loading->technology.size);
2304 for (i = 0; i < loading->technology.size; i++) {
2305 sg_failure_ret(string[i] == '1' || string[i] == '0',
2306 "Undefined value '%c' within 'game.global_advances'.",
2307 string[i]);
2308 if (string[i] == '1') {
2309 struct advance *padvance =
2310 advance_by_rule_name(loading->technology.order[i]);
2312 if (padvance != NULL) {
2313 game.info.global_advances[advance_number(padvance)] = TRUE;
2319 game.info.is_new_game
2320 = !secfile_lookup_bool_default(loading->file, TRUE, "game.save_players");
2322 game.server.turn_change_time
2323 = secfile_lookup_int_default(loading->file, 0, "game.last_turn_change_time") / 100;
2326 /****************************************************************************
2327 Save '[ruledata]'.
2328 ****************************************************************************/
2329 static void sg_save_ruledata(struct savedata *saving)
2331 int set_count = 0;
2333 governments_iterate(pgov) {
2334 char path[256];
2336 fc_snprintf(path, sizeof(path),
2337 "ruledata.government%d", set_count++);
2339 secfile_insert_str(saving->file, government_rule_name(pgov),
2340 "%s.name", path);
2341 secfile_insert_int(saving->file, pgov->changed_to_times,
2342 "%s.changes", path);
2343 } governments_iterate_end;
2346 /****************************************************************************
2347 Save '[game]'.
2348 ****************************************************************************/
2349 static void sg_save_game(struct savedata *saving)
2351 int game_version;
2352 const char *user_message;
2353 enum server_states srv_state;
2354 char global_advances[game.control.num_tech_types + 1];
2355 int i;
2357 /* Check status and return if not OK (sg_success != TRUE). */
2358 sg_check_ret();
2360 game_version = MAJOR_VERSION *10000 + MINOR_VERSION *100 + PATCH_VERSION;
2361 secfile_insert_int(saving->file, game_version, "game.version");
2363 /* Game state: once the game is no longer a new game (ie, has been
2364 * started the first time), it should always be considered a running
2365 * game for savegame purposes. */
2366 if (saving->scenario && !game.scenario.players) {
2367 srv_state = S_S_INITIAL;
2368 } else {
2369 srv_state = game.info.is_new_game ? server_state() : S_S_RUNNING;
2371 secfile_insert_str(saving->file, server_states_name(srv_state),
2372 "game.server_state");
2374 secfile_insert_str(saving->file, get_meta_patches_string(),
2375 "game.meta_patches");
2376 secfile_insert_bool(saving->file, game.server.meta_info.user_message_set,
2377 "game.meta_usermessage");
2378 user_message = get_user_meta_message_string();
2379 if (user_message != NULL) {
2380 secfile_insert_str(saving->file, user_message, "game.meta_message");
2382 secfile_insert_str(saving->file, meta_addr_port(), "game.meta_server");
2384 secfile_insert_str(saving->file, server.game_identifier, "game.id");
2385 secfile_insert_str(saving->file, srvarg.serverid, "game.serverid");
2387 secfile_insert_str(saving->file, ai_level_name(game.info.skill_level),
2388 "game.level");
2389 secfile_insert_int(saving->file, game.info.phase_mode,
2390 "game.phase_mode");
2391 secfile_insert_int(saving->file, game.server.phase_mode_stored,
2392 "game.phase_mode_stored");
2393 secfile_insert_int(saving->file, game.info.phase,
2394 "game.phase");
2395 secfile_insert_int(saving->file, game.server.scoreturn,
2396 "game.scoreturn");
2398 secfile_insert_int(saving->file, game.server.timeoutint,
2399 "game.timeoutint");
2400 secfile_insert_int(saving->file, game.server.timeoutintinc,
2401 "game.timeoutintinc");
2402 secfile_insert_int(saving->file, game.server.timeoutinc,
2403 "game.timeoutinc");
2404 secfile_insert_int(saving->file, game.server.timeoutincmult,
2405 "game.timeoutincmult");
2406 secfile_insert_int(saving->file, game.server.timeoutcounter,
2407 "game.timeoutcounter");
2409 secfile_insert_int(saving->file, game.info.turn, "game.turn");
2410 secfile_insert_int(saving->file, game.info.year, "game.year");
2411 secfile_insert_bool(saving->file, game.info.year_0_hack,
2412 "game.year_0_hack");
2414 secfile_insert_int(saving->file, game.info.globalwarming,
2415 "game.globalwarming");
2416 secfile_insert_int(saving->file, game.info.heating,
2417 "game.heating");
2418 secfile_insert_int(saving->file, game.info.warminglevel,
2419 "game.warminglevel");
2421 secfile_insert_int(saving->file, game.info.nuclearwinter,
2422 "game.nuclearwinter");
2423 secfile_insert_int(saving->file, game.info.cooling,
2424 "game.cooling");
2425 secfile_insert_int(saving->file, game.info.coolinglevel,
2426 "game.coolinglevel");
2427 /* For debugging purposes only.
2428 * Do not save it if it's 0 (not known);
2429 * this confuses people reading this 'document' less than
2430 * saving 0. */
2431 if (game.server.seed != 0) {
2432 secfile_insert_int(saving->file, game.server.seed,
2433 "game.random_seed");
2436 /* Global advances. */
2437 for (i = 0; i < game.control.num_tech_types; i++) {
2438 global_advances[i] = game.info.global_advances[i] ? '1' : '0';
2440 global_advances[i] = '\0';
2441 secfile_insert_str(saving->file, global_advances, "game.global_advances");
2443 if (!game_was_started()) {
2444 saving->save_players = FALSE;
2445 } else {
2446 if (saving->scenario) {
2447 saving->save_players = game.scenario.players;
2448 } else {
2449 saving->save_players = TRUE;
2451 #ifndef SAVE_DUMMY_TURN_CHANGE_TIME
2452 secfile_insert_int(saving->file, game.server.turn_change_time * 100,
2453 "game.last_turn_change_time");
2454 #else /* SAVE_DUMMY_TURN_CHANGE_TIME */
2455 secfile_insert_int(saving->file, game.info.turn * 10,
2456 "game.last_turn_change_time");
2457 #endif /* SAVE_DUMMY_TURN_CHANGE_TIME */
2459 secfile_insert_bool(saving->file, saving->save_players,
2460 "game.save_players");
2463 /* =======================================================================
2464 * Load / save random status.
2465 * ======================================================================= */
2467 /****************************************************************************
2468 Load '[random]'.
2469 ****************************************************************************/
2470 static void sg_load_random(struct loaddata *loading)
2472 /* Check status and return if not OK (sg_success != TRUE). */
2473 sg_check_ret();
2475 if (secfile_lookup_bool_default(loading->file, FALSE, "random.save")) {
2476 const char *string;
2477 int i;
2479 /* Since random state was previously saved, save it also when resaving.
2480 * This affects only pre-2.6 scenarios where scenario.save_random
2481 * is not defined.
2482 * - If this is 2.6 or later scenario -> it would have saved random.save = TRUE
2483 * only if scenario.save_random is already TRUE
2485 * Do NOT touch this in case of regular savegame. They always have random.save
2486 * set, but if one starts to make scenario based on a savegame, we want
2487 * default scenario settings in the beginning (default save_random = FALSE).
2489 if (game.scenario.is_scenario) {
2490 game.scenario.save_random = TRUE;
2493 sg_failure_ret(secfile_lookup_int(loading->file, &loading->rstate.j,
2494 "random.index_J"), "%s", secfile_error());
2495 sg_failure_ret(secfile_lookup_int(loading->file, &loading->rstate.k,
2496 "random.index_K"), "%s", secfile_error());
2497 sg_failure_ret(secfile_lookup_int(loading->file, &loading->rstate.x,
2498 "random.index_X"), "%s", secfile_error());
2500 for (i = 0; i < 8; i++) {
2501 string = secfile_lookup_str(loading->file, "random.table%d",i);
2502 sg_failure_ret(NULL != string, "%s", secfile_error());
2503 sscanf(string, "%8x %8x %8x %8x %8x %8x %8x", &loading->rstate.v[7*i],
2504 &loading->rstate.v[7*i+1], &loading->rstate.v[7*i+2],
2505 &loading->rstate.v[7*i+3], &loading->rstate.v[7*i+4],
2506 &loading->rstate.v[7*i+5], &loading->rstate.v[7*i+6]);
2508 loading->rstate.is_init = TRUE;
2509 fc_rand_set_state(loading->rstate);
2510 } else {
2511 /* No random values - mark the setting. */
2512 (void) secfile_entry_by_path(loading->file, "random.save");
2514 /* We're loading a game without a seed (which is okay, if it's a scenario).
2515 * We need to generate the game seed now because it will be needed later
2516 * during the load. */
2517 init_game_seed();
2518 loading->rstate = fc_rand_state();
2522 /****************************************************************************
2523 Save '[random]'.
2524 ****************************************************************************/
2525 static void sg_save_random(struct savedata *saving)
2527 /* Check status and return if not OK (sg_success != TRUE). */
2528 sg_check_ret();
2530 if (fc_rand_is_init() && (!saving->scenario || game.scenario.save_random)) {
2531 int i;
2532 RANDOM_STATE rstate = fc_rand_state();
2534 secfile_insert_bool(saving->file, TRUE, "random.save");
2535 fc_assert(rstate.is_init);
2537 secfile_insert_int(saving->file, rstate.j, "random.index_J");
2538 secfile_insert_int(saving->file, rstate.k, "random.index_K");
2539 secfile_insert_int(saving->file, rstate.x, "random.index_X");
2541 for (i = 0; i < 8; i++) {
2542 char vec[100];
2544 fc_snprintf(vec, sizeof(vec),
2545 "%8x %8x %8x %8x %8x %8x %8x", rstate.v[7 * i],
2546 rstate.v[7 * i + 1], rstate.v[7 * i + 2],
2547 rstate.v[7 * i + 3], rstate.v[7 * i + 4],
2548 rstate.v[7 * i + 5], rstate.v[7 * i + 6]);
2549 secfile_insert_str(saving->file, vec, "random.table%d", i);
2551 } else {
2552 secfile_insert_bool(saving->file, FALSE, "random.save");
2556 /* =======================================================================
2557 * Load / save lua script data.
2558 * ======================================================================= */
2560 /****************************************************************************
2561 Load '[script]'.
2562 ****************************************************************************/
2563 static void sg_load_script(struct loaddata *loading)
2565 /* Check status and return if not OK (sg_success != TRUE). */
2566 sg_check_ret();
2568 script_server_state_load(loading->file);
2571 /****************************************************************************
2572 Save '[script]'.
2573 ****************************************************************************/
2574 static void sg_save_script(struct savedata *saving)
2576 /* Check status and return if not OK (sg_success != TRUE). */
2577 sg_check_ret();
2579 script_server_state_save(saving->file);
2582 /* =======================================================================
2583 * Load / save scenario data.
2584 * ======================================================================= */
2586 /****************************************************************************
2587 Load '[scenario]'.
2588 ****************************************************************************/
2589 static void sg_load_scenario(struct loaddata *loading)
2591 const char *buf;
2592 bool lake_flood_default;
2594 /* Check status and return if not OK (sg_success != TRUE). */
2595 sg_check_ret();
2597 if (NULL == secfile_section_lookup(loading->file, "scenario")) {
2598 game.scenario.is_scenario = FALSE;
2600 return;
2603 /* Default is that when there's scenario section (which we already checked)
2604 * this is a scenario. Only if it explicitly says that it's not, we consider
2605 * this regular savegame */
2606 game.scenario.is_scenario = secfile_lookup_bool_default(loading->file, TRUE, "scenario.is_scenario");
2608 if (!game.scenario.is_scenario) {
2609 return;
2612 buf = secfile_lookup_str_default(loading->file, "", "scenario.name");
2613 if (buf[0] != '\0') {
2614 sz_strlcpy(game.scenario.name, buf);
2617 buf = secfile_lookup_str_default(loading->file, "",
2618 "scenario.authors");
2619 if (buf[0] != '\0') {
2620 sz_strlcpy(game.scenario.authors, buf);
2621 } else {
2622 game.scenario.authors[0] = '\0';
2625 buf = secfile_lookup_str_default(loading->file, "",
2626 "scenario.description");
2627 if (buf[0] != '\0') {
2628 sz_strlcpy(game.scenario_desc.description, buf);
2629 } else {
2630 game.scenario_desc.description[0] = '\0';
2633 game.scenario.save_random
2634 = secfile_lookup_bool_default(loading->file, FALSE, "scenario.save_random");
2635 game.scenario.players
2636 = secfile_lookup_bool_default(loading->file, TRUE, "scenario.players");
2637 game.scenario.startpos_nations
2638 = secfile_lookup_bool_default(loading->file, FALSE,
2639 "scenario.startpos_nations");
2641 game.scenario.prevent_new_cities
2642 = secfile_lookup_bool_default(loading->file, FALSE,
2643 "scenario.prevent_new_cities");
2644 if (loading->version < 20599) {
2645 /* Lake flooding may break some old scenarios where rivers made out of
2646 * lake terrains, so play safe there */
2647 lake_flood_default = FALSE;
2648 } else {
2649 /* If lake flooding is a problem for a newer scenario, it could explicitly
2650 * disable it. */
2651 lake_flood_default = TRUE;
2653 game.scenario.lake_flooding
2654 = secfile_lookup_bool_default(loading->file, lake_flood_default,
2655 "scenario.lake_flooding");
2656 game.scenario.handmade
2657 = secfile_lookup_bool_default(loading->file, FALSE,
2658 "scenario.handmade");
2659 game.scenario.allow_ai_type_fallback
2660 = secfile_lookup_bool_default(loading->file, FALSE,
2661 "scenario.allow_ai_type_fallback");
2663 sg_failure_ret(loading->server_state == S_S_INITIAL
2664 || (loading->server_state == S_S_RUNNING
2665 && game.scenario.players == TRUE),
2666 "Invalid scenario definition (server state '%s' and "
2667 "players are %s).",
2668 server_states_name(loading->server_state),
2669 game.scenario.players ? "saved" : "not saved");
2671 /* Remove all defined players. They are recreated with the skill level
2672 * defined by the scenario. */
2673 (void) aifill(0);
2676 /****************************************************************************
2677 Save '[scenario]'.
2678 ****************************************************************************/
2679 static void sg_save_scenario(struct savedata *saving)
2681 struct entry *mod_entry;
2682 int game_version;
2684 /* Check status and return if not OK (sg_success != TRUE). */
2685 sg_check_ret();
2687 if (!saving->scenario || !game.scenario.is_scenario) {
2688 secfile_insert_bool(saving->file, FALSE, "scenario.is_scenario");
2689 return;
2692 secfile_insert_bool(saving->file, TRUE, "scenario.is_scenario");
2694 game_version = MAJOR_VERSION * 10000 + MINOR_VERSION * 100 + PATCH_VERSION;
2695 secfile_insert_int(saving->file, game_version, "scenario.game_version");
2697 /* Name is mandatory to the level that is saved even if empty. */
2698 mod_entry = secfile_insert_str(saving->file, game.scenario.name, "scenario.name");
2699 entry_str_set_gt_marking(mod_entry, TRUE);
2701 /* Authors list is saved only if it exist */
2702 if (game.scenario.authors[0] != '\0') {
2703 mod_entry = secfile_insert_str(saving->file, game.scenario.authors,
2704 "scenario.authors");
2705 entry_str_set_gt_marking(mod_entry, TRUE);
2708 /* Description is saved only if it exist */
2709 if (game.scenario_desc.description[0] != '\0') {
2710 mod_entry = secfile_insert_str(saving->file, game.scenario_desc.description,
2711 "scenario.description");
2712 entry_str_set_gt_marking(mod_entry, TRUE);
2715 secfile_insert_bool(saving->file, game.scenario.save_random, "scenario.save_random");
2716 secfile_insert_bool(saving->file, game.scenario.players, "scenario.players");
2717 secfile_insert_bool(saving->file, game.scenario.startpos_nations,
2718 "scenario.startpos_nations");
2719 if (game.scenario.prevent_new_cities) {
2720 secfile_insert_bool(saving->file, game.scenario.prevent_new_cities,
2721 "scenario.prevent_new_cities");
2723 secfile_insert_bool(saving->file, game.scenario.lake_flooding,
2724 "scenario.lake_flooding");
2725 if (game.scenario.handmade) {
2726 secfile_insert_bool(saving->file, game.scenario.handmade,
2727 "scenario.handmade");
2729 if (game.scenario.allow_ai_type_fallback) {
2730 secfile_insert_bool(saving->file, game.scenario.allow_ai_type_fallback,
2731 "scenario.allow_ai_type_fallback");
2735 /* =======================================================================
2736 * Load / save game settings.
2737 * ======================================================================= */
2739 /****************************************************************************
2740 Load '[settings]'.
2741 ****************************************************************************/
2742 static void sg_load_settings(struct loaddata *loading)
2744 /* Check status and return if not OK (sg_success != TRUE). */
2745 sg_check_ret();
2747 settings_game_load(loading->file, "settings");
2749 /* Save current status of fogofwar. */
2750 game.server.fogofwar_old = game.info.fogofwar;
2752 /* Add all compatibility settings here. */
2755 /****************************************************************************
2756 Save [settings].
2757 ****************************************************************************/
2758 static void sg_save_settings(struct savedata *saving)
2760 enum map_generator real_generator = game.map.server.generator;
2762 /* Check status and return if not OK (sg_success != TRUE). */
2763 sg_check_ret();
2765 if (saving->scenario) {
2766 game.map.server.generator = MAPGEN_SCENARIO; /* We want a scenario. */
2769 settings_game_save(saving->file, "settings");
2770 /* Restore real map generator. */
2771 game.map.server.generator = real_generator;
2773 /* Add all compatibility settings here. */
2776 /* =======================================================================
2777 * Load / save the main map.
2778 * ======================================================================= */
2780 /****************************************************************************
2781 Load '[map'].
2782 ****************************************************************************/
2783 static void sg_load_map(struct loaddata *loading)
2785 /* Check status and return if not OK (sg_success != TRUE). */
2786 sg_check_ret();
2788 /* This defaults to TRUE even if map has not been generated. Also,
2789 * old versions have also explicitly saved TRUE even in pre-game.
2790 * We rely on that
2791 * 1) scenario maps have it explicity right.
2792 * 2) when map is actually generated, it re-initialize this to FALSE. */
2793 game.map.server.have_huts
2794 = secfile_lookup_bool_default(loading->file, TRUE, "map.have_huts");
2796 if (S_S_INITIAL == loading->server_state
2797 && MAPGEN_SCENARIO == game.map.server.generator) {
2798 /* Generator MAPGEN_SCENARIO is used;
2799 * this map was done with the map editor. */
2801 /* Load tiles. */
2802 sg_load_map_tiles(loading);
2803 sg_load_map_startpos(loading);
2805 if (loading->version >= 30) {
2806 /* 2.6.0 or newer */
2807 sg_load_map_tiles_extras(loading);
2808 } else {
2809 sg_load_map_tiles_bases(loading);
2810 if (loading->version >= 20) {
2811 /* 2.5.0 or newer */
2812 sg_load_map_tiles_roads(loading);
2814 if (has_capability("specials", loading->secfile_options)) {
2815 /* Load specials. */
2816 sg_load_map_tiles_specials(loading, FALSE);
2820 if (has_capability("specials", loading->secfile_options)) {
2821 /* Load resources. */
2822 sg_load_map_tiles_resources(loading);
2823 } else if (has_capability("riversoverlay", loading->secfile_options)) {
2824 /* Load only rivers overlay. */
2825 sg_load_map_tiles_specials(loading, TRUE);
2828 /* Nothing more needed for a scenario. */
2829 return;
2832 if (S_S_INITIAL == loading->server_state) {
2833 /* Nothing more to do if it is not a scenario but in initial state. */
2834 return;
2837 sg_load_map_tiles(loading);
2838 sg_load_map_startpos(loading);
2839 if (loading->version >= 30) {
2840 /* 2.6.0 or newer */
2841 sg_load_map_tiles_extras(loading);
2842 } else {
2843 sg_load_map_tiles_bases(loading);
2844 if (loading->version >= 20) {
2845 /* 2.5.0 or newer */
2846 sg_load_map_tiles_roads(loading);
2848 sg_load_map_tiles_specials(loading, FALSE);
2850 sg_load_map_tiles_resources(loading);
2851 sg_load_map_known(loading);
2852 sg_load_map_owner(loading);
2853 sg_load_map_worked(loading);
2856 /****************************************************************************
2857 Save 'map'.
2858 ****************************************************************************/
2859 static void sg_save_map(struct savedata *saving)
2861 /* Check status and return if not OK (sg_success != TRUE). */
2862 sg_check_ret();
2864 if (map_is_empty()) {
2865 /* No map. */
2866 return;
2869 if (saving->scenario) {
2870 secfile_insert_bool(saving->file, game.map.server.have_huts, "map.have_huts");
2871 } else {
2872 secfile_insert_bool(saving->file, TRUE, "map.have_huts");
2875 /* For debugging purposes only.
2876 * Do not save it if it's 0 (not known);
2877 * this confuses people reading this 'document' less than
2878 * saving 0. */
2879 if (game.map.server.seed) {
2880 secfile_insert_int(saving->file, game.map.server.seed,
2881 "map.random_seed");
2884 sg_save_map_tiles(saving);
2885 sg_save_map_startpos(saving);
2886 sg_save_map_tiles_extras(saving);
2887 if (game.scenario.have_resources) {
2888 sg_save_savefile_options(saving, " specials");
2889 sg_save_map_tiles_resources(saving);
2892 sg_save_map_owner(saving);
2893 sg_save_map_worked(saving);
2894 sg_save_map_known(saving);
2897 /****************************************************************************
2898 Load tiles of the map.
2899 ****************************************************************************/
2900 static void sg_load_map_tiles(struct loaddata *loading)
2902 /* Check status and return if not OK (sg_success != TRUE). */
2903 sg_check_ret();
2905 /* Initialize the map for the current topology. 'map.xsize' and
2906 * 'map.ysize' must be set. */
2907 map_init_topology();
2909 /* Allocate map. */
2910 map_allocate();
2912 /* get the terrain type */
2913 LOAD_MAP_CHAR(ch, ptile, ptile->terrain = char2terrain(ch), loading->file,
2914 "map.t%04d");
2915 assign_continent_numbers();
2917 /* Check for special tile sprites. */
2918 whole_map_iterate(ptile) {
2919 const char *spec_sprite;
2920 const char *label;
2921 int nat_x, nat_y;
2923 index_to_native_pos(&nat_x, &nat_y, tile_index(ptile));
2924 spec_sprite = secfile_lookup_str(loading->file, "map.spec_sprite_%d_%d",
2925 nat_x, nat_y);
2926 label = secfile_lookup_str_default(loading->file, NULL, "map.label_%d_%d",
2927 nat_x, nat_y);
2928 if (NULL != ptile->spec_sprite) {
2929 ptile->spec_sprite = fc_strdup(spec_sprite);
2931 if (label != NULL) {
2932 tile_set_label(ptile, label);
2934 } whole_map_iterate_end;
2937 /****************************************************************************
2938 Save all map tiles
2939 ****************************************************************************/
2940 static void sg_save_map_tiles(struct savedata *saving)
2942 /* Check status and return if not OK (sg_success != TRUE). */
2943 sg_check_ret();
2945 /* Save the terrain type. */
2946 SAVE_MAP_CHAR(ptile, terrain2char(ptile->terrain), saving->file,
2947 "map.t%04d");
2949 /* Save special tile sprites. */
2950 whole_map_iterate(ptile) {
2951 int nat_x, nat_y;
2953 index_to_native_pos(&nat_x, &nat_y, tile_index(ptile));
2954 if (ptile->spec_sprite) {
2955 secfile_insert_str(saving->file, ptile->spec_sprite,
2956 "map.spec_sprite_%d_%d", nat_x, nat_y);
2958 if (ptile->label != NULL) {
2959 secfile_insert_str(saving->file, ptile->label,
2960 "map.label_%d_%d", nat_x, nat_y);
2962 } whole_map_iterate_end;
2965 /****************************************************************************
2966 Load extras to map
2967 ****************************************************************************/
2968 static void sg_load_map_tiles_extras(struct loaddata *loading)
2970 /* Check status and return if not OK (sg_success != TRUE). */
2971 sg_check_ret();
2973 /* Load extras. */
2974 halfbyte_iterate_extras(j, loading->extra.size) {
2975 LOAD_MAP_CHAR(ch, ptile, sg_extras_set(&ptile->extras, ch, loading->extra.order + 4 * j),
2976 loading->file, "map.e%02d_%04d", j);
2977 } halfbyte_iterate_extras_end;
2980 /****************************************************************************
2981 Save information about extras on map
2982 ****************************************************************************/
2983 static void sg_save_map_tiles_extras(struct savedata *saving)
2985 /* Check status and return if not OK (sg_success != TRUE). */
2986 sg_check_ret();
2988 /* Save extras. */
2989 halfbyte_iterate_extras(j, game.control.num_extra_types) {
2990 int mod[4];
2991 int l;
2993 for (l = 0; l < 4; l++) {
2994 if (4 * j + 1 > game.control.num_extra_types) {
2995 mod[l] = -1;
2996 } else {
2997 mod[l] = 4 * j + l;
3000 SAVE_MAP_CHAR(ptile, sg_extras_get(ptile->extras, mod),
3001 saving->file, "map.e%02d_%04d", j);
3002 } halfbyte_iterate_extras_end;
3005 /****************************************************************************
3006 Load bases to map
3007 ****************************************************************************/
3008 static void sg_load_map_tiles_bases(struct loaddata *loading)
3010 /* Check status and return if not OK (sg_success != TRUE). */
3011 sg_check_ret();
3013 /* Load bases. */
3014 halfbyte_iterate_bases(j, loading->base.size) {
3015 LOAD_MAP_CHAR(ch, ptile, sg_bases_set(&ptile->extras, ch,
3016 loading->base.order + 4 * j),
3017 loading->file, "map.b%02d_%04d", j);
3018 } halfbyte_iterate_bases_end;
3021 /****************************************************************************
3022 Load roads to map
3023 ****************************************************************************/
3024 static void sg_load_map_tiles_roads(struct loaddata *loading)
3026 /* Check status and return if not OK (sg_success != TRUE). */
3027 sg_check_ret();
3029 /* Load roads. */
3030 halfbyte_iterate_roads(j, loading->road.size) {
3031 LOAD_MAP_CHAR(ch, ptile, sg_roads_set(&ptile->extras, ch,
3032 loading->road.order + 4 * j),
3033 loading->file, "map.r%02d_%04d", j);
3034 } halfbyte_iterate_roads_end;
3037 /****************************************************************************
3038 Load information about specials on map
3039 ****************************************************************************/
3040 static void sg_load_map_tiles_specials(struct loaddata *loading,
3041 bool rivers_overlay)
3043 /* Check status and return if not OK (sg_success != TRUE). */
3044 sg_check_ret();
3046 /* If 'rivers_overlay' is set to TRUE, load only the rivers overlay map
3047 * from the savegame file.
3049 * A scenario may define the terrain of the map but not list the specials
3050 * on it (thus allowing users to control the placement of specials).
3051 * However rivers are a special case and must be included in the map along
3052 * with the scenario. Thus in those cases this function should be called
3053 * to load the river information separate from any other special data.
3055 * This does not need to be called from map_load(), because map_load()
3056 * loads the rivers overlay along with the rest of the specials. Call this
3057 * only if you've already called map_load_tiles(), and want to load only
3058 * the rivers overlay but no other specials. Scenarios that encode things
3059 * this way should have the "riversoverlay" capability. */
3060 halfbyte_iterate_special(j, loading->special.size) {
3061 LOAD_MAP_CHAR(ch, ptile, sg_special_set(ptile, &ptile->extras, ch,
3062 loading->special.order + 4 * j,
3063 rivers_overlay),
3064 loading->file, "map.spe%02d_%04d", j);
3065 } halfbyte_iterate_special_end;
3068 /****************************************************************************
3069 Load information about resources on map.
3070 ****************************************************************************/
3071 static void sg_load_map_tiles_resources(struct loaddata *loading)
3073 /* Check status and return if not OK (sg_success != TRUE). */
3074 sg_check_ret();
3076 LOAD_MAP_CHAR(ch, ptile, ptile->resource = char2resource(ch),
3077 loading->file, "map.res%04d");
3079 /* After the resources are loaded, indicate those currently valid. */
3080 whole_map_iterate(ptile) {
3081 if (NULL == ptile->resource || NULL == ptile->terrain) {
3082 continue;
3085 if (terrain_has_resource(ptile->terrain, ptile->resource)) {
3086 /* cannot use set_special() for internal values */
3087 ptile->resource_valid = TRUE;
3089 } whole_map_iterate_end;
3091 game.map.server.have_resources = TRUE;
3092 game.scenario.have_resources = TRUE;
3095 /****************************************************************************
3096 Load information about resources on map.
3097 ****************************************************************************/
3098 static void sg_save_map_tiles_resources(struct savedata *saving)
3100 /* Check status and return if not OK (sg_success != TRUE). */
3101 sg_check_ret();
3103 SAVE_MAP_CHAR(ptile, resource2char(ptile->resource), saving->file,
3104 "map.res%04d");
3107 /****************************************************************************
3108 Load starting positions for the players from a savegame file. There should
3109 be at least enough for every player.
3110 ****************************************************************************/
3111 static void sg_load_map_startpos(struct loaddata *loading)
3113 struct nation_type *pnation;
3114 struct startpos *psp;
3115 struct tile *ptile;
3116 const char SEPARATOR = '#';
3117 const char *nation_names;
3118 int nat_x, nat_y;
3119 bool exclude;
3120 int i, startpos_count;
3122 /* Check status and return if not OK (sg_success != TRUE). */
3123 sg_check_ret();
3125 startpos_count
3126 = secfile_lookup_int_default(loading->file, 0, "map.startpos_count");
3128 if (0 == startpos_count) {
3129 /* Nothing to do. */
3130 return;
3133 for (i = 0; i < startpos_count; i++) {
3134 if (!secfile_lookup_int(loading->file, &nat_x, "map.startpos%d.x", i)
3135 || !secfile_lookup_int(loading->file, &nat_y,
3136 "map.startpos%d.y", i)) {
3137 log_sg("Warning: Undefined coordinates for startpos %d", i);
3138 continue;
3141 ptile = native_pos_to_tile(nat_x, nat_y);
3142 if (NULL == ptile) {
3143 log_error("Start position native coordinates (%d, %d) do not exist "
3144 "in this map. Skipping...", nat_x, nat_y);
3145 continue;
3148 exclude = secfile_lookup_bool_default(loading->file, FALSE,
3149 "map.startpos%d.exclude", i);
3151 psp = map_startpos_new(ptile);
3153 nation_names = secfile_lookup_str(loading->file,
3154 "map.startpos%d.nations", i);
3155 if (NULL != nation_names && '\0' != nation_names[0]) {
3156 const size_t size = strlen(nation_names) + 1;
3157 char buf[size], *start, *end;
3159 memcpy(buf, nation_names, size);
3160 for (start = buf - 1; NULL != start; start = end) {
3161 start++;
3162 if ((end = strchr(start, SEPARATOR))) {
3163 *end = '\0';
3166 pnation = nation_by_rule_name(start);
3167 if (NO_NATION_SELECTED != pnation) {
3168 if (exclude) {
3169 startpos_disallow(psp, pnation);
3170 } else {
3171 startpos_allow(psp, pnation);
3173 } else {
3174 log_verbose("Missing nation \"%s\".", start);
3180 if (0 < map_startpos_count()
3181 && loading->server_state == S_S_INITIAL
3182 && map_startpos_count() < game.server.max_players) {
3183 log_verbose("Number of starts (%d) are lower than rules.max_players "
3184 "(%d), lowering rules.max_players.",
3185 map_startpos_count(), game.server.max_players);
3186 game.server.max_players = map_startpos_count();
3189 /* Re-initialize nation availability in light of start positions.
3190 * This has to be after loading [scenario] and [map].startpos and
3191 * before we seek nations for players. */
3192 update_nations_with_startpos();
3195 /****************************************************************************
3196 Save the map start positions.
3197 ****************************************************************************/
3198 static void sg_save_map_startpos(struct savedata *saving)
3200 struct tile *ptile;
3201 const char SEPARATOR = '#';
3202 int i = 0;
3204 /* Check status and return if not OK (sg_success != TRUE). */
3205 sg_check_ret();
3207 if (!game.server.save_options.save_starts) {
3208 return;
3211 secfile_insert_int(saving->file, map_startpos_count(),
3212 "map.startpos_count");
3214 map_startpos_iterate(psp) {
3215 int nat_x, nat_y;
3217 ptile = startpos_tile(psp);
3219 index_to_native_pos(&nat_x, &nat_y, tile_index(ptile));
3220 secfile_insert_int(saving->file, nat_x, "map.startpos%d.x", i);
3221 secfile_insert_int(saving->file, nat_y, "map.startpos%d.y", i);
3223 secfile_insert_bool(saving->file, startpos_is_excluding(psp),
3224 "map.startpos%d.exclude", i);
3225 if (startpos_allows_all(psp)) {
3226 secfile_insert_str(saving->file, "", "map.startpos%d.nations", i);
3227 } else {
3228 const struct nation_hash *nations = startpos_raw_nations(psp);
3229 char nation_names[MAX_LEN_NAME * nation_hash_size(nations)];
3231 nation_names[0] = '\0';
3232 nation_hash_iterate(nations, pnation) {
3233 if ('\0' == nation_names[0]) {
3234 fc_strlcpy(nation_names, nation_rule_name(pnation),
3235 sizeof(nation_names));
3236 } else {
3237 cat_snprintf(nation_names, sizeof(nation_names),
3238 "%c%s", SEPARATOR, nation_rule_name(pnation));
3240 } nation_hash_iterate_end;
3241 secfile_insert_str(saving->file, nation_names,
3242 "map.startpos%d.nations", i);
3244 i++;
3245 } map_startpos_iterate_end;
3247 fc_assert(map_startpos_count() == i);
3250 /****************************************************************************
3251 Load tile owner information
3252 ****************************************************************************/
3253 static void sg_load_map_owner(struct loaddata *loading)
3255 int x, y;
3256 struct player *owner = NULL;
3257 struct tile *claimer = NULL;
3258 struct player *eowner = NULL;
3260 /* Check status and return if not OK (sg_success != TRUE). */
3261 sg_check_ret();
3263 if (game.info.is_new_game) {
3264 /* No owner/source information for a new game / scenario. */
3265 return;
3268 /* Owner and ownership source are stored as plain numbers */
3269 for (y = 0; y < game.map.ysize; y++) {
3270 const char *buffer1 = secfile_lookup_str(loading->file,
3271 "map.owner%04d", y);
3272 const char *buffer2 = secfile_lookup_str(loading->file,
3273 "map.source%04d", y);
3274 const char *buffer3 = secfile_lookup_str(loading->file,
3275 "map.eowner%04d", y);
3276 const char *ptr1 = buffer1;
3277 const char *ptr2 = buffer2;
3278 const char *ptr3 = buffer3;
3280 sg_failure_ret(buffer1 != NULL, "%s", secfile_error());
3281 sg_failure_ret(buffer2 != NULL, "%s", secfile_error());
3282 if (loading->version >= 30) {
3283 sg_failure_ret(buffer3 != NULL, "%s", secfile_error());
3286 for (x = 0; x < game.map.xsize; x++) {
3287 char token1[TOKEN_SIZE];
3288 char token2[TOKEN_SIZE];
3289 char token3[TOKEN_SIZE];
3290 int number;
3291 struct tile *ptile = native_pos_to_tile(x, y);
3293 scanin(&ptr1, ",", token1, sizeof(token1));
3294 sg_failure_ret(token1[0] != '\0',
3295 "Map size not correct (map.owner%d).", y);
3296 if (strcmp(token1, "-") == 0) {
3297 owner = NULL;
3298 } else {
3299 sg_failure_ret(str_to_int(token1, &number),
3300 "Got map owner %s in (%d, %d).", token1, x, y);
3301 owner = player_by_number(number);
3304 scanin(&ptr2, ",", token2, sizeof(token2));
3305 sg_failure_ret(token2[0] != '\0',
3306 "Map size not correct (map.source%d).", y);
3307 if (strcmp(token2, "-") == 0) {
3308 claimer = NULL;
3309 } else {
3310 sg_failure_ret(str_to_int(token2, &number),
3311 "Got map source %s in (%d, %d).", token2, x, y);
3312 claimer = index_to_tile(number);
3315 if (loading->version >= 30) {
3316 scanin(&ptr3, ",", token3, sizeof(token3));
3317 sg_failure_ret(token3[0] != '\0',
3318 "Map size not correct (map.eowner%d).", y);
3319 if (strcmp(token3, "-") == 0) {
3320 eowner = NULL;
3321 } else {
3322 sg_failure_ret(str_to_int(token3, &number),
3323 "Got base owner %s in (%d, %d).", token3, x, y);
3324 eowner = player_by_number(number);
3326 } else {
3327 eowner = owner;
3330 map_claim_ownership(ptile, owner, claimer, FALSE);
3331 tile_claim_bases(ptile, eowner);
3332 log_debug("extras_owner(%d, %d) = %s", TILE_XY(ptile), player_name(eowner));
3337 /****************************************************************************
3338 Save tile owner information
3339 ****************************************************************************/
3340 static void sg_save_map_owner(struct savedata *saving)
3342 int x, y;
3344 /* Check status and return if not OK (sg_success != TRUE). */
3345 sg_check_ret();
3347 if (saving->scenario && !saving->save_players) {
3348 /* Nothing to do for a scenario without saved players. */
3349 return;
3352 /* Store owner and ownership source as plain numbers. */
3353 for (y = 0; y < game.map.ysize; y++) {
3354 char line[game.map.xsize * TOKEN_SIZE];
3356 line[0] = '\0';
3357 for (x = 0; x < game.map.xsize; x++) {
3358 char token[TOKEN_SIZE];
3359 struct tile *ptile = native_pos_to_tile(x, y);
3361 if (!saving->save_players || tile_owner(ptile) == NULL) {
3362 strcpy(token, "-");
3363 } else {
3364 fc_snprintf(token, sizeof(token), "%d",
3365 player_number(tile_owner(ptile)));
3367 strcat(line, token);
3368 if (x + 1 < game.map.xsize) {
3369 strcat(line, ",");
3372 secfile_insert_str(saving->file, line, "map.owner%04d", y);
3375 for (y = 0; y < game.map.ysize; y++) {
3376 char line[game.map.xsize * TOKEN_SIZE];
3378 line[0] = '\0';
3379 for (x = 0; x < game.map.xsize; x++) {
3380 char token[TOKEN_SIZE];
3381 struct tile *ptile = native_pos_to_tile(x, y);
3383 if (ptile->claimer == NULL) {
3384 strcpy(token, "-");
3385 } else {
3386 fc_snprintf(token, sizeof(token), "%d", tile_index(ptile->claimer));
3388 strcat(line, token);
3389 if (x + 1 < game.map.xsize) {
3390 strcat(line, ",");
3393 secfile_insert_str(saving->file, line, "map.source%04d", y);
3396 for (y = 0; y < game.map.ysize; y++) {
3397 char line[game.map.xsize * TOKEN_SIZE];
3399 line[0] = '\0';
3400 for (x = 0; x < game.map.xsize; x++) {
3401 char token[TOKEN_SIZE];
3402 struct tile *ptile = native_pos_to_tile(x, y);
3404 if (!saving->save_players || extra_owner(ptile) == NULL) {
3405 strcpy(token, "-");
3406 } else {
3407 fc_snprintf(token, sizeof(token), "%d",
3408 player_number(extra_owner(ptile)));
3410 strcat(line, token);
3411 if (x + 1 < game.map.xsize) {
3412 strcat(line, ",");
3415 secfile_insert_str(saving->file, line, "map.eowner%04d", y);
3419 /****************************************************************************
3420 Load worked tiles information
3421 ****************************************************************************/
3422 static void sg_load_map_worked(struct loaddata *loading)
3424 int x, y;
3426 /* Check status and return if not OK (sg_success != TRUE). */
3427 sg_check_ret();
3429 sg_failure_ret(loading->worked_tiles == NULL,
3430 "City worked map not loaded!");
3432 loading->worked_tiles = fc_malloc(MAP_INDEX_SIZE *
3433 sizeof(*loading->worked_tiles));
3435 for (y = 0; y < game.map.ysize; y++) {
3436 const char *buffer = secfile_lookup_str(loading->file, "map.worked%04d",
3438 const char *ptr = buffer;
3440 sg_failure_ret(NULL != buffer,
3441 "Savegame corrupt - map line %d not found.", y);
3442 for (x = 0; x < game.map.xsize; x++) {
3443 char token[TOKEN_SIZE];
3444 int number;
3445 struct tile *ptile = native_pos_to_tile(x, y);
3447 scanin(&ptr, ",", token, sizeof(token));
3448 sg_failure_ret('\0' != token[0],
3449 "Savegame corrupt - map size not correct.");
3450 if (strcmp(token, "-") == 0) {
3451 number = -1;
3452 } else {
3453 sg_failure_ret(str_to_int(token, &number) && 0 < number,
3454 "Savegame corrupt - got tile worked by city "
3455 "id=%s in (%d, %d).", token, x, y);
3458 loading->worked_tiles[ptile->index] = number;
3463 /****************************************************************************
3464 Save worked tiles information
3465 ****************************************************************************/
3466 static void sg_save_map_worked(struct savedata *saving)
3468 int x, y;
3470 /* Check status and return if not OK (sg_success != TRUE). */
3471 sg_check_ret();
3473 if (saving->scenario && !saving->save_players) {
3474 /* Nothing to do for a scenario without saved players. */
3475 return;
3478 /* additionally save the tiles worked by the cities */
3479 for (y = 0; y < game.map.ysize; y++) {
3480 char line[game.map.xsize * TOKEN_SIZE];
3482 line[0] = '\0';
3483 for (x = 0; x < game.map.xsize; x++) {
3484 char token[TOKEN_SIZE];
3485 struct tile *ptile = native_pos_to_tile(x, y);
3486 struct city *pcity = tile_worked(ptile);
3488 if (pcity == NULL) {
3489 strcpy(token, "-");
3490 } else {
3491 fc_snprintf(token, sizeof(token), "%d", pcity->id);
3493 strcat(line, token);
3494 if (x < game.map.xsize) {
3495 strcat(line, ",");
3498 secfile_insert_str(saving->file, line, "map.worked%04d", y);
3502 /****************************************************************************
3503 Load tile known status
3504 ****************************************************************************/
3505 static void sg_load_map_known(struct loaddata *loading)
3507 /* Check status and return if not OK (sg_success != TRUE). */
3508 sg_check_ret();
3510 players_iterate(pplayer) {
3511 /* Allocate player private map here; it is needed in different modules
3512 * besides this one ((i.e. sg_load_player_*()). */
3513 player_map_init(pplayer);
3514 } players_iterate_end;
3516 if (secfile_lookup_bool_default(loading->file, TRUE,
3517 "game.save_known")) {
3518 int lines = player_slot_max_used_number()/32 + 1, j, p, l, i;
3519 unsigned int *known = fc_calloc(lines * MAP_INDEX_SIZE, sizeof(*known));
3521 for (l = 0; l < lines; l++) {
3522 for (j = 0; j < 8; j++) {
3523 for (i = 0; i < 4; i++) {
3524 /* Only bother trying to load the map for this halfbyte if at least
3525 * one of the corresponding player slots is in use. */
3526 if (player_slot_is_used(player_slot_by_number(l*32 + j*4 + i))) {
3527 LOAD_MAP_CHAR(ch, ptile,
3528 known[l * MAP_INDEX_SIZE + tile_index(ptile)]
3529 |= ascii_hex2bin(ch, j),
3530 loading->file, "map.k%02d_%04d", l * 8 + j);
3531 break;
3537 players_iterate(pplayer) {
3538 dbv_clr_all(&pplayer->tile_known);
3539 } players_iterate_end;
3541 /* HACK: we read the known data from hex into 32-bit integers, and
3542 * now we convert it to the known tile data of each player. */
3543 whole_map_iterate(ptile) {
3544 players_iterate(pplayer) {
3545 p = player_index(pplayer);
3546 l = player_index(pplayer) / 32;
3548 if (known[l * MAP_INDEX_SIZE + tile_index(ptile)] & (1u << (p % 32))) {
3549 map_set_known(ptile, pplayer);
3551 } players_iterate_end;
3552 } whole_map_iterate_end;
3554 FC_FREE(known);
3558 /****************************************************************************
3559 Save tile known status for whole map and all players
3560 ****************************************************************************/
3561 static void sg_save_map_known(struct savedata *saving)
3563 /* Check status and return if not OK (sg_success != TRUE). */
3564 sg_check_ret();
3566 if (!saving->save_players) {
3567 secfile_insert_bool(saving->file, FALSE, "game.save_known");
3568 return;
3569 } else {
3570 int lines = player_slot_max_used_number()/32 + 1;
3572 secfile_insert_bool(saving->file, game.server.save_options.save_known,
3573 "game.save_known");
3574 if (game.server.save_options.save_known) {
3575 int j, p, l, i;
3576 unsigned int *known = fc_calloc(lines * MAP_INDEX_SIZE, sizeof(*known));
3578 /* HACK: we convert the data into a 32-bit integer, and then save it as
3579 * hex. */
3581 whole_map_iterate(ptile) {
3582 players_iterate(pplayer) {
3583 if (map_is_known(ptile, pplayer)) {
3584 p = player_index(pplayer);
3585 l = p / 32;
3586 known[l * MAP_INDEX_SIZE + tile_index(ptile)]
3587 |= (1u << (p % 32)); /* "p % 32" = "p - l * 32" */
3589 } players_iterate_end;
3590 } whole_map_iterate_end;
3592 for (l = 0; l < lines; l++) {
3593 for (j = 0; j < 8; j++) {
3594 for (i = 0; i < 4; i++) {
3595 /* Only bother saving the map for this halfbyte if at least one
3596 * of the corresponding player slots is in use */
3597 if (player_slot_is_used(player_slot_by_number(l*32 + j*4 + i))) {
3598 /* put 4-bit segments of the 32-bit "known" field */
3599 SAVE_MAP_CHAR(ptile, bin2ascii_hex(known[l * MAP_INDEX_SIZE
3600 + tile_index(ptile)], j),
3601 saving->file, "map.k%02d_%04d", l * 8 + j);
3602 break;
3608 FC_FREE(known);
3613 /* =======================================================================
3614 * Load / save player data.
3616 * This is splitted into two parts as some data can only be loaded if the
3617 * number of players is known and the corresponding player slots are
3618 * defined.
3619 * ======================================================================= */
3621 /****************************************************************************
3622 Load '[player]' (basic data).
3623 ****************************************************************************/
3624 static void sg_load_players_basic(struct loaddata *loading)
3626 int i, k, nplayers;
3627 const char *string;
3628 bool shuffle_loaded = TRUE;
3630 /* Check status and return if not OK (sg_success != TRUE). */
3631 sg_check_ret();
3633 if (S_S_INITIAL == loading->server_state
3634 || game.info.is_new_game) {
3635 /* Nothing more to do. */
3636 return;
3639 /* Load destroyed wonders: */
3640 string = secfile_lookup_str(loading->file,
3641 "players.destroyed_wonders");
3642 sg_failure_ret(string != NULL, "%s", secfile_error());
3643 sg_failure_ret(strlen(string) == loading->improvement.size,
3644 "Invalid length for 'players.destroyed_wonders' "
3645 "(%lu ~= %lu)", (unsigned long) strlen(string),
3646 (unsigned long) loading->improvement.size);
3647 for (k = 0; k < loading->improvement.size; k++) {
3648 sg_failure_ret(string[k] == '1' || string[k] == '0',
3649 "Undefined value '%c' within "
3650 "'players.destroyed_wonders'.", string[k]);
3652 if (string[k] == '1') {
3653 struct impr_type *pimprove =
3654 improvement_by_rule_name(loading->improvement.order[k]);
3655 if (pimprove) {
3656 game.info.great_wonder_owners[improvement_index(pimprove)]
3657 = WONDER_DESTROYED;
3662 server.identity_number
3663 = secfile_lookup_int_default(loading->file, server.identity_number,
3664 "players.identity_number_used");
3666 /* First remove all defined players. */
3667 players_iterate(pplayer) {
3668 server_remove_player(pplayer);
3669 } players_iterate_end;
3671 /* Now, load the players from the savefile. */
3672 player_slots_iterate(pslot) {
3673 struct player *pplayer;
3674 struct rgbcolor *prgbcolor = NULL;
3675 int pslot_id = player_slot_index(pslot);
3677 if (NULL == secfile_section_lookup(loading->file, "player%d",
3678 pslot_id)) {
3679 continue;
3682 /* Get player AI type. */
3683 string = secfile_lookup_str(loading->file, "player%d.ai_type",
3684 player_slot_index(pslot));
3685 sg_failure_ret(string != NULL, "%s", secfile_error());
3687 /* Get player color */
3688 if (!rgbcolor_load(loading->file, &prgbcolor, "player%d.color",
3689 pslot_id)) {
3690 if (loading->version >= 10 && game_was_started()) {
3691 /* 2.4.0 or later savegame. This is not an error in 2.3 savefiles,
3692 * as they predate the introduction of configurable player colors. */
3693 log_sg("Game has started, yet player %d has no color defined.",
3694 pslot_id);
3695 /* This will be fixed up later */
3696 } else {
3697 log_verbose("No color defined for player %d.", pslot_id);
3698 /* Colors will be assigned on game start, or at end of savefile
3699 * loading if game has already started */
3703 /* Create player. */
3704 pplayer = server_create_player(player_slot_index(pslot), string,
3705 prgbcolor, game.scenario.allow_ai_type_fallback);
3706 sg_failure_ret(pplayer != NULL, "Invalid AI type: '%s'!", string);
3708 server_player_init(pplayer, FALSE, FALSE);
3710 /* Free the color definition. */
3711 rgbcolor_destroy(prgbcolor);
3713 /* Multipliers (policies) */
3715 /* First initialise player values with ruleset defaults; this will
3716 * cover any in the ruleset not known when the savefile was created. */
3717 multipliers_iterate(pmul) {
3718 pplayer->multipliers[multiplier_index(pmul)]
3719 = pplayer->multipliers_target[multiplier_index(pmul)] = pmul->def;
3720 } multipliers_iterate_end;
3722 /* Now override with any values from the savefile. */
3723 for (k = 0; k < loading->multiplier.size; k++) {
3724 const struct multiplier *pmul = loading->multiplier.order[k];
3726 if (pmul) {
3727 Multiplier_type_id idx = multiplier_index(pmul);
3728 int val =
3729 secfile_lookup_int_default(loading->file, pmul->def,
3730 "player%d.multiplier%d.val",
3731 player_slot_index(pslot), k);
3732 int rval = (((CLIP(pmul->start, val, pmul->stop)
3733 - pmul->start) / pmul->step) * pmul->step) + pmul->start;
3735 if (rval != val) {
3736 log_verbose("Player %d had illegal value for multiplier \"%s\": "
3737 "was %d, clamped to %d", pslot_id,
3738 multiplier_rule_name(pmul), val, rval);
3740 pplayer->multipliers[idx] = rval;
3742 val =
3743 secfile_lookup_int_default(loading->file,
3744 pplayer->multipliers[idx],
3745 "player%d.multiplier%d.target",
3746 player_slot_index(pslot), k);
3747 rval = (((CLIP(pmul->start, val, pmul->stop)
3748 - pmul->start) / pmul->step) * pmul->step) + pmul->start;
3750 if (rval != val) {
3751 log_verbose("Player %d had illegal value for multiplier_target "
3752 "\"%s\": was %d, clamped to %d", pslot_id,
3753 multiplier_rule_name(pmul), val, rval);
3755 pplayer->multipliers_target[idx] = rval;
3756 } /* else silently discard multiplier not in current ruleset */
3758 } player_slots_iterate_end;
3760 /* check number of players */
3761 nplayers = secfile_lookup_int_default(loading->file, 0, "players.nplayers");
3762 sg_failure_ret(player_count() == nplayers, "The value of players.nplayers "
3763 "(%d) from the loaded game does not match the number of "
3764 "players present (%d).", nplayers, player_count());
3766 /* Load team informations. */
3767 players_iterate(pplayer) {
3768 int team;
3769 struct team_slot *tslot = NULL;
3771 sg_failure_ret(secfile_lookup_int(loading->file, &team,
3772 "player%d.team_no",
3773 player_number(pplayer))
3774 && (tslot = team_slot_by_number(team)),
3775 "Invalid team definition for player %s (nb %d).",
3776 player_name(pplayer), player_number(pplayer));
3777 team_add_player(pplayer, team_new(tslot));
3778 } players_iterate_end;
3780 /* Loading the shuffle list is quite complex. At the time of saving the
3781 * shuffle data is saved as
3782 * shuffled_player_<number> = player_slot_id
3783 * where number is an increasing number and player_slot_id is a number
3784 * between 0 and the maximum number of player slots. Now we have to create
3785 * a list
3786 * shuffler_players[number] = player_slot_id
3787 * where all player slot IDs are used exactly one time. The code below
3788 * handles this ... */
3789 if (secfile_lookup_int_default(loading->file, -1,
3790 "players.shuffled_player_%d", 0) >= 0) {
3791 int shuffled_players[player_slot_count()];
3792 bool shuffled_player_set[player_slot_count()];
3794 player_slots_iterate(pslot) {
3795 int plrid = player_slot_index(pslot);
3797 /* Array to save used numbers. */
3798 shuffled_player_set[plrid] = FALSE;
3799 /* List of all player IDs (needed for set_shuffled_players()). It is
3800 * initialised with the value -1 to indicate that no value is set. */
3801 shuffled_players[plrid] = -1;
3802 } player_slots_iterate_end;
3804 /* Load shuffled player list. */
3805 for (i = 0; i < player_count(); i++){
3806 int shuffle
3807 = secfile_lookup_int_default(loading->file, -1,
3808 "players.shuffled_player_%d", i);
3810 if (shuffle == -1) {
3811 log_sg("Missing player shuffle information (index %d) "
3812 "- reshuffle player list!", i);
3813 shuffle_loaded = FALSE;
3814 break;
3815 } else if (shuffled_player_set[shuffle]) {
3816 log_sg("Player shuffle %d used two times "
3817 "- reshuffle player list!", shuffle);
3818 shuffle_loaded = FALSE;
3819 break;
3821 /* Set this ID as used. */
3822 shuffled_player_set[shuffle] = TRUE;
3824 /* Save the player ID in the shuffle list. */
3825 shuffled_players[i] = shuffle;
3828 if (shuffle_loaded) {
3829 /* Insert missing numbers. */
3830 int shuffle_index = player_count();
3831 for (i = 0; i < player_slot_count(); i++){
3832 if (!shuffled_player_set[i]) {
3833 shuffled_players[shuffle_index] = i;
3834 shuffle_index++;
3836 /* shuffle_index must not grow behind the size of shuffled_players. */
3837 sg_failure_ret(shuffle_index <= player_slot_count(),
3838 "Invalid player shuffle data!");
3841 #ifdef DEBUG
3842 log_debug("[load shuffle] player_count() = %d", player_count());
3843 player_slots_iterate(pslot) {
3844 int plrid = player_slot_index(pslot);
3845 log_debug("[load shuffle] id: %3d => slot: %3d | slot %3d: %s",
3846 plrid, shuffled_players[plrid], plrid,
3847 shuffled_player_set[plrid] ? "is used" : "-");
3848 } player_slots_iterate_end;
3849 #endif /* DEBUG */
3851 /* Set shuffle list from savegame. */
3852 set_shuffled_players(shuffled_players);
3856 if (!shuffle_loaded) {
3857 /* No shuffled players included or error loading them, so shuffle them
3858 * (this may include scenarios). */
3859 shuffle_players();
3863 /****************************************************************************
3864 Load '[player]'.
3865 ****************************************************************************/
3866 static void sg_load_players(struct loaddata *loading)
3868 /* Check status and return if not OK (sg_success != TRUE). */
3869 sg_check_ret();
3871 if (game.info.is_new_game) {
3872 /* Nothing to do. */
3873 return;
3876 players_iterate(pplayer) {
3877 sg_load_player_main(loading, pplayer);
3878 sg_load_player_cities(loading, pplayer);
3879 sg_load_player_units(loading, pplayer);
3880 sg_load_player_attributes(loading, pplayer);
3882 /* Check the sucess of the functions above. */
3883 sg_check_ret();
3885 /* print out some informations */
3886 if (pplayer->ai_controlled) {
3887 log_normal(_("%s has been added as %s level AI-controlled player "
3888 "(%s)."), player_name(pplayer),
3889 ai_level_translated_name(pplayer->ai_common.skill_level),
3890 ai_name(pplayer->ai));
3891 } else {
3892 log_normal(_("%s has been added as human player."),
3893 player_name(pplayer));
3895 } players_iterate_end;
3897 /* Also load the transport status of the units here. It must be a special
3898 * case as all units must be known (unit on an allied transporter). */
3899 players_iterate(pplayer) {
3900 /* Load unit transport status. */
3901 sg_load_player_units_transport(loading, pplayer);
3902 } players_iterate_end;
3904 /* Savegame may contain nation assignments that are incompatible with the
3905 * current nationset -- for instance, if it predates the introduction of
3906 * nationsets. Ensure they are compatible, one way or another. */
3907 fit_nationset_to_players();
3909 /* Some players may have invalid nations in the ruleset. Once all players
3910 * are loaded, pick one of the remaining nations for them. */
3911 players_iterate(pplayer) {
3912 if (pplayer->nation == NO_NATION_SELECTED) {
3913 player_set_nation(pplayer, pick_a_nation(NULL, FALSE, TRUE,
3914 NOT_A_BARBARIAN));
3915 /* TRANS: Minor error message: <Leader> ... <Poles>. */
3916 log_sg(_("%s had invalid nation; changing to %s."),
3917 player_name(pplayer), nation_plural_for_player(pplayer));
3919 ai_traits_init(pplayer);
3921 } players_iterate_end;
3923 /* Sanity check alliances, prevent allied-with-ally-of-enemy. */
3924 players_iterate_alive(plr) {
3925 players_iterate_alive(aplayer) {
3926 if (pplayers_allied(plr, aplayer)) {
3927 enum dipl_reason can_ally = pplayer_can_make_treaty(plr, aplayer,
3928 DS_ALLIANCE);
3929 if (can_ally == DIPL_ALLIANCE_PROBLEM_US
3930 || can_ally == DIPL_ALLIANCE_PROBLEM_THEM) {
3931 log_sg("Illegal alliance structure detected: "
3932 "%s alliance to %s reduced to peace treaty.",
3933 nation_rule_name(nation_of_player(plr)),
3934 nation_rule_name(nation_of_player(aplayer)));
3935 player_diplstate_get(plr, aplayer)->type = DS_PEACE;
3936 player_diplstate_get(aplayer, plr)->type = DS_PEACE;
3939 } players_iterate_alive_end;
3940 } players_iterate_alive_end;
3942 /* Update cached city illness. This can depend on trade routes,
3943 * so can't be calculated until all players have been loaded. */
3944 if (game.info.illness_on) {
3945 cities_iterate(pcity) {
3946 pcity->server.illness
3947 = city_illness_calc(pcity, NULL, NULL,
3948 &(pcity->illness_trade), NULL);
3949 } cities_iterate_end;
3952 /* Update all city information. This must come after all cities are
3953 * loaded (in player_load) but before player (dumb) cities are loaded
3954 * in player_load_vision(). */
3955 players_iterate(plr) {
3956 city_list_iterate(plr->cities, pcity) {
3957 city_refresh(pcity);
3958 sanity_check_city(pcity);
3959 CALL_PLR_AI_FUNC(city_got, plr, plr, pcity);
3960 } city_list_iterate_end;
3961 } players_iterate_end;
3963 /* Since the cities must be placed on the map to put them on the
3964 player map we do this afterwards */
3965 players_iterate(pplayer) {
3966 sg_load_player_vision(loading, pplayer);
3967 /* Check the sucess of the function above. */
3968 sg_check_ret();
3969 } players_iterate_end;
3971 /* Check shared vision. */
3972 players_iterate(pplayer) {
3973 BV_CLR_ALL(pplayer->gives_shared_vision);
3974 BV_CLR_ALL(pplayer->server.really_gives_vision);
3975 } players_iterate_end;
3977 players_iterate(pplayer) {
3978 int plr1 = player_index(pplayer);
3980 players_iterate(pplayer2) {
3981 int plr2 = player_index(pplayer2);
3982 if (secfile_lookup_bool_default(loading->file, FALSE,
3983 "player%d.diplstate%d.gives_shared_vision", plr1, plr2)) {
3984 give_shared_vision(pplayer, pplayer2);
3986 } players_iterate_end;
3987 } players_iterate_end;
3989 initialize_globals();
3990 unit_ordering_apply();
3992 /* All vision is ready; this calls city_thaw_workers_queue(). */
3993 map_calculate_borders();
3995 /* Make sure everything is consistent. */
3996 players_iterate(pplayer) {
3997 unit_list_iterate(pplayer->units, punit) {
3998 if (!can_unit_continue_current_activity(punit)) {
3999 log_sg("Unit doing illegal activity in savegame!");
4000 log_sg("Activity: %s, Target: %s",
4001 unit_activity_name(punit->activity),
4002 punit->activity_target ? extra_rule_name(
4003 punit->activity_target)
4004 : "missing");
4005 punit->activity = ACTIVITY_IDLE;
4007 } unit_list_iterate_end;
4008 } players_iterate_end;
4010 cities_iterate(pcity) {
4011 city_refresh(pcity);
4012 city_thaw_workers(pcity); /* may auto_arrange_workers() */
4013 } cities_iterate_end;
4015 /* Player colors are always needed once game has started. Pre-2.4 savegames
4016 * lack them. This cannot be in compatibility conversion layer as we need
4017 * all the player data available to be able to assign best colors. */
4018 if (game_was_started()) {
4019 assign_player_colors();
4023 /****************************************************************************
4024 Save '[player]'.
4025 ****************************************************************************/
4026 static void sg_save_players(struct savedata *saving)
4028 /* Check status and return if not OK (sg_success != TRUE). */
4029 sg_check_ret();
4031 if ((saving->scenario && !saving->save_players)
4032 || !game_was_started()) {
4033 /* Nothing to do for a scenario without saved players or a game in
4034 * INITIAL state. */
4035 return;
4038 secfile_insert_int(saving->file, player_count(), "players.nplayers");
4040 /* Save destroyed wonders as bitvector. Note that improvement order
4041 * is saved in 'savefile.improvement.order'. */
4043 char destroyed[B_LAST+1];
4045 improvement_iterate(pimprove) {
4046 if (is_great_wonder(pimprove)
4047 && great_wonder_is_destroyed(pimprove)) {
4048 destroyed[improvement_index(pimprove)] = '1';
4049 } else {
4050 destroyed[improvement_index(pimprove)] = '0';
4052 } improvement_iterate_end;
4053 destroyed[improvement_count()] = '\0';
4054 secfile_insert_str(saving->file, destroyed,
4055 "players.destroyed_wonders");
4058 secfile_insert_int(saving->file, server.identity_number,
4059 "players.identity_number_used");
4061 /* Save player order. */
4063 int i = 0;
4064 shuffled_players_iterate(pplayer) {
4065 secfile_insert_int(saving->file, player_number(pplayer),
4066 "players.shuffled_player_%d", i);
4067 i++;
4068 } shuffled_players_iterate_end;
4071 /* Sort units. */
4072 unit_ordering_calc();
4074 /* Save players. */
4075 players_iterate(pplayer) {
4076 sg_save_player_main(saving, pplayer);
4077 sg_save_player_cities(saving, pplayer);
4078 sg_save_player_units(saving, pplayer);
4079 sg_save_player_attributes(saving, pplayer);
4080 sg_save_player_vision(saving, pplayer);
4081 } players_iterate_end;
4084 /****************************************************************************
4085 Main player data loading function
4086 ****************************************************************************/
4087 static void sg_load_player_main(struct loaddata *loading,
4088 struct player *plr)
4090 int i, plrno = player_number(plr);
4091 const char *string;
4092 struct government *gov;
4093 const char *level;
4094 const char *barb_str;
4096 /* Check status and return if not OK (sg_success != TRUE). */
4097 sg_check_ret();
4099 /* Basic player data. */
4100 string = secfile_lookup_str(loading->file, "player%d.name", plrno);
4101 sg_failure_ret(string != NULL, "%s", secfile_error());
4102 server_player_set_name(plr, string);
4103 sz_strlcpy(plr->username,
4104 secfile_lookup_str_default(loading->file, "",
4105 "player%d.username", plrno));
4106 sg_failure_ret(secfile_lookup_bool(loading->file, &plr->unassigned_user,
4107 "player%d.unassigned_user", plrno),
4108 "%s", secfile_error());
4109 sz_strlcpy(plr->ranked_username,
4110 secfile_lookup_str_default(loading->file, "",
4111 "player%d.ranked_username",
4112 plrno));
4113 sg_failure_ret(secfile_lookup_bool(loading->file, &plr->unassigned_ranked,
4114 "player%d.unassigned_ranked", plrno),
4115 "%s", secfile_error());
4116 string = secfile_lookup_str_default(loading->file, "",
4117 "player%d.delegation_username",
4118 plrno);
4119 /* Defaults to no delegation. */
4120 if (strlen(string)) {
4121 player_delegation_set(plr, string);
4124 /* Nation */
4125 string = secfile_lookup_str(loading->file, "player%d.nation", plrno);
4126 player_set_nation(plr, nation_by_rule_name(string));
4127 if (plr->nation != NULL) {
4128 ai_traits_init(plr);
4131 /* Government */
4132 string = secfile_lookup_str(loading->file, "player%d.government_name",
4133 plrno);
4134 gov = government_by_rule_name(string);
4135 sg_failure_ret(gov != NULL, "Player%d: unsupported government \"%s\".",
4136 plrno, string);
4137 plr->government = gov;
4139 /* Target government */
4140 string = secfile_lookup_str(loading->file,
4141 "player%d.target_government_name", plrno);
4142 if (string) {
4143 plr->target_government = government_by_rule_name(string);
4144 } else {
4145 plr->target_government = NULL;
4147 plr->revolution_finishes
4148 = secfile_lookup_int_default(loading->file, -1,
4149 "player%d.revolution_finishes", plrno);
4151 sg_failure_ret(secfile_lookup_bool(loading->file,
4152 &plr->server.got_first_city,
4153 "player%d.got_first_city", plrno),
4154 "%s", secfile_error());
4156 sg_failure_ret(secfile_lookup_bool(loading->file, &plr->ai_controlled,
4157 "player%d.ai.control", plrno),
4158 "%s", secfile_error());
4160 /* Load diplomatic data (diplstate + embassy + vision).
4161 * Shared vision is loaded in sg_load_players(). */
4162 BV_CLR_ALL(plr->real_embassy);
4163 players_iterate(pplayer) {
4164 char buf[32];
4165 int unconverted;
4166 struct player_diplstate *ds = player_diplstate_get(plr, pplayer);
4167 i = player_index(pplayer);
4169 /* load diplomatic status */
4170 fc_snprintf(buf, sizeof(buf), "player%d.diplstate%d", plrno, i);
4172 unconverted =
4173 secfile_lookup_int_default(loading->file, -1, "%s.type", buf);
4174 if (unconverted >= 0 && unconverted < loading->ds_t.size) {
4175 /* Look up what state the unconverted number represents. */
4176 ds->type = loading->ds_t.order[unconverted];
4177 } else {
4178 log_sg("No valid diplomatic state type between players %d and %d",
4179 plrno, i);
4181 ds->type = DS_WAR;
4184 unconverted =
4185 secfile_lookup_int_default(loading->file, -1, "%s.max_state", buf);
4186 if (unconverted >= 0 && unconverted < loading->ds_t.size) {
4187 /* Look up what state the unconverted number represents. */
4188 ds->max_state = loading->ds_t.order[unconverted];
4189 } else {
4190 log_sg("No valid diplomatic max_state between players %d and %d",
4191 plrno, i);
4193 ds->max_state = DS_WAR;
4196 ds->first_contact_turn =
4197 secfile_lookup_int_default(loading->file, 0,
4198 "%s.first_contact_turn", buf);
4199 ds->turns_left =
4200 secfile_lookup_int_default(loading->file, -2, "%s.turns_left", buf);
4201 ds->has_reason_to_cancel =
4202 secfile_lookup_int_default(loading->file, 0,
4203 "%s.has_reason_to_cancel", buf);
4204 ds->contact_turns_left =
4205 secfile_lookup_int_default(loading->file, 0,
4206 "%s.contact_turns_left", buf);
4208 if (secfile_lookup_bool_default(loading->file, FALSE, "%s.embassy",
4209 buf)) {
4210 BV_SET(plr->real_embassy, i);
4212 /* 'gives_shared_vision' is loaded in sg_load_players() as all cities
4213 * must be known. */
4214 } players_iterate_end;
4216 /* load ai data */
4217 players_iterate(aplayer) {
4218 char buf[32];
4220 fc_snprintf(buf, sizeof(buf), "player%d.ai%d", plrno,
4221 player_index(aplayer));
4223 plr->ai_common.love[player_index(aplayer)] =
4224 secfile_lookup_int_default(loading->file, 1, "%s.love", buf);
4225 CALL_FUNC_EACH_AI(player_load_relations, plr, aplayer, loading->file, plrno);
4226 } players_iterate_end;
4228 CALL_FUNC_EACH_AI(player_load, plr, loading->file, plrno);
4230 /* Some sane defaults */
4231 plr->ai_common.fuzzy = 0;
4232 plr->ai_common.expand = 100;
4233 plr->ai_common.science_cost = 100;
4236 level = secfile_lookup_str_default(loading->file, NULL,
4237 "player%d.ai.level", plrno);
4238 if (level != NULL) {
4239 plr->ai_common.skill_level = ai_level_by_name(level, fc_strcasecmp);
4241 /* In builds where level "Experimental" is not supported, convert it to "Hard" */
4242 if (!ai_level_is_valid(plr->ai_common.skill_level)
4243 && !fc_strcasecmp(level, "Experimental")) {
4244 plr->ai_common.skill_level = AI_LEVEL_HARD;
4246 } else {
4247 plr->ai_common.skill_level = ai_level_invalid();
4250 if (!ai_level_is_valid(plr->ai_common.skill_level)) {
4251 plr->ai_common.skill_level
4252 = ai_level_convert(secfile_lookup_int_default(loading->file,
4253 game.info.skill_level,
4254 "player%d.ai.skill_level",
4255 plrno));
4258 barb_str = secfile_lookup_str_default(loading->file, "None",
4259 "player%d.ai.barb_type", plrno);
4260 plr->ai_common.barbarian_type = barbarian_type_by_name(barb_str, fc_strcasecmp);
4262 if (!barbarian_type_is_valid(plr->ai_common.barbarian_type)) {
4263 log_sg("Player%d: Invalid barbarian type \"%s\". "
4264 "Changed to \"None\".", plrno, barb_str);
4265 plr->ai_common.barbarian_type = NOT_A_BARBARIAN;
4268 if (is_barbarian(plr)) {
4269 server.nbarbarians++;
4272 if (plr->ai_controlled) {
4273 set_ai_level_directer(plr, plr->ai_common.skill_level);
4274 CALL_PLR_AI_FUNC(gained_control, plr, plr);
4277 /* Load nation style. */
4279 struct nation_style *style;
4281 string = secfile_lookup_str(loading->file, "player%d.style_by_name", plrno);
4283 /* Handle pre-2.6 savegames */
4284 if (string == NULL) {
4285 string = secfile_lookup_str(loading->file, "player%d.city_style_by_name",
4286 plrno);
4289 sg_failure_ret(string != NULL, "%s", secfile_error());
4290 style = style_by_rule_name(string);
4291 if (style == NULL) {
4292 style = style_by_number(0);
4293 log_sg("Player%d: unsupported city_style_name \"%s\". "
4294 "Changed to \"%s\".", plrno, string, style_rule_name(style));
4296 plr->style = style;
4299 sg_failure_ret(secfile_lookup_int(loading->file, &plr->nturns_idle,
4300 "player%d.idle_turns", plrno),
4301 "%s", secfile_error());
4302 plr->is_male = secfile_lookup_bool_default(loading->file, TRUE,
4303 "player%d.is_male", plrno);
4304 sg_failure_ret(secfile_lookup_bool(loading->file, &plr->is_alive,
4305 "player%d.is_alive", plrno),
4306 "%s", secfile_error());
4307 sg_failure_ret(secfile_lookup_int(loading->file, &plr->turns_alive,
4308 "player%d.turns_alive", plrno),
4309 "%s", secfile_error());
4310 sg_failure_ret(secfile_lookup_int(loading->file, &plr->last_war_action,
4311 "player%d.last_war", plrno),
4312 "%s", secfile_error());
4313 plr->phase_done = secfile_lookup_bool_default(loading->file, FALSE,
4314 "player%d.phase_done", plrno);
4315 sg_failure_ret(secfile_lookup_int(loading->file, &plr->economic.gold,
4316 "player%d.gold", plrno),
4317 "%s", secfile_error());
4318 sg_failure_ret(secfile_lookup_int(loading->file, &plr->economic.tax,
4319 "player%d.rates.tax", plrno),
4320 "%s", secfile_error());
4321 sg_failure_ret(secfile_lookup_int(loading->file, &plr->economic.science,
4322 "player%d.rates.science", plrno),
4323 "%s", secfile_error());
4324 sg_failure_ret(secfile_lookup_int(loading->file, &plr->economic.luxury,
4325 "player%d.rates.luxury", plrno),
4326 "%s", secfile_error());
4327 plr->server.bulbs_last_turn =
4328 secfile_lookup_int_default(loading->file, 0,
4329 "player%d.research.bulbs_last_turn", plrno);
4331 /* Traits */
4332 if (plr->nation) {
4333 for (i = 0; i < loading->trait.size; i++) {
4334 enum trait tr = trait_by_name(loading->trait.order[i], fc_strcasecmp);
4336 if (trait_is_valid(tr)) {
4337 int val = secfile_lookup_int_default(loading->file, -1, "player%d.trait%d.val",
4338 plrno, i);
4340 if (val != -1) {
4341 plr->ai_common.traits[tr].val = val;
4344 sg_failure_ret(secfile_lookup_int(loading->file, &val,
4345 "player%d.trait%d.mod", plrno, i),
4346 "%s", secfile_error());
4347 plr->ai_common.traits[tr].mod = val;
4352 /* Achievements */
4354 int count;
4356 count = secfile_lookup_int_default(loading->file, -1,
4357 "player%d.achievement_count", plrno);
4359 if (count > 0) {
4360 for (i = 0; i < count; i++) {
4361 const char *name;
4362 struct achievement *pach;
4363 bool first;
4365 name = secfile_lookup_str(loading->file,
4366 "player%d.achievement%d.name", plrno, i);
4367 pach = achievement_by_rule_name(name);
4369 sg_failure_ret(pach != NULL,
4370 "Unknown achievement \"%s\".", name);
4372 sg_failure_ret(secfile_lookup_bool(loading->file, &first,
4373 "player%d.achievement%d.first",
4374 plrno, i),
4375 "achievement error: %s", secfile_error());
4377 sg_failure_ret(pach->first == NULL || !first,
4378 "Multiple players listed as first to get achievement \"%s\".",
4379 name);
4381 BV_SET(pach->achievers, player_index(plr));
4383 if (first) {
4384 pach->first = plr;
4390 /* Player score. */
4391 plr->score.happy =
4392 secfile_lookup_int_default(loading->file, 0,
4393 "score%d.happy", plrno);
4394 plr->score.content =
4395 secfile_lookup_int_default(loading->file, 0,
4396 "score%d.content", plrno);
4397 plr->score.unhappy =
4398 secfile_lookup_int_default(loading->file, 0,
4399 "score%d.unhappy", plrno);
4400 plr->score.angry =
4401 secfile_lookup_int_default(loading->file, 0,
4402 "score%d.angry", plrno);
4404 /* Make sure that the score about specialists in current ruleset that
4405 * were not present at saving time are set to zero. */
4406 specialist_type_iterate(sp) {
4407 plr->score.specialists[sp] = 0;
4408 } specialist_type_iterate_end;
4410 for (i = 0; i < loading->specialist.size; i++) {
4411 plr->score.specialists[specialist_index(loading->specialist.order[i])]
4412 = secfile_lookup_int_default(loading->file, 0,
4413 "score%d.specialists%d", plrno, i);
4416 plr->score.wonders =
4417 secfile_lookup_int_default(loading->file, 0,
4418 "score%d.wonders", plrno);
4419 plr->score.techs =
4420 secfile_lookup_int_default(loading->file, 0,
4421 "score%d.techs", plrno);
4422 plr->score.techout =
4423 secfile_lookup_int_default(loading->file, 0,
4424 "score%d.techout", plrno);
4425 plr->score.landarea =
4426 secfile_lookup_int_default(loading->file, 0,
4427 "score%d.landarea", plrno);
4428 plr->score.settledarea =
4429 secfile_lookup_int_default(loading->file, 0,
4430 "score%d.settledarea", plrno);
4431 plr->score.population =
4432 secfile_lookup_int_default(loading->file, 0,
4433 "score%d.population", plrno);
4434 plr->score.cities =
4435 secfile_lookup_int_default(loading->file, 0,
4436 "score%d.cities", plrno);
4437 plr->score.units =
4438 secfile_lookup_int_default(loading->file, 0,
4439 "score%d.units", plrno);
4440 plr->score.pollution =
4441 secfile_lookup_int_default(loading->file, 0,
4442 "score%d.pollution", plrno);
4443 plr->score.literacy =
4444 secfile_lookup_int_default(loading->file, 0,
4445 "score%d.literacy", plrno);
4446 plr->score.bnp =
4447 secfile_lookup_int_default(loading->file, 0,
4448 "score%d.bnp", plrno);
4449 plr->score.mfg =
4450 secfile_lookup_int_default(loading->file, 0,
4451 "score%d.mfg", plrno);
4452 plr->score.spaceship =
4453 secfile_lookup_int_default(loading->file, 0,
4454 "score%d.spaceship", plrno);
4455 plr->score.units_built =
4456 secfile_lookup_int_default(loading->file, 0,
4457 "score%d.units_built", plrno);
4458 plr->score.units_killed =
4459 secfile_lookup_int_default(loading->file, 0,
4460 "score%d.units_killed", plrno);
4461 plr->score.units_lost =
4462 secfile_lookup_int_default(loading->file, 0,
4463 "score%d.units_lost", plrno);
4464 plr->score.culture =
4465 secfile_lookup_int_default(loading->file, 0,
4466 "score%d.culture", plrno);
4467 plr->score.game =
4468 secfile_lookup_int_default(loading->file, 0,
4469 "score%d.total", plrno);
4471 /* Load space ship data. */
4473 struct player_spaceship *ship = &plr->spaceship;
4474 char prefix[32];
4475 const char *st;
4476 int ei;
4478 fc_snprintf(prefix, sizeof(prefix), "player%d.spaceship", plrno);
4479 spaceship_init(ship);
4480 sg_failure_ret(secfile_lookup_int(loading->file,
4481 &ei,
4482 "%s.state", prefix),
4483 "%s", secfile_error());
4484 ship->state = ei;
4486 if (ship->state != SSHIP_NONE) {
4487 sg_failure_ret(secfile_lookup_int(loading->file, &ship->structurals,
4488 "%s.structurals", prefix),
4489 "%s", secfile_error());
4490 sg_failure_ret(secfile_lookup_int(loading->file, &ship->components,
4491 "%s.components", prefix),
4492 "%s", secfile_error());
4493 sg_failure_ret(secfile_lookup_int(loading->file, &ship->modules,
4494 "%s.modules", prefix),
4495 "%s", secfile_error());
4496 sg_failure_ret(secfile_lookup_int(loading->file, &ship->fuel,
4497 "%s.fuel", prefix),
4498 "%s", secfile_error());
4499 sg_failure_ret(secfile_lookup_int(loading->file, &ship->propulsion,
4500 "%s.propulsion", prefix),
4501 "%s", secfile_error());
4502 sg_failure_ret(secfile_lookup_int(loading->file, &ship->habitation,
4503 "%s.habitation", prefix),
4504 "%s", secfile_error());
4505 sg_failure_ret(secfile_lookup_int(loading->file, &ship->life_support,
4506 "%s.life_support", prefix),
4507 "%s", secfile_error());
4508 sg_failure_ret(secfile_lookup_int(loading->file, &ship->solar_panels,
4509 "%s.solar_panels", prefix),
4510 "%s", secfile_error());
4512 st = secfile_lookup_str(loading->file, "%s.structure", prefix);
4513 sg_failure_ret(st != NULL, "%s", secfile_error())
4514 for (i = 0; i < NUM_SS_STRUCTURALS && st[i]; i++) {
4515 sg_failure_ret(st[i] == '1' || st[i] == '0',
4516 "Undefined value '%c' within '%s.structure'.", st[i],
4517 prefix)
4519 if (!(st[i] == '0')) {
4520 BV_SET(ship->structure, i);
4523 if (ship->state >= SSHIP_LAUNCHED) {
4524 sg_failure_ret(secfile_lookup_int(loading->file, &ship->launch_year,
4525 "%s.launch_year", prefix),
4526 "%s", secfile_error());
4528 spaceship_calc_derived(ship);
4532 /* Load lost wonder data. */
4533 string = secfile_lookup_str(loading->file, "player%d.lost_wonders", plrno);
4534 /* If not present, probably an old savegame; nothing to be done */
4535 if (string) {
4536 int k;
4537 sg_failure_ret(strlen(string) == loading->improvement.size,
4538 "Invalid length for 'player%d.lost_wonders' "
4539 "(%lu ~= %lu)", plrno, (unsigned long) strlen(string),
4540 (unsigned long) loading->improvement.size);
4541 for (k = 0; k < loading->improvement.size; k++) {
4542 sg_failure_ret(string[k] == '1' || string[k] == '0',
4543 "Undefined value '%c' within "
4544 "'player%d.lost_wonders'.", plrno, string[k]);
4546 if (string[k] == '1') {
4547 struct impr_type *pimprove =
4548 improvement_by_rule_name(loading->improvement.order[k]);
4549 if (pimprove) {
4550 plr->wonders[improvement_index(pimprove)] = WONDER_LOST;
4556 plr->culture =
4557 secfile_lookup_int_default(loading->file, 0, "player%d.culture", plrno);
4558 plr->server.huts =
4559 secfile_lookup_int_default(loading->file, 0, "player%d.hut_count", plrno);
4562 /****************************************************************************
4563 Main player data saving function.
4564 ****************************************************************************/
4565 static void sg_save_player_main(struct savedata *saving,
4566 struct player *plr)
4568 int i, k, plrno = player_number(plr);
4569 struct player_spaceship *ship = &plr->spaceship;
4571 /* Check status and return if not OK (sg_success != TRUE). */
4572 sg_check_ret();
4574 secfile_insert_str(saving->file, ai_name(plr->ai),
4575 "player%d.ai_type", plrno);
4576 secfile_insert_str(saving->file, player_name(plr),
4577 "player%d.name", plrno);
4578 secfile_insert_str(saving->file, plr->username,
4579 "player%d.username", plrno);
4580 secfile_insert_bool(saving->file, plr->unassigned_user,
4581 "player%d.unassigned_user", plrno);
4582 if (plr->rgb != NULL) {
4583 rgbcolor_save(saving->file, plr->rgb, "player%d.color", plrno);
4584 } else {
4585 /* Colorless players are ok in pregame */
4586 if (game_was_started()) {
4587 log_sg("Game has started, yet player %d has no color defined.", plrno);
4590 secfile_insert_str(saving->file, plr->ranked_username,
4591 "player%d.ranked_username", plrno);
4592 secfile_insert_bool(saving->file, plr->unassigned_ranked,
4593 "player%d.unassigned_ranked", plrno);
4594 secfile_insert_str(saving->file,
4595 player_delegation_get(plr) ? player_delegation_get(plr)
4596 : "",
4597 "player%d.delegation_username", plrno);
4598 secfile_insert_str(saving->file, nation_rule_name(nation_of_player(plr)),
4599 "player%d.nation", plrno);
4600 secfile_insert_int(saving->file, plr->team ? team_index(plr->team) : -1,
4601 "player%d.team_no", plrno);
4603 secfile_insert_str(saving->file,
4604 government_rule_name(government_of_player(plr)),
4605 "player%d.government_name", plrno);
4607 if (plr->target_government) {
4608 secfile_insert_str(saving->file,
4609 government_rule_name(plr->target_government),
4610 "player%d.target_government_name", plrno);
4613 secfile_insert_str(saving->file, style_rule_name(plr->style),
4614 "player%d.style_by_name", plrno);
4616 secfile_insert_int(saving->file, plr->nturns_idle,
4617 "player%d.idle_turns", plrno);
4618 secfile_insert_bool(saving->file, plr->is_male,
4619 "player%d.is_male", plrno);
4620 secfile_insert_bool(saving->file, plr->is_alive,
4621 "player%d.is_alive", plrno);
4622 secfile_insert_int(saving->file, plr->turns_alive,
4623 "player%d.turns_alive", plrno);
4624 secfile_insert_int(saving->file, plr->last_war_action,
4625 "player%d.last_war", plrno);
4626 secfile_insert_bool(saving->file, plr->ai_controlled,
4627 "player%d.ai.control", plrno);
4628 secfile_insert_bool(saving->file, plr->phase_done,
4629 "player%d.phase_done", plrno);
4631 players_iterate(pplayer) {
4632 char buf[32];
4633 struct player_diplstate *ds = player_diplstate_get(plr, pplayer);
4635 i = player_index(pplayer);
4637 /* save diplomatic state */
4638 fc_snprintf(buf, sizeof(buf), "player%d.diplstate%d", plrno, i);
4640 secfile_insert_int(saving->file, ds->type,
4641 "%s.type", buf);
4642 secfile_insert_int(saving->file, ds->max_state,
4643 "%s.max_state", buf);
4644 secfile_insert_int(saving->file, ds->first_contact_turn,
4645 "%s.first_contact_turn", buf);
4646 secfile_insert_int(saving->file, ds->turns_left,
4647 "%s.turns_left", buf);
4648 secfile_insert_int(saving->file, ds->has_reason_to_cancel,
4649 "%s.has_reason_to_cancel", buf);
4650 secfile_insert_int(saving->file, ds->contact_turns_left,
4651 "%s.contact_turns_left", buf);
4652 secfile_insert_bool(saving->file, player_has_real_embassy(plr, pplayer),
4653 "%s.embassy", buf);
4654 secfile_insert_bool(saving->file, gives_shared_vision(plr, pplayer),
4655 "%s.gives_shared_vision", buf);
4656 } players_iterate_end;
4658 players_iterate(aplayer) {
4659 i = player_index(aplayer);
4660 /* save ai data */
4661 secfile_insert_int(saving->file, plr->ai_common.love[i],
4662 "player%d.ai%d.love", plrno, i);
4663 CALL_FUNC_EACH_AI(player_save_relations, plr, aplayer, saving->file, plrno);
4664 } players_iterate_end;
4666 CALL_FUNC_EACH_AI(player_save, plr, saving->file, plrno);
4668 /* Multipliers (policies) */
4669 i = multiplier_count();
4671 for (k = 0; k < i; k++) {
4672 secfile_insert_int(saving->file, plr->multipliers[k],
4673 "player%d.multiplier%d.val", plrno, k);
4674 secfile_insert_int(saving->file, plr->multipliers_target[k],
4675 "player%d.multiplier%d.target", plrno, k);
4678 secfile_insert_str(saving->file, ai_level_name(plr->ai_common.skill_level),
4679 "player%d.ai.level", plrno);
4680 secfile_insert_str(saving->file, barbarian_type_name(plr->ai_common.barbarian_type),
4681 "player%d.ai.barb_type", plrno);
4682 secfile_insert_int(saving->file, plr->economic.gold,
4683 "player%d.gold", plrno);
4684 secfile_insert_int(saving->file, plr->economic.tax,
4685 "player%d.rates.tax", plrno);
4686 secfile_insert_int(saving->file, plr->economic.science,
4687 "player%d.rates.science", plrno);
4688 secfile_insert_int(saving->file, plr->economic.luxury,
4689 "player%d.rates.luxury", plrno);
4690 secfile_insert_int(saving->file, plr->server.bulbs_last_turn,
4691 "player%d.research.bulbs_last_turn", plrno);
4693 /* Save traits */
4695 enum trait tr;
4696 int j;
4698 for (tr = trait_begin(), j = 0; tr != trait_end(); tr = trait_next(tr), j++) {
4699 secfile_insert_int(saving->file, plr->ai_common.traits[tr].val,
4700 "player%d.trait%d.val", plrno, j);
4701 secfile_insert_int(saving->file, plr->ai_common.traits[tr].mod,
4702 "player%d.trait%d.mod", plrno, j);
4706 /* Save achievements */
4708 int j = 0;
4710 achievements_iterate(pach) {
4711 if (achievement_player_has(pach, plr)) {
4712 secfile_insert_str(saving->file, achievement_rule_name(pach),
4713 "player%d.achievement%d.name", plrno, j);
4714 if (pach->first == plr) {
4715 secfile_insert_bool(saving->file, TRUE,
4716 "player%d.achievement%d.first", plrno, j);
4717 } else {
4718 secfile_insert_bool(saving->file, FALSE,
4719 "player%d.achievement%d.first", plrno, j);
4722 j++;
4724 } achievements_iterate_end;
4726 secfile_insert_int(saving->file, j,
4727 "player%d.achievement_count", plrno);
4730 secfile_insert_bool(saving->file, plr->server.got_first_city,
4731 "player%d.got_first_city", plrno);
4732 secfile_insert_int(saving->file, plr->revolution_finishes,
4733 "player%d.revolution_finishes", plrno);
4735 /* Player score */
4736 secfile_insert_int(saving->file, plr->score.happy,
4737 "score%d.happy", plrno);
4738 secfile_insert_int(saving->file, plr->score.content,
4739 "score%d.content", plrno);
4740 secfile_insert_int(saving->file, plr->score.unhappy,
4741 "score%d.unhappy", plrno);
4742 secfile_insert_int(saving->file, plr->score.angry,
4743 "score%d.angry", plrno);
4744 specialist_type_iterate(sp) {
4745 secfile_insert_int(saving->file, plr->score.specialists[sp],
4746 "score%d.specialists%d", plrno, sp);
4747 } specialist_type_iterate_end;
4748 secfile_insert_int(saving->file, plr->score.wonders,
4749 "score%d.wonders", plrno);
4750 secfile_insert_int(saving->file, plr->score.techs,
4751 "score%d.techs", plrno);
4752 secfile_insert_int(saving->file, plr->score.techout,
4753 "score%d.techout", plrno);
4754 secfile_insert_int(saving->file, plr->score.landarea,
4755 "score%d.landarea", plrno);
4756 secfile_insert_int(saving->file, plr->score.settledarea,
4757 "score%d.settledarea", plrno);
4758 secfile_insert_int(saving->file, plr->score.population,
4759 "score%d.population", plrno);
4760 secfile_insert_int(saving->file, plr->score.cities,
4761 "score%d.cities", plrno);
4762 secfile_insert_int(saving->file, plr->score.units,
4763 "score%d.units", plrno);
4764 secfile_insert_int(saving->file, plr->score.pollution,
4765 "score%d.pollution", plrno);
4766 secfile_insert_int(saving->file, plr->score.literacy,
4767 "score%d.literacy", plrno);
4768 secfile_insert_int(saving->file, plr->score.bnp,
4769 "score%d.bnp", plrno);
4770 secfile_insert_int(saving->file, plr->score.mfg,
4771 "score%d.mfg", plrno);
4772 secfile_insert_int(saving->file, plr->score.spaceship,
4773 "score%d.spaceship", plrno);
4774 secfile_insert_int(saving->file, plr->score.units_built,
4775 "score%d.units_built", plrno);
4776 secfile_insert_int(saving->file, plr->score.units_killed,
4777 "score%d.units_killed", plrno);
4778 secfile_insert_int(saving->file, plr->score.units_lost,
4779 "score%d.units_lost", plrno);
4780 secfile_insert_int(saving->file, plr->score.culture,
4781 "score%d.culture", plrno);
4782 secfile_insert_int(saving->file, plr->score.game,
4783 "score%d.total", plrno);
4785 /* Save space ship status. */
4786 secfile_insert_int(saving->file, ship->state, "player%d.spaceship.state",
4787 plrno);
4788 if (ship->state != SSHIP_NONE) {
4789 char buf[32];
4790 char st[NUM_SS_STRUCTURALS+1];
4791 int ssi;
4793 fc_snprintf(buf, sizeof(buf), "player%d.spaceship", plrno);
4795 secfile_insert_int(saving->file, ship->structurals,
4796 "%s.structurals", buf);
4797 secfile_insert_int(saving->file, ship->components,
4798 "%s.components", buf);
4799 secfile_insert_int(saving->file, ship->modules,
4800 "%s.modules", buf);
4801 secfile_insert_int(saving->file, ship->fuel, "%s.fuel", buf);
4802 secfile_insert_int(saving->file, ship->propulsion, "%s.propulsion", buf);
4803 secfile_insert_int(saving->file, ship->habitation, "%s.habitation", buf);
4804 secfile_insert_int(saving->file, ship->life_support,
4805 "%s.life_support", buf);
4806 secfile_insert_int(saving->file, ship->solar_panels,
4807 "%s.solar_panels", buf);
4809 for(ssi = 0; ssi < NUM_SS_STRUCTURALS; ssi++) {
4810 st[ssi] = BV_ISSET(ship->structure, ssi) ? '1' : '0';
4812 st[ssi] = '\0';
4813 secfile_insert_str(saving->file, st, "%s.structure", buf);
4814 if (ship->state >= SSHIP_LAUNCHED) {
4815 secfile_insert_int(saving->file, ship->launch_year,
4816 "%s.launch_year", buf);
4820 /* Save lost wonders info. */
4822 char lost[B_LAST+1];
4824 improvement_iterate(pimprove) {
4825 if (is_wonder(pimprove) && wonder_is_lost(plr, pimprove)) {
4826 lost[improvement_index(pimprove)] = '1';
4827 } else {
4828 lost[improvement_index(pimprove)] = '0';
4830 } improvement_iterate_end;
4831 lost[improvement_count()] = '\0';
4832 secfile_insert_str(saving->file, lost,
4833 "player%d.lost_wonders", plrno);
4836 secfile_insert_int(saving->file, plr->culture,
4837 "player%d.culture", plrno);
4838 secfile_insert_int(saving->file, plr->server.huts,
4839 "player%d.hut_count", plrno);
4842 /****************************************************************************
4843 Load city data
4844 ****************************************************************************/
4845 static void sg_load_player_cities(struct loaddata *loading,
4846 struct player *plr)
4848 int ncities, i, plrno = player_number(plr);
4849 bool tasks_handled;
4851 /* Check status and return if not OK (sg_success != TRUE). */
4852 sg_check_ret();
4854 sg_failure_ret(secfile_lookup_int(loading->file, &ncities,
4855 "player%d.ncities", plrno),
4856 "%s", secfile_error());
4858 if (!plr->is_alive && ncities > 0) {
4859 log_sg("'player%d.ncities' = %d for dead player!", plrno, ncities);
4860 ncities = 0;
4863 if (!plr->server.got_first_city && ncities > 0) {
4864 /* Probably barbarians in an old savegame; fix up */
4865 plr->server.got_first_city = TRUE;
4868 /* Load all cities of the player. */
4869 for (i = 0; i < ncities; i++) {
4870 char buf[32];
4871 struct city *pcity;
4873 fc_snprintf(buf, sizeof(buf), "player%d.c%d", plrno, i);
4875 /* Create a dummy city. */
4876 pcity = create_city_virtual(plr, NULL, buf);
4877 adv_city_alloc(pcity);
4878 if (!sg_load_player_city(loading, plr, pcity, buf)) {
4879 adv_city_free(pcity);
4880 destroy_city_virtual(pcity);
4881 sg_failure_ret(FALSE, "Error loading city %d of player %d.", i, plrno);
4884 identity_number_reserve(pcity->id);
4885 idex_register_city(pcity);
4887 /* Load the information about the nationality of citizens. This is done
4888 * here because the city sanity check called by citizens_update() requires
4889 * that the city is registered. */
4890 sg_load_player_city_citizens(loading, plr, pcity, buf);
4892 /* After everything is loaded, but before vision. */
4893 map_claim_ownership(city_tile(pcity), plr, city_tile(pcity), TRUE);
4895 /* adding the city contribution to fog-of-war */
4896 pcity->server.vision = vision_new(plr, city_tile(pcity));
4897 vision_reveal_tiles(pcity->server.vision, game.server.vision_reveal_tiles);
4898 city_refresh_vision(pcity);
4900 city_list_append(plr->cities, pcity);
4903 tasks_handled = FALSE;
4904 for (i = 0; !tasks_handled; i++) {
4905 int city_id;
4906 struct city *pcity = NULL;
4908 city_id = secfile_lookup_int_default(loading->file, -1, "player%d.task%d.city",
4909 plrno, i);
4911 if (city_id != -1) {
4912 pcity = player_city_by_number(plr, city_id);
4915 if (pcity != NULL) {
4916 const char *str;
4917 int nat_x, nat_y;
4918 struct worker_task *ptask = fc_malloc(sizeof(struct worker_task));
4920 nat_x = secfile_lookup_int_default(loading->file, -1, "player%d.task%d.x", plrno, i);
4921 nat_y = secfile_lookup_int_default(loading->file, -1, "player%d.task%d.y", plrno, i);
4923 ptask->ptile = native_pos_to_tile(nat_x, nat_y);
4925 str = secfile_lookup_str(loading->file, "player%d.task%d.activity", plrno, i);
4926 ptask->act = unit_activity_by_name(str, fc_strcasecmp);
4928 sg_failure_ret(unit_activity_is_valid(ptask->act),
4929 "Unknown workertask activity %s", str);
4931 str = secfile_lookup_str(loading->file, "player%d.task%d.target", plrno, i);
4933 if (strcmp("-", str)) {
4934 ptask->tgt = extra_type_by_rule_name(str);
4936 sg_failure_ret(ptask->tgt != NULL,
4937 "Unknown workertask target %s", str);
4940 ptask->want = secfile_lookup_int_default(loading->file, 1,
4941 "player%d.task%d.want", plrno, i);
4943 worker_task_list_append(pcity->task_reqs, ptask);
4944 } else {
4945 tasks_handled = TRUE;
4950 /****************************************************************************
4951 Load data for one city. sg_save_player_city() is not defined.
4952 ****************************************************************************/
4953 static bool sg_load_player_city(struct loaddata *loading, struct player *plr,
4954 struct city *pcity, const char *citystr)
4956 struct player *past;
4957 const char *kind, *name, *string;
4958 int id, i, repair, sp_count = 0, workers = 0, value;
4959 int nat_x, nat_y;
4960 citizens size;
4961 const char *stylename;
4963 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_x, "%s.x", citystr),
4964 FALSE, "%s", secfile_error());
4965 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_y, "%s.y", citystr),
4966 FALSE, "%s", secfile_error());
4967 pcity->tile = native_pos_to_tile(nat_x, nat_y);
4968 sg_warn_ret_val(NULL != pcity->tile, FALSE,
4969 "%s has invalid center tile (%d, %d)",
4970 citystr, nat_x, nat_y);
4971 sg_warn_ret_val(NULL == tile_city(pcity->tile), FALSE,
4972 "%s duplicates city (%d, %d)", citystr, nat_x, nat_y);
4974 /* Instead of dying, use 'citystr' string for damaged name. */
4975 sz_strlcpy(pcity->name, secfile_lookup_str_default(loading->file, citystr,
4976 "%s.name", citystr));
4978 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->id, "%s.id",
4979 citystr), FALSE, "%s", secfile_error());
4981 id = secfile_lookup_int_default(loading->file, player_number(plr),
4982 "%s.original", citystr);
4983 past = player_by_number(id);
4984 if (NULL != past) {
4985 pcity->original = past;
4988 sg_warn_ret_val(secfile_lookup_int(loading->file, &value, "%s.size",
4989 citystr), FALSE, "%s", secfile_error());
4990 size = (citizens)value; /* set the correct type */
4991 sg_warn_ret_val(value == (int)size, FALSE,
4992 "Invalid city size: %d, set to %d", value, size);
4993 city_size_set(pcity, size);
4995 for (i = 0; i < loading->specialist.size; i++) {
4996 sg_warn_ret_val(secfile_lookup_int(loading->file, &value, "%s.nspe%d",
4997 citystr, i),
4998 FALSE, "%s", secfile_error());
4999 pcity->specialists[specialist_index(loading->specialist.order[i])]
5000 = (citizens)value;
5001 sp_count += value;
5004 for (i = 0; i < MAX_TRADE_ROUTES; i++) {
5005 pcity->trade[i] = secfile_lookup_int_default(loading->file, 0,
5006 "%s.traderoute%d", citystr, i);
5009 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->food_stock,
5010 "%s.food_stock", citystr),
5011 FALSE, "%s", secfile_error());
5012 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->shield_stock,
5013 "%s.shield_stock", citystr),
5014 FALSE, "%s", secfile_error());
5015 pcity->history =
5016 secfile_lookup_int_default(loading->file, 0, "%s.history", citystr);
5018 pcity->airlift =
5019 secfile_lookup_int_default(loading->file, 0, "%s.airlift", citystr);
5020 pcity->was_happy =
5021 secfile_lookup_bool_default(loading->file, FALSE, "%s.was_happy",
5022 citystr);
5024 pcity->turn_plague =
5025 secfile_lookup_int_default(loading->file, 0, "%s.turn_plague", citystr);
5027 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->anarchy,
5028 "%s.anarchy", citystr),
5029 FALSE, "%s", secfile_error());
5030 pcity->rapture =
5031 secfile_lookup_int_default(loading->file, 0, "%s.rapture", citystr);
5032 pcity->server.steal =
5033 secfile_lookup_int_default(loading->file, 0, "%s.steal", citystr);
5035 /* before did_buy for undocumented hack */
5036 pcity->turn_founded =
5037 secfile_lookup_int_default(loading->file, -2, "%s.turn_founded",
5038 citystr);
5039 sg_warn_ret_val(secfile_lookup_int(loading->file, &i, "%s.did_buy",
5040 citystr), FALSE, "%s", secfile_error());
5041 pcity->did_buy = (i != 0);
5042 if (i == -1 && pcity->turn_founded == -2) {
5043 /* undocumented hack */
5044 pcity->turn_founded = game.info.turn;
5047 pcity->did_sell =
5048 secfile_lookup_bool_default(loading->file, FALSE, "%s.did_sell", citystr);
5050 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->turn_last_built,
5051 "%s.turn_last_built", citystr),
5052 FALSE, "%s", secfile_error());
5054 kind = secfile_lookup_str(loading->file, "%s.currently_building_kind",
5055 citystr);
5056 name = secfile_lookup_str(loading->file, "%s.currently_building_name",
5057 citystr);
5058 pcity->production = universal_by_rule_name(kind, name);
5059 sg_warn_ret_val(pcity->production.kind != universals_n_invalid(), FALSE,
5060 "%s.currently_building: unknown \"%s\" \"%s\".",
5061 citystr, kind, name);
5063 kind = secfile_lookup_str(loading->file, "%s.changed_from_kind",
5064 citystr);
5065 name = secfile_lookup_str(loading->file, "%s.changed_from_name",
5066 citystr);
5067 pcity->changed_from = universal_by_rule_name(kind, name);
5068 sg_warn_ret_val(pcity->changed_from.kind != universals_n_invalid(), FALSE,
5069 "%s.changed_from: unknown \"%s\" \"%s\".",
5070 citystr, kind, name);
5072 pcity->before_change_shields =
5073 secfile_lookup_int_default(loading->file, pcity->shield_stock,
5074 "%s.before_change_shields", citystr);
5075 pcity->caravan_shields =
5076 secfile_lookup_int_default(loading->file, 0,
5077 "%s.caravan_shields", citystr);
5078 pcity->disbanded_shields =
5079 secfile_lookup_int_default(loading->file, 0,
5080 "%s.disbanded_shields", citystr);
5081 pcity->last_turns_shield_surplus =
5082 secfile_lookup_int_default(loading->file, 0,
5083 "%s.last_turns_shield_surplus",
5084 citystr);
5086 stylename = secfile_lookup_str_default(loading->file, NULL,
5087 "%s.style", citystr);
5088 if (stylename != NULL) {
5089 pcity->style = city_style_by_rule_name(stylename);
5090 } else {
5091 pcity->style = 0;
5093 if (pcity->style < 0) {
5094 pcity->style = city_style(pcity);
5097 pcity->server.synced = FALSE; /* must re-sync with clients */
5099 /* Initialise list of city improvements. */
5100 for (i = 0; i < ARRAY_SIZE(pcity->built); i++) {
5101 pcity->built[i].turn = I_NEVER;
5104 /* Load city improvements. */
5105 string = secfile_lookup_str(loading->file, "%s.improvements", citystr);
5106 sg_warn_ret_val(string != NULL, FALSE, "%s", secfile_error());
5107 sg_warn_ret_val(strlen(string) == loading->improvement.size, FALSE,
5108 "Invalid length of '%s.improvements' (%lu ~= %lu).",
5109 citystr, (unsigned long) strlen(string),
5110 (unsigned long) loading->improvement.size);
5111 for (i = 0; i < loading->improvement.size; i++) {
5112 sg_warn_ret_val(string[i] == '1' || string[i] == '0', FALSE,
5113 "Undefined value '%c' within '%s.improvements'.",
5114 string[i], citystr)
5116 if (string[i] == '1') {
5117 struct impr_type *pimprove =
5118 improvement_by_rule_name(loading->improvement.order[i]);
5119 if (pimprove) {
5120 city_add_improvement(pcity, pimprove);
5125 sg_failure_ret_val(loading->worked_tiles != NULL, FALSE,
5126 "No worked tiles map defined.");
5128 city_freeze_workers(pcity);
5130 /* load new savegame with variable (squared) city radius and worked
5131 * tiles map */
5133 int radius_sq
5134 = secfile_lookup_int_default(loading->file, -1, "%s.city_radius_sq",
5135 citystr);
5136 city_map_radius_sq_set(pcity, radius_sq);
5138 city_tile_iterate(radius_sq, city_tile(pcity), ptile) {
5139 if (loading->worked_tiles[ptile->index] == pcity->id) {
5140 tile_set_worked(ptile, pcity);
5141 workers++;
5143 #ifdef FREECIV_DEBUG
5144 /* set this tile to unused; a check for not resetted tiles is
5145 * included in game_load_internal() */
5146 loading->worked_tiles[ptile->index] = -1;
5147 #endif /* FREECIV_DEBUG */
5149 } city_tile_iterate_end;
5151 if (tile_worked(city_tile(pcity)) != pcity) {
5152 struct city *pwork = tile_worked(city_tile(pcity));
5154 if (NULL != pwork) {
5155 log_sg("[%s] city center of '%s' (%d,%d) [%d] is worked by '%s' "
5156 "(%d,%d) [%d]; repairing ", citystr, city_name_get(pcity),
5157 TILE_XY(city_tile(pcity)), city_size_get(pcity), city_name_get(pwork),
5158 TILE_XY(city_tile(pwork)), city_size_get(pwork));
5160 tile_set_worked(city_tile(pcity), NULL); /* remove tile from pwork */
5161 pwork->specialists[DEFAULT_SPECIALIST]++;
5162 auto_arrange_workers(pwork);
5163 } else {
5164 log_sg("[%s] city center of '%s' (%d,%d) [%d] is empty; repairing ",
5165 citystr, city_name_get(pcity), TILE_XY(city_tile(pcity)),
5166 city_size_get(pcity));
5169 /* repair pcity */
5170 tile_set_worked(city_tile(pcity), pcity);
5171 city_repair_size(pcity, -1);
5174 repair = city_size_get(pcity) - sp_count - (workers - FREE_WORKED_TILES);
5175 if (0 != repair) {
5176 log_sg("[%s] size mismatch for '%s' (%d,%d): size [%d] != "
5177 "(workers [%d] - free worked tiles [%d]) + specialists [%d]",
5178 citystr, city_name_get(pcity), TILE_XY(city_tile(pcity)), city_size_get(pcity),
5179 workers, FREE_WORKED_TILES, sp_count);
5181 /* repair pcity */
5182 city_repair_size(pcity, repair);
5185 /* worklist_init() done in create_city_virtual() */
5186 worklist_load(loading->file, &pcity->worklist, "%s", citystr);
5188 /* Load city options. */
5189 BV_CLR_ALL(pcity->city_options);
5190 for (i = 0; i < CITYO_LAST; i++) {
5191 if (secfile_lookup_bool_default(loading->file, FALSE, "%s.option%d",
5192 citystr, i)) {
5193 BV_SET(pcity->city_options, i);
5197 CALL_FUNC_EACH_AI(city_load, loading->file, pcity, citystr);
5199 return TRUE;
5202 /****************************************************************************
5203 Load nationality data for one city.
5204 ****************************************************************************/
5205 static void sg_load_player_city_citizens(struct loaddata *loading,
5206 struct player *plr,
5207 struct city *pcity,
5208 const char *citystr)
5210 if (game.info.citizen_nationality) {
5211 citizens size;
5213 citizens_init(pcity);
5214 player_slots_iterate(pslot) {
5215 int nationality;
5217 nationality = secfile_lookup_int_default(loading->file, -1,
5218 "%s.citizen%d", citystr,
5219 player_slot_index(pslot));
5220 if (nationality > 0 && !player_slot_is_used(pslot)) {
5221 log_sg("Citizens of an invalid nation for %s (player slot %d)!",
5222 city_name_get(pcity), player_slot_index(pslot));
5223 continue;
5226 if (nationality != -1 && player_slot_is_used(pslot)) {
5227 sg_warn(nationality >= 0 && nationality <= MAX_CITY_SIZE,
5228 "Invalid value for citizens of player %d in %s: %d.",
5229 player_slot_index(pslot), city_name_get(pcity), nationality);
5230 citizens_nation_set(pcity, pslot, nationality);
5232 } player_slots_iterate_end;
5233 /* Sanity check. */
5234 size = citizens_count(pcity);
5235 if (size != city_size_get(pcity)) {
5236 if (size != 0) {
5237 /* size == 0 can be result from the fact that ruleset had no
5238 * nationality enabled at saving time, so no citizens at all
5239 * were saved. But something more serious must be going on if
5240 * citizens have been saved partially - if some of them are there. */
5241 log_sg("City size and number of citizens does not match in %s "
5242 "(%d != %d)! Repairing ...", city_name_get(pcity),
5243 city_size_get(pcity), size);
5245 citizens_update(pcity, NULL);
5250 /****************************************************************************
5251 Save cities data
5252 ****************************************************************************/
5253 static void sg_save_player_cities(struct savedata *saving,
5254 struct player *plr)
5256 int wlist_max_length = 0;
5257 int i = 0;
5258 int plrno = player_number(plr);
5259 bool nations[MAX_NUM_PLAYER_SLOTS];
5261 /* Check status and return if not OK (sg_success != TRUE). */
5262 sg_check_ret();
5264 secfile_insert_int(saving->file, city_list_size(plr->cities),
5265 "player%d.ncities", plrno);
5267 if (game.info.citizen_nationality) {
5268 /* Initialise the nation list for the citizens information. */
5269 player_slots_iterate(pslot) {
5270 nations[player_slot_index(pslot)] = FALSE;
5271 } player_slots_iterate_end;
5274 /* First determine lenght of longest worklist and the nations we have. */
5275 city_list_iterate(plr->cities, pcity) {
5276 /* Check the sanity of the city. */
5277 city_refresh(pcity);
5278 sanity_check_city(pcity);
5280 if (pcity->worklist.length > wlist_max_length) {
5281 wlist_max_length = pcity->worklist.length;
5284 if (game.info.citizen_nationality) {
5285 /* Find all nations of the citizens,*/
5286 players_iterate(pplayer) {
5287 if (!nations[player_index(pplayer)]
5288 && citizens_nation_get(pcity, pplayer->slot) != 0) {
5289 nations[player_index(pplayer)] = TRUE;
5291 } players_iterate_end;
5293 } city_list_iterate_end;
5295 city_list_iterate(plr->cities, pcity) {
5296 struct tile *pcenter = city_tile(pcity);
5297 char impr_buf[MAX_NUM_ITEMS + 1];
5298 char buf[32];
5299 int j, nat_x, nat_y;
5301 fc_snprintf(buf, sizeof(buf), "player%d.c%d", plrno, i);
5304 index_to_native_pos(&nat_x, &nat_y, tile_index(pcenter));
5305 secfile_insert_int(saving->file, nat_y, "%s.y", buf);
5306 secfile_insert_int(saving->file, nat_x, "%s.x", buf);
5308 secfile_insert_int(saving->file, pcity->id, "%s.id", buf);
5310 secfile_insert_int(saving->file, player_number(pcity->original),
5311 "%s.original", buf);
5312 secfile_insert_int(saving->file, city_size_get(pcity), "%s.size", buf);
5314 j = 0;
5315 specialist_type_iterate(sp) {
5316 secfile_insert_int(saving->file, pcity->specialists[sp], "%s.nspe%d",
5317 buf, j++);
5318 } specialist_type_iterate_end;
5320 for (j = 0; j < MAX_TRADE_ROUTES; j++) {
5321 secfile_insert_int(saving->file, pcity->trade[j], "%s.traderoute%d",
5322 buf, j);
5325 secfile_insert_int(saving->file, pcity->food_stock, "%s.food_stock",
5326 buf);
5327 secfile_insert_int(saving->file, pcity->shield_stock, "%s.shield_stock",
5328 buf);
5329 secfile_insert_int(saving->file, pcity->history, "%s.history",
5330 buf);
5332 secfile_insert_int(saving->file, pcity->airlift, "%s.airlift",
5333 buf);
5334 secfile_insert_bool(saving->file, pcity->was_happy, "%s.was_happy",
5335 buf);
5336 secfile_insert_int(saving->file, pcity->turn_plague, "%s.turn_plague",
5337 buf);
5339 secfile_insert_int(saving->file, pcity->anarchy, "%s.anarchy", buf);
5340 secfile_insert_int(saving->file, pcity->rapture, "%s.rapture", buf);
5341 secfile_insert_int(saving->file, pcity->server.steal, "%s.steal", buf);
5343 secfile_insert_int(saving->file, pcity->turn_founded, "%s.turn_founded",
5344 buf);
5345 if (pcity->turn_founded == game.info.turn) {
5346 j = -1; /* undocumented hack */
5347 } else {
5348 fc_assert(pcity->did_buy == TRUE || pcity->did_buy == FALSE);
5349 j = pcity->did_buy ? 1 : 0;
5351 secfile_insert_int(saving->file, j, "%s.did_buy", buf);
5352 secfile_insert_bool(saving->file, pcity->did_sell, "%s.did_sell", buf);
5353 secfile_insert_int(saving->file, pcity->turn_last_built,
5354 "%s.turn_last_built", buf);
5356 /* for visual debugging, variable length strings together here */
5357 secfile_insert_str(saving->file, city_name_get(pcity), "%s.name", buf);
5359 secfile_insert_str(saving->file, universal_type_rule_name(&pcity->production),
5360 "%s.currently_building_kind", buf);
5361 secfile_insert_str(saving->file, universal_rule_name(&pcity->production),
5362 "%s.currently_building_name", buf);
5364 secfile_insert_str(saving->file, universal_type_rule_name(&pcity->changed_from),
5365 "%s.changed_from_kind", buf);
5366 secfile_insert_str(saving->file, universal_rule_name(&pcity->changed_from),
5367 "%s.changed_from_name", buf);
5369 secfile_insert_int(saving->file, pcity->before_change_shields,
5370 "%s.before_change_shields", buf);
5371 secfile_insert_int(saving->file, pcity->caravan_shields,
5372 "%s.caravan_shields", buf);
5373 secfile_insert_int(saving->file, pcity->disbanded_shields,
5374 "%s.disbanded_shields", buf);
5375 secfile_insert_int(saving->file, pcity->last_turns_shield_surplus,
5376 "%s.last_turns_shield_surplus", buf);
5378 secfile_insert_str(saving->file, city_style_rule_name(pcity->style),
5379 "%s.style", buf);
5381 /* Save the squared city radius and all tiles within the corresponing
5382 * city map. */
5383 secfile_insert_int(saving->file, pcity->city_radius_sq,
5384 "player%d.c%d.city_radius_sq", plrno, i);
5385 /* The tiles worked by the city are saved using the main map.
5386 * See also sg_save_map_worked(). */
5388 /* Save improvement list as bytevector. Note that improvement order
5389 * is saved in savefile.improvement_order. */
5390 improvement_iterate(pimprove) {
5391 impr_buf[improvement_index(pimprove)]
5392 = (pcity->built[improvement_index(pimprove)].turn <= I_NEVER) ? '0'
5393 : '1';
5394 } improvement_iterate_end;
5395 impr_buf[improvement_count()] = '\0';
5396 sg_failure_ret(strlen(impr_buf) < sizeof(impr_buf),
5397 "Invalid size of the improvement vector (%s.improvements: "
5398 "%lu < %lu).", buf, (long unsigned int) strlen(impr_buf),
5399 (long unsigned int) sizeof(impr_buf));
5400 secfile_insert_str(saving->file, impr_buf, "%s.improvements", buf);
5402 worklist_save(saving->file, &pcity->worklist, wlist_max_length, "%s",
5403 buf);
5405 for (j = 0; j < CITYO_LAST; j++) {
5406 secfile_insert_bool(saving->file, BV_ISSET(pcity->city_options, j),
5407 "%s.option%d", buf, j);
5410 CALL_FUNC_EACH_AI(city_save, saving->file, pcity, buf);
5412 if (game.info.citizen_nationality) {
5413 /* Save nationality of the citizens,*/
5414 players_iterate(pplayer) {
5415 if (nations[player_index(pplayer)]) {
5416 secfile_insert_int(saving->file,
5417 citizens_nation_get(pcity, pplayer->slot),
5418 "%s.citizen%d", buf, player_index(pplayer));
5420 } players_iterate_end;
5423 i++;
5424 } city_list_iterate_end;
5426 i = 0;
5427 city_list_iterate(plr->cities, pcity) {
5428 worker_task_list_iterate(pcity->task_reqs, ptask) {
5429 int nat_x, nat_y;
5431 index_to_native_pos(&nat_x, &nat_y, tile_index(ptask->ptile));
5432 secfile_insert_int(saving->file, pcity->id, "player%d.task%d.city",
5433 plrno, i);
5434 secfile_insert_int(saving->file, nat_y, "player%d.task%d.y", plrno, i);
5435 secfile_insert_int(saving->file, nat_x, "player%d.task%d.x", plrno, i);
5436 secfile_insert_str(saving->file, unit_activity_name(ptask->act),
5437 "player%d.task%d.activity",
5438 plrno, i);
5439 if (ptask->tgt != NULL) {
5440 secfile_insert_str(saving->file, extra_rule_name(ptask->tgt),
5441 "player%d.task%d.target",
5442 plrno, i);
5443 } else {
5444 secfile_insert_str(saving->file, "-",
5445 "player%d.task%d.target",
5446 plrno, i);
5448 secfile_insert_int(saving->file, ptask->want, "player%d.task%d.want", plrno, i);
5450 i++;
5451 } worker_task_list_iterate_end;
5452 } city_list_iterate_end;
5455 /****************************************************************************
5456 Load unit data
5457 ****************************************************************************/
5458 static void sg_load_player_units(struct loaddata *loading,
5459 struct player *plr)
5461 int nunits, i, plrno = player_number(plr);
5463 /* Check status and return if not OK (sg_success != TRUE). */
5464 sg_check_ret();
5466 sg_failure_ret(secfile_lookup_int(loading->file, &nunits,
5467 "player%d.nunits", plrno),
5468 "%s", secfile_error());
5469 if (!plr->is_alive && nunits > 0) {
5470 log_sg("'player%d.nunits' = %d for dead player!", plrno, nunits);
5471 nunits = 0; /* Some old savegames may be buggy. */
5474 for (i = 0; i < nunits; i++) {
5475 struct unit *punit;
5476 struct city *pcity;
5477 const char *name;
5478 char buf[32];
5479 struct unit_type *type;
5480 struct tile *ptile;
5482 fc_snprintf(buf, sizeof(buf), "player%d.u%d", plrno, i);
5484 name = secfile_lookup_str(loading->file, "%s.type_by_name", buf);
5485 type = unit_type_by_rule_name(name);
5486 sg_failure_ret(type != NULL, "%s: unknown unit type \"%s\".", buf, name);
5488 /* Create a dummy unit. */
5489 punit = unit_virtual_create(plr, NULL, type, 0);
5490 if (!sg_load_player_unit(loading, plr, punit, buf)) {
5491 unit_virtual_destroy(punit);
5492 sg_failure_ret(FALSE, "Error loading unit %d of player %d.", i, plrno);
5495 identity_number_reserve(punit->id);
5496 idex_register_unit(punit);
5498 if ((pcity = game_city_by_number(punit->homecity))) {
5499 unit_list_prepend(pcity->units_supported, punit);
5500 } else if (punit->homecity > IDENTITY_NUMBER_ZERO) {
5501 log_sg("%s: bad home city %d.", buf, punit->homecity);
5502 punit->homecity = IDENTITY_NUMBER_ZERO;
5505 ptile = unit_tile(punit);
5507 /* allocate the unit's contribution to fog of war */
5508 punit->server.vision = vision_new(unit_owner(punit), ptile);
5509 unit_refresh_vision(punit);
5510 /* NOTE: There used to be some map_set_known calls here. These were
5511 * unneeded since unfogging the tile when the unit sees it will
5512 * automatically reveal that tile. */
5514 unit_list_append(plr->units, punit);
5515 unit_list_prepend(unit_tile(punit)->units, punit);
5517 /* Claim ownership of fortress? */
5518 if ((extra_owner(ptile) == NULL
5519 || pplayers_at_war(extra_owner(ptile), plr))
5520 && tile_has_claimable_base(ptile, unit_type_get(punit))) {
5521 tile_claim_bases(ptile, plr);
5526 /****************************************************************************
5527 Load one unit. sg_save_player_unit() is not defined.
5528 ****************************************************************************/
5529 static bool sg_load_player_unit(struct loaddata *loading,
5530 struct player *plr, struct unit *punit,
5531 const char *unitstr)
5533 int j;
5534 enum unit_activity activity;
5535 int nat_x, nat_y;
5536 enum tile_special_type target;
5537 struct extra_type *pextra = NULL;
5538 struct base_type *pbase = NULL;
5539 struct road_type *proad = NULL;
5540 struct tile *ptile;
5541 int extra_id;
5542 int base_id;
5543 int road_id;
5544 int ei;
5545 const char *facing_str;
5546 enum tile_special_type cfspe;
5547 int natnbr;
5549 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->id, "%s.id",
5550 unitstr), FALSE, "%s", secfile_error());
5551 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_x, "%s.x", unitstr),
5552 FALSE, "%s", secfile_error());
5553 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_y, "%s.y", unitstr),
5554 FALSE, "%s", secfile_error());
5556 ptile = native_pos_to_tile(nat_x, nat_y);
5557 sg_warn_ret_val(NULL != ptile, FALSE, "%s invalid tile (%d, %d)",
5558 unitstr, nat_x, nat_y);
5559 unit_tile_set(punit, ptile);
5561 facing_str
5562 = secfile_lookup_str_default(loading->file, "x",
5563 "%s.facing", unitstr);
5564 if (facing_str[0] != 'x') {
5565 /* We don't touch punit->facing if savegame does not contain that
5566 * information. Initial orientation set by unit_virtual_create()
5567 * is as good as any. */
5568 enum direction8 facing = char2dir(facing_str[0]);
5570 if (direction8_is_valid(facing)) {
5571 punit->facing = facing;
5572 } else {
5573 log_error("Illegal unit orientation '%s'", facing_str);
5577 /* If savegame has unit nationality, it doesn't hurt to
5578 * internally set it even if nationality rules are disabled. */
5579 natnbr = secfile_lookup_int_default(loading->file,
5580 player_number(plr),
5581 "%s.nationality", unitstr);
5583 punit->nationality = player_by_number(natnbr);
5584 if (punit->nationality == NULL) {
5585 punit->nationality = plr;
5588 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->homecity,
5589 "%s.homecity", unitstr), FALSE,
5590 "%s", secfile_error());
5591 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->moves_left,
5592 "%s.moves", unitstr), FALSE,
5593 "%s", secfile_error());
5594 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->fuel,
5595 "%s.fuel", unitstr), FALSE,
5596 "%s", secfile_error());
5597 sg_warn_ret_val(secfile_lookup_int(loading->file, &ei,
5598 "%s.activity", unitstr), FALSE,
5599 "%s", secfile_error());
5600 activity = ei;
5602 punit->server.birth_turn
5603 = secfile_lookup_int_default(loading->file, game.info.turn,
5604 "%s.born", unitstr);
5606 if (activity == ACTIVITY_PATROL_UNUSED) {
5607 /* Previously ACTIVITY_PATROL and ACTIVITY_GOTO were used for
5608 * client-side goto. Now client-side goto is handled by setting
5609 * a special flag, and units with orders generally have ACTIVITY_IDLE.
5610 * Old orders are lost. Old client-side goto units will still have
5611 * ACTIVITY_GOTO and will goto the correct position via server goto.
5612 * Old client-side patrol units lose their patrol routes and are put
5613 * into idle mode. */
5614 activity = ACTIVITY_IDLE;
5617 extra_id = secfile_lookup_int_default(loading->file, -2,
5618 "%s.activity_tgt", unitstr);
5620 if (extra_id != -2) {
5621 if (extra_id >= 0 && extra_id < loading->extra.size) {
5622 pextra = loading->extra.order[extra_id];
5623 set_unit_activity_targeted(punit, activity, pextra);
5624 } else if (activity == ACTIVITY_IRRIGATE) {
5625 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
5626 EC_IRRIGATION,
5627 unit_owner(punit),
5628 punit);
5629 if (tgt != NULL) {
5630 set_unit_activity_targeted(punit, ACTIVITY_IRRIGATE, tgt);
5631 } else {
5632 set_unit_activity_targeted(punit, ACTIVITY_IRRIGATE, NULL);
5634 } else if (activity == ACTIVITY_MINE) {
5635 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
5636 EC_MINE,
5637 unit_owner(punit),
5638 punit);
5639 if (tgt != NULL) {
5640 set_unit_activity_targeted(punit, ACTIVITY_MINE, tgt);
5641 } else {
5642 set_unit_activity_targeted(punit, ACTIVITY_MINE, NULL);
5644 } else {
5645 set_unit_activity(punit, activity);
5647 } else {
5648 /* extra_id == -2 -> activity_tgt not set */
5649 base_id = secfile_lookup_int_default(loading->file, -1,
5650 "%s.activity_base", unitstr);
5651 if (base_id >= 0 && base_id < loading->base.size) {
5652 pbase = loading->base.order[base_id];
5654 road_id = secfile_lookup_int_default(loading->file, -1,
5655 "%s.activity_road", unitstr);
5656 if (road_id >= 0 && road_id < loading->road.size) {
5657 proad = loading->road.order[road_id];
5661 int tgt_no = secfile_lookup_int_default(loading->file,
5662 loading->special.size /* S_LAST */,
5663 "%s.activity_target", unitstr);
5664 if (tgt_no >= 0 && tgt_no < loading->special.size) {
5665 target = loading->special.order[tgt_no];
5666 } else {
5667 target = S_LAST;
5671 if (target == S_OLD_ROAD) {
5672 target = S_LAST;
5673 proad = road_by_compat_special(ROCO_ROAD);
5674 } else if (target == S_OLD_RAILROAD) {
5675 target = S_LAST;
5676 proad = road_by_compat_special(ROCO_RAILROAD);
5679 if (activity == ACTIVITY_OLD_ROAD) {
5680 activity = ACTIVITY_GEN_ROAD;
5681 proad = road_by_compat_special(ROCO_ROAD);
5682 } else if (activity == ACTIVITY_OLD_RAILROAD) {
5683 activity = ACTIVITY_GEN_ROAD;
5684 proad = road_by_compat_special(ROCO_RAILROAD);
5687 /* We need changed_from == ACTIVITY_IDLE by now so that
5688 * set_unit_activity() and friends don't spuriously restore activity
5689 * points -- unit should have been created this way */
5690 fc_assert(punit->changed_from == ACTIVITY_IDLE);
5692 if (activity == ACTIVITY_BASE) {
5693 if (pbase) {
5694 set_unit_activity_base(punit, base_number(pbase));
5695 } else {
5696 log_sg("Cannot find base %d for %s to build",
5697 base_id, unit_rule_name(punit));
5698 set_unit_activity(punit, ACTIVITY_IDLE);
5700 } else if (activity == ACTIVITY_GEN_ROAD) {
5701 if (proad) {
5702 set_unit_activity_road(punit, road_number(proad));
5703 } else {
5704 log_sg("Cannot find road %d for %s to build",
5705 road_id, unit_rule_name(punit));
5706 set_unit_activity(punit, ACTIVITY_IDLE);
5708 } else if (activity == ACTIVITY_PILLAGE) {
5709 struct extra_type *a_target;
5711 if (target != S_LAST) {
5712 a_target = special_extra_get(target);
5713 } else if (pbase != NULL) {
5714 a_target = base_extra_get(pbase);
5715 } else if (proad != NULL) {
5716 a_target = road_extra_get(proad);
5717 } else {
5718 a_target = NULL;
5720 /* An out-of-range base number is seen with old savegames. We take
5721 * it as indicating undirected pillaging. We will assign pillage
5722 * targets before play starts. */
5723 set_unit_activity_targeted(punit, activity, a_target);
5724 } else if (activity == ACTIVITY_IRRIGATE) {
5725 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
5726 EC_IRRIGATION,
5727 unit_owner(punit),
5728 punit);
5729 if (tgt != NULL) {
5730 set_unit_activity_targeted(punit, ACTIVITY_IRRIGATE, tgt);
5731 } else {
5732 set_unit_activity_targeted(punit, ACTIVITY_IRRIGATE, NULL);
5734 } else if (activity == ACTIVITY_MINE) {
5735 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
5736 EC_MINE,
5737 unit_owner(punit),
5738 punit);
5739 if (tgt != NULL) {
5740 set_unit_activity_targeted(punit, ACTIVITY_MINE, tgt);
5741 } else {
5742 set_unit_activity_targeted(punit, ACTIVITY_MINE, NULL);
5744 } else if (activity == ACTIVITY_POLLUTION) {
5745 struct extra_type *tgt = prev_extra_in_tile(unit_tile(punit),
5746 ERM_CLEANPOLLUTION,
5747 unit_owner(punit),
5748 punit);
5749 if (tgt != NULL) {
5750 set_unit_activity_targeted(punit, ACTIVITY_POLLUTION, tgt);
5751 } else {
5752 set_unit_activity_targeted(punit, ACTIVITY_POLLUTION, NULL);
5754 } else if (activity == ACTIVITY_FALLOUT) {
5755 struct extra_type *tgt = prev_extra_in_tile(unit_tile(punit),
5756 ERM_CLEANFALLOUT,
5757 unit_owner(punit),
5758 punit);
5759 if (tgt != NULL) {
5760 set_unit_activity_targeted(punit, ACTIVITY_FALLOUT, tgt);
5761 } else {
5762 set_unit_activity_targeted(punit, ACTIVITY_FALLOUT, NULL);
5764 } else {
5765 set_unit_activity_targeted(punit, activity, NULL);
5767 } /* activity_tgt == NULL */
5769 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->activity_count,
5770 "%s.activity_count", unitstr), FALSE,
5771 "%s", secfile_error());
5773 punit->changed_from =
5774 secfile_lookup_int_default(loading->file, ACTIVITY_IDLE,
5775 "%s.changed_from", unitstr);
5777 extra_id = secfile_lookup_int_default(loading->file, -2,
5778 "%s.changed_from_tgt", unitstr);
5780 if (extra_id != -2) {
5781 if (extra_id >= 0 && extra_id < loading->extra.size) {
5782 punit->changed_from_target = loading->extra.order[extra_id];
5783 } else {
5784 punit->changed_from_target = NULL;
5786 } else {
5787 /* extra_id == -2 -> changed_from_tgt not set */
5789 cfspe =
5790 secfile_lookup_int_default(loading->file, S_LAST,
5791 "%s.changed_from_target", unitstr);
5792 base_id =
5793 secfile_lookup_int_default(loading->file, -1,
5794 "%s.changed_from_base", unitstr);
5795 road_id =
5796 secfile_lookup_int_default(loading->file, -1,
5797 "%s.changed_from_road", unitstr);
5799 if (road_id == -1) {
5800 if (cfspe == S_OLD_ROAD) {
5801 proad = road_by_compat_special(ROCO_ROAD);
5802 if (proad) {
5803 road_id = road_index(proad);
5805 } else if (cfspe == S_OLD_RAILROAD) {
5806 proad = road_by_compat_special(ROCO_RAILROAD);
5807 if (proad) {
5808 road_id = road_index(proad);
5813 if (base_id >= 0 && base_id < loading->base.size) {
5814 punit->changed_from_target = base_extra_get(loading->base.order[base_id]);
5815 } else if (road_id >= 0 && road_id < loading->road.size) {
5816 punit->changed_from_target = road_extra_get(loading->road.order[road_id]);
5817 } else if (cfspe != S_LAST) {
5818 punit->changed_from_target = special_extra_get(cfspe);
5819 } else {
5820 punit->changed_from_target = NULL;
5823 if (punit->changed_from == ACTIVITY_IRRIGATE) {
5824 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
5825 EC_IRRIGATION,
5826 unit_owner(punit),
5827 punit);
5828 if (tgt != NULL) {
5829 punit->changed_from_target = tgt;
5830 } else {
5831 punit->changed_from_target = NULL;
5833 } else if (punit->changed_from == ACTIVITY_MINE) {
5834 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
5835 EC_MINE,
5836 unit_owner(punit),
5837 punit);
5838 if (tgt != NULL) {
5839 punit->changed_from_target = tgt;
5840 } else {
5841 punit->changed_from_target = NULL;
5843 } else if (punit->changed_from == ACTIVITY_POLLUTION) {
5844 struct extra_type *tgt = prev_extra_in_tile(unit_tile(punit),
5845 ERM_CLEANPOLLUTION,
5846 unit_owner(punit),
5847 punit);
5848 if (tgt != NULL) {
5849 punit->changed_from_target = tgt;
5850 } else {
5851 punit->changed_from_target = NULL;
5853 } else if (punit->changed_from == ACTIVITY_FALLOUT) {
5854 struct extra_type *tgt = prev_extra_in_tile(unit_tile(punit),
5855 ERM_CLEANFALLOUT,
5856 unit_owner(punit),
5857 punit);
5858 if (tgt != NULL) {
5859 punit->changed_from_target = tgt;
5860 } else {
5861 punit->changed_from_target = NULL;
5866 punit->changed_from_count =
5867 secfile_lookup_int_default(loading->file, 0,
5868 "%s.changed_from_count", unitstr);
5870 /* Special case: for a long time, we accidentally incremented
5871 * activity_count while a unit was sentried, so it could increase
5872 * without bound (bug #20641) and be saved in old savefiles.
5873 * We zero it to prevent potential trouble overflowing the range
5874 * in network packets, etc. */
5875 if (activity == ACTIVITY_SENTRY) {
5876 punit->activity_count = 0;
5878 if (punit->changed_from == ACTIVITY_SENTRY) {
5879 punit->changed_from_count = 0;
5882 punit->veteran
5883 = secfile_lookup_int_default(loading->file, 0, "%s.veteran", unitstr);
5885 /* Protect against change in veteran system in ruleset */
5886 const int levels = utype_veteran_levels(unit_type_get(punit));
5887 if (punit->veteran >= levels) {
5888 fc_assert(levels >= 1);
5889 punit->veteran = levels - 1;
5892 punit->done_moving
5893 = secfile_lookup_bool_default(loading->file, (punit->moves_left == 0),
5894 "%s.done_moving", unitstr);
5895 punit->battlegroup
5896 = secfile_lookup_int_default(loading->file, BATTLEGROUP_NONE,
5897 "%s.battlegroup", unitstr);
5899 if (secfile_lookup_bool_default(loading->file, FALSE,
5900 "%s.go", unitstr)) {
5901 int gnat_x, gnat_y;
5903 sg_warn_ret_val(secfile_lookup_int(loading->file, &gnat_x,
5904 "%s.goto_x", unitstr), FALSE,
5905 "%s", secfile_error());
5906 sg_warn_ret_val(secfile_lookup_int(loading->file, &gnat_y,
5907 "%s.goto_y", unitstr), FALSE,
5908 "%s", secfile_error());
5910 punit->goto_tile = native_pos_to_tile(gnat_x, gnat_y);
5911 } else {
5912 punit->goto_tile = NULL;
5914 /* These variables are not used but needed for saving the unit table.
5915 * Load them to prevent unused variables errors. */
5916 (void) secfile_entry_lookup(loading->file, "%s.goto_x", unitstr);
5917 (void) secfile_entry_lookup(loading->file, "%s.goto_y", unitstr);
5920 /* Load AI data of the unit. */
5921 CALL_FUNC_EACH_AI(unit_load, loading->file, punit, unitstr);
5923 sg_warn_ret_val(secfile_lookup_bool(loading->file,
5924 &punit->ai_controlled,
5925 "%s.ai", unitstr), FALSE,
5926 "%s", secfile_error());
5927 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->hp,
5928 "%s.hp", unitstr), FALSE,
5929 "%s", secfile_error());
5931 punit->server.ord_map
5932 = secfile_lookup_int_default(loading->file, 0, "%s.ord_map", unitstr);
5933 punit->server.ord_city
5934 = secfile_lookup_int_default(loading->file, 0, "%s.ord_city", unitstr);
5935 punit->moved
5936 = secfile_lookup_bool_default(loading->file, FALSE, "%s.moved", unitstr);
5937 punit->paradropped
5938 = secfile_lookup_bool_default(loading->file, FALSE,
5939 "%s.paradropped", unitstr);
5941 /* The transport status (punit->transported_by) is loaded in
5942 * sg_player_units_transport(). */
5944 /* Initialize upkeep values: these are hopefully initialized
5945 * elsewhere before use (specifically, in city_support(); but
5946 * fixme: check whether always correctly initialized?).
5947 * Below is mainly for units which don't have homecity --
5948 * otherwise these don't get initialized (and AI calculations
5949 * etc may use junk values). */
5950 output_type_iterate(o) {
5951 punit->upkeep[o] = utype_upkeep_cost(unit_type_get(punit), plr, o);
5952 } output_type_iterate_end;
5954 punit->action_decision_want
5955 = secfile_lookup_enum_default(loading->file,
5956 ACT_DEC_NOTHING, action_decision,
5957 "%s.action_decision_want", unitstr);
5959 if (punit->action_decision_want != ACT_DEC_NOTHING) {
5960 /* Load the tile to act against. */
5961 int adwt_x, adwt_y;
5963 if (secfile_lookup_int(loading->file, &adwt_x,
5964 "%s.action_decision_tile_x", unitstr)
5965 && secfile_lookup_int(loading->file, &adwt_y,
5966 "%s.action_decision_tile_y", unitstr)) {
5967 punit->action_decision_tile = native_pos_to_tile(adwt_x, adwt_y);
5968 } else {
5969 punit->action_decision_want = ACT_DEC_NOTHING;
5970 punit->action_decision_tile = NULL;
5971 log_sg("Bad action_decision_tile for unit %d", punit->id);
5973 } else {
5974 (void) secfile_entry_lookup(loading->file, "%s.action_decision_tile_x", unitstr);
5975 (void) secfile_entry_lookup(loading->file, "%s.action_decision_tile_y", unitstr);
5976 punit->action_decision_tile = NULL;
5979 /* load the unit orders */
5981 int len = secfile_lookup_int_default(loading->file, 0,
5982 "%s.orders_length", unitstr);
5983 if (len > 0) {
5984 const char *orders_unitstr, *dir_unitstr, *act_unitstr;
5985 const char *tgt_unitstr;
5986 const char *base_unitstr = NULL;
5987 const char *road_unitstr = NULL;
5988 int road_idx = road_index(road_by_compat_special(ROCO_ROAD));
5989 int rail_idx = road_index(road_by_compat_special(ROCO_RAILROAD));
5991 punit->orders.list = fc_malloc(len * sizeof(*(punit->orders.list)));
5992 punit->orders.length = len;
5993 punit->orders.index
5994 = secfile_lookup_int_default(loading->file, 0,
5995 "%s.orders_index", unitstr);
5996 punit->orders.repeat
5997 = secfile_lookup_bool_default(loading->file, FALSE,
5998 "%s.orders_repeat", unitstr);
5999 punit->orders.vigilant
6000 = secfile_lookup_bool_default(loading->file, FALSE,
6001 "%s.orders_vigilant", unitstr);
6003 orders_unitstr
6004 = secfile_lookup_str_default(loading->file, "",
6005 "%s.orders_list", unitstr);
6006 dir_unitstr
6007 = secfile_lookup_str_default(loading->file, "",
6008 "%s.dir_list", unitstr);
6009 act_unitstr
6010 = secfile_lookup_str_default(loading->file, "",
6011 "%s.activity_list", unitstr);
6012 tgt_unitstr
6013 = secfile_lookup_str_default(loading->file, NULL, "%s.tgt_list", unitstr);
6015 if (tgt_unitstr == NULL) {
6016 base_unitstr
6017 = secfile_lookup_str(loading->file, "%s.base_list", unitstr);
6018 road_unitstr
6019 = secfile_lookup_str_default(loading->file, NULL, "%s.road_list", unitstr);
6022 punit->has_orders = TRUE;
6023 for (j = 0; j < len; j++) {
6024 struct unit_order *order = &punit->orders.list[j];
6026 if (orders_unitstr[j] == '\0' || dir_unitstr[j] == '\0'
6027 || act_unitstr[j] == '\0') {
6028 log_sg("Invalid unit orders.");
6029 free_unit_orders(punit);
6030 break;
6032 order->order = char2order(orders_unitstr[j]);
6033 order->dir = char2dir(dir_unitstr[j]);
6034 order->activity = char2activity(act_unitstr[j]);
6035 if (order->order == ORDER_LAST
6036 || (order->order == ORDER_MOVE && !direction8_is_valid(order->dir))
6037 || (order->order == ORDER_ACTION_MOVE
6038 && !direction8_is_valid(order->dir))
6039 || (order->order == ORDER_ACTIVITY
6040 && order->activity == ACTIVITY_LAST)) {
6041 /* An invalid order. Just drop the orders for this unit. */
6042 free(punit->orders.list);
6043 punit->orders.list = NULL;
6044 punit->has_orders = FALSE;
6045 break;
6048 if (tgt_unitstr) {
6049 if (tgt_unitstr[j] != '?') {
6050 extra_id = char2num(tgt_unitstr[j]);
6052 if (extra_id < 0 || extra_id >= loading->extra.size) {
6053 log_sg("Cannot find extra %d for %s to build",
6054 extra_id, unit_rule_name(punit));
6055 order->target = EXTRA_NONE;
6056 } else {
6057 order->target = extra_id;
6059 } else {
6060 order->target = EXTRA_NONE;
6062 } else {
6063 /* In pre-2.6 savegames, base_list and road_list were only saved
6064 * for those activities (and not e.g. pillaging) */
6065 if (base_unitstr && base_unitstr[j] != '?'
6066 && order->activity == ACTIVITY_BASE) {
6067 base_id = char2num(base_unitstr[j]);
6069 if (base_id < 0 || base_id >= loading->base.size) {
6070 log_sg("Cannot find base %d for %s to build",
6071 base_id, unit_rule_name(punit));
6072 base_id = base_number(get_base_by_gui_type(BASE_GUI_FORTRESS,
6073 NULL, NULL));
6076 order->target
6077 = extra_number(base_extra_get(base_by_number(base_id)));
6078 } else if (road_unitstr && road_unitstr[j] != '?'
6079 && order->activity == ACTIVITY_GEN_ROAD) {
6080 road_id = char2num(road_unitstr[j]);
6082 if (road_id < 0 || road_id >= loading->road.size) {
6083 log_sg("Cannot find road %d for %s to build",
6084 road_id, unit_rule_name(punit));
6085 road_id = 0;
6088 order->target
6089 = extra_number(road_extra_get(road_by_number(road_id)));
6090 } else {
6091 order->target = EXTRA_NONE;
6094 if (order->activity == ACTIVITY_OLD_ROAD) {
6095 order->activity = ACTIVITY_GEN_ROAD;
6096 order->target
6097 = extra_number(road_extra_get(road_by_number(road_idx)));
6098 } else if (order->activity == ACTIVITY_OLD_RAILROAD) {
6099 order->activity = ACTIVITY_GEN_ROAD;
6100 order->target
6101 = extra_number(road_extra_get(road_by_number(rail_idx)));
6105 } else {
6106 punit->has_orders = FALSE;
6107 punit->orders.list = NULL;
6109 (void) secfile_entry_lookup(loading->file, "%s.orders_index", unitstr);
6110 (void) secfile_entry_lookup(loading->file, "%s.orders_repeat", unitstr);
6111 (void) secfile_entry_lookup(loading->file, "%s.orders_vigilant", unitstr);
6112 (void) secfile_entry_lookup(loading->file, "%s.orders_list", unitstr);
6113 (void) secfile_entry_lookup(loading->file, "%s.dir_list", unitstr);
6114 (void) secfile_entry_lookup(loading->file, "%s.activity_list", unitstr);
6115 (void) secfile_entry_lookup(loading->file, "%s.tgt_list", unitstr);
6119 return TRUE;
6122 /*****************************************************************************
6123 Load the transport status of all units. This is seperated from the other
6124 code as all units must be known.
6125 *****************************************************************************/
6126 static void sg_load_player_units_transport(struct loaddata *loading,
6127 struct player *plr)
6129 int nunits, i, plrno = player_number(plr);
6131 /* Check status and return if not OK (sg_success != TRUE). */
6132 sg_check_ret();
6134 /* Recheck the number of units for the player. This is a copied from
6135 * sg_load_player_units(). */
6136 sg_failure_ret(secfile_lookup_int(loading->file, &nunits,
6137 "player%d.nunits", plrno),
6138 "%s", secfile_error());
6139 if (!plr->is_alive && nunits > 0) {
6140 log_sg("'player%d.nunits' = %d for dead player!", plrno, nunits);
6141 nunits = 0; /* Some old savegames may be buggy. */
6144 for (i = 0; i < nunits; i++) {
6145 int id_unit, id_trans;
6146 struct unit *punit, *ptrans;
6148 id_unit = secfile_lookup_int_default(loading->file, -1,
6149 "player%d.u%d.id",
6150 plrno, i);
6151 punit = player_unit_by_number(plr, id_unit);
6152 fc_assert_action(punit != NULL, continue);
6154 id_trans = secfile_lookup_int_default(loading->file, -1,
6155 "player%d.u%d.transported_by",
6156 plrno, i);
6157 if (id_trans == -1) {
6158 /* Not transported. */
6159 continue;
6162 ptrans = game_unit_by_number(id_trans);
6163 fc_assert_action(id_trans == -1 || ptrans != NULL, continue);
6165 if (ptrans) {
6166 bool load_success = unit_transport_load(punit, ptrans, TRUE);
6168 fc_assert_action(load_success == TRUE, continue);
6173 /****************************************************************************
6174 Save unit data
6175 ****************************************************************************/
6176 static void sg_save_player_units(struct savedata *saving,
6177 struct player *plr)
6179 int i = 0;
6181 /* Check status and return if not OK (sg_success != TRUE). */
6182 sg_check_ret();
6184 secfile_insert_int(saving->file, unit_list_size(plr->units),
6185 "player%d.nunits", player_number(plr));
6187 unit_list_iterate(plr->units, punit) {
6188 char buf[32];
6189 char dirbuf[2] = " ";
6190 int nat_x, nat_y;
6192 fc_snprintf(buf, sizeof(buf), "player%d.u%d", player_number(plr), i);
6193 dirbuf[0] = dir2char(punit->facing);
6194 secfile_insert_int(saving->file, punit->id, "%s.id", buf);
6196 index_to_native_pos(&nat_x, &nat_y, tile_index(unit_tile(punit)));
6197 secfile_insert_int(saving->file, nat_x, "%s.x", buf);
6198 secfile_insert_int(saving->file, nat_y, "%s.y", buf);
6200 secfile_insert_str(saving->file, dirbuf, "%s.facing", buf);
6201 if (game.info.citizen_nationality) {
6202 secfile_insert_int(saving->file, player_number(unit_nationality(punit)),
6203 "%s.nationality", buf);
6205 secfile_insert_int(saving->file, punit->veteran, "%s.veteran", buf);
6206 secfile_insert_int(saving->file, punit->hp, "%s.hp", buf);
6207 secfile_insert_int(saving->file, punit->homecity, "%s.homecity", buf);
6208 secfile_insert_str(saving->file, unit_rule_name(punit),
6209 "%s.type_by_name", buf);
6211 secfile_insert_int(saving->file, punit->activity, "%s.activity", buf);
6212 secfile_insert_int(saving->file, punit->activity_count,
6213 "%s.activity_count", buf);
6214 if (punit->activity_target == NULL) {
6215 secfile_insert_int(saving->file, -1, "%s.activity_tgt", buf);
6216 } else {
6217 secfile_insert_int(saving->file, extra_index(punit->activity_target),
6218 "%s.activity_tgt", buf);
6221 secfile_insert_int(saving->file, punit->changed_from,
6222 "%s.changed_from", buf);
6223 secfile_insert_int(saving->file, punit->changed_from_count,
6224 "%s.changed_from_count", buf);
6225 if (punit->changed_from_target == NULL) {
6226 secfile_insert_int(saving->file, -1, "%s.changed_from_tgt", buf);
6227 } else {
6228 secfile_insert_int(saving->file, extra_index(punit->changed_from_target),
6229 "%s.changed_from_tgt", buf);
6232 secfile_insert_bool(saving->file, punit->done_moving,
6233 "%s.done_moving", buf);
6234 secfile_insert_int(saving->file, punit->moves_left, "%s.moves", buf);
6235 secfile_insert_int(saving->file, punit->fuel, "%s.fuel", buf);
6236 secfile_insert_int(saving->file, punit->server.birth_turn,
6237 "%s.born", buf);
6238 secfile_insert_int(saving->file, punit->battlegroup,
6239 "%s.battlegroup", buf);
6241 if (punit->goto_tile) {
6242 index_to_native_pos(&nat_x, &nat_y, tile_index(punit->goto_tile));
6243 secfile_insert_bool(saving->file, TRUE, "%s.go", buf);
6244 secfile_insert_int(saving->file, nat_x, "%s.goto_x", buf);
6245 secfile_insert_int(saving->file, nat_y, "%s.goto_y", buf);
6246 } else {
6247 secfile_insert_bool(saving->file, FALSE, "%s.go", buf);
6248 /* Set this values to allow saving it as table. */
6249 secfile_insert_int(saving->file, 0, "%s.goto_x", buf);
6250 secfile_insert_int(saving->file, 0, "%s.goto_y", buf);
6253 secfile_insert_bool(saving->file, punit->ai_controlled,
6254 "%s.ai", buf);
6256 /* Save AI data of the unit. */
6257 CALL_FUNC_EACH_AI(unit_save, saving->file, punit, buf);
6259 secfile_insert_int(saving->file, punit->server.ord_map,
6260 "%s.ord_map", buf);
6261 secfile_insert_int(saving->file, punit->server.ord_city,
6262 "%s.ord_city", buf);
6263 secfile_insert_bool(saving->file, punit->moved, "%s.moved", buf);
6264 secfile_insert_bool(saving->file, punit->paradropped,
6265 "%s.paradropped", buf);
6266 secfile_insert_int(saving->file, unit_transport_get(punit)
6267 ? unit_transport_get(punit)->id : -1,
6268 "%s.transported_by", buf);
6270 secfile_insert_enum(saving->file, punit->action_decision_want,
6271 action_decision, "%s.action_decision_want", buf);
6273 /* Stored as tile rather than direction to make sure the target tile is
6274 * sane. */
6275 if (punit->action_decision_tile) {
6276 index_to_native_pos(&nat_x, &nat_y,
6277 tile_index(punit->action_decision_tile));
6278 secfile_insert_int(saving->file, nat_x,
6279 "%s.action_decision_tile_x", buf);
6280 secfile_insert_int(saving->file, nat_y,
6281 "%s.action_decision_tile_y", buf);
6282 } else {
6283 /* Dummy values to get tabular format. */
6284 secfile_insert_int(saving->file, -1,
6285 "%s.action_decision_tile_x", buf);
6286 secfile_insert_int(saving->file, -1,
6287 "%s.action_decision_tile_y", buf);
6290 if (punit->has_orders) {
6291 int len = punit->orders.length, j;
6292 char orders_buf[len + 1], dir_buf[len + 1];
6293 char act_buf[len + 1], tgt_buf[len + 1];
6295 secfile_insert_int(saving->file, len, "%s.orders_length", buf);
6296 secfile_insert_int(saving->file, punit->orders.index,
6297 "%s.orders_index", buf);
6298 secfile_insert_bool(saving->file, punit->orders.repeat,
6299 "%s.orders_repeat", buf);
6300 secfile_insert_bool(saving->file, punit->orders.vigilant,
6301 "%s.orders_vigilant", buf);
6303 for (j = 0; j < len; j++) {
6304 orders_buf[j] = order2char(punit->orders.list[j].order);
6305 dir_buf[j] = '?';
6306 act_buf[j] = '?';
6307 tgt_buf[j] = '?';
6308 switch (punit->orders.list[j].order) {
6309 case ORDER_MOVE:
6310 case ORDER_ACTION_MOVE:
6311 dir_buf[j] = dir2char(punit->orders.list[j].dir);
6312 break;
6313 case ORDER_ACTIVITY:
6314 tgt_buf[j] = num2char(punit->orders.list[j].target);
6315 act_buf[j] = activity2char(punit->orders.list[j].activity);
6316 break;
6317 case ORDER_FULL_MP:
6318 case ORDER_BUILD_CITY:
6319 case ORDER_DISBAND:
6320 case ORDER_BUILD_WONDER:
6321 case ORDER_TRADE_ROUTE:
6322 case ORDER_HOMECITY:
6323 case ORDER_LAST:
6324 break;
6327 orders_buf[len] = dir_buf[len] = act_buf[len] = tgt_buf[len] = '\0';
6329 secfile_insert_str(saving->file, orders_buf, "%s.orders_list", buf);
6330 secfile_insert_str(saving->file, dir_buf, "%s.dir_list", buf);
6331 secfile_insert_str(saving->file, act_buf, "%s.activity_list", buf);
6332 secfile_insert_str(saving->file, tgt_buf, "%s.tgt_list", buf);
6333 } else {
6334 /* Put all the same fields into the savegame - otherwise the
6335 * registry code can't correctly use a tabular format and the
6336 * savegame will be bigger. */
6337 secfile_insert_int(saving->file, 0, "%s.orders_length", buf);
6338 secfile_insert_int(saving->file, 0, "%s.orders_index", buf);
6339 secfile_insert_bool(saving->file, FALSE, "%s.orders_repeat", buf);
6340 secfile_insert_bool(saving->file, FALSE, "%s.orders_vigilant", buf);
6341 secfile_insert_str(saving->file, "-", "%s.orders_list", buf);
6342 secfile_insert_str(saving->file, "-", "%s.dir_list", buf);
6343 secfile_insert_str(saving->file, "-", "%s.activity_list", buf);
6344 secfile_insert_str(saving->file, "-", "%s.tgt_list", buf);
6347 i++;
6348 } unit_list_iterate_end;
6351 /****************************************************************************
6352 Load player (client) attributes data
6353 ****************************************************************************/
6354 static void sg_load_player_attributes(struct loaddata *loading,
6355 struct player *plr)
6357 int plrno = player_number(plr);
6359 /* Check status and return if not OK (sg_success != TRUE). */
6360 sg_check_ret();
6362 /* Toss any existing attribute_block (should not exist) */
6363 if (plr->attribute_block.data) {
6364 free(plr->attribute_block.data);
6365 plr->attribute_block.data = NULL;
6368 /* This is a big heap of opaque data for the client, check everything! */
6369 plr->attribute_block.length = secfile_lookup_int_default(
6370 loading->file, 0, "player%d.attribute_v2_block_length", plrno);
6372 if (0 > plr->attribute_block.length) {
6373 log_sg("player%d.attribute_v2_block_length=%d too small", plrno,
6374 plr->attribute_block.length);
6375 plr->attribute_block.length = 0;
6376 } else if (MAX_ATTRIBUTE_BLOCK < plr->attribute_block.length) {
6377 log_sg("player%d.attribute_v2_block_length=%d too big (max %d)",
6378 plrno, plr->attribute_block.length, MAX_ATTRIBUTE_BLOCK);
6379 plr->attribute_block.length = 0;
6380 } else if (0 < plr->attribute_block.length) {
6381 int part_nr, parts;
6382 size_t actual_length;
6383 int quoted_length;
6384 char *quoted;
6386 sg_failure_ret(
6387 secfile_lookup_int(loading->file, &quoted_length,
6388 "player%d.attribute_v2_block_length_quoted",
6389 plrno), "%s", secfile_error());
6390 sg_failure_ret(
6391 secfile_lookup_int(loading->file, &parts,
6392 "player%d.attribute_v2_block_parts", plrno),
6393 "%s", secfile_error());
6395 quoted = fc_malloc(quoted_length + 1);
6396 quoted[0] = '\0';
6397 plr->attribute_block.data = fc_malloc(plr->attribute_block.length);
6398 for (part_nr = 0; part_nr < parts; part_nr++) {
6399 const char *current =
6400 secfile_lookup_str(loading->file,
6401 "player%d.attribute_v2_block_data.part%d",
6402 plrno, part_nr);
6403 if (!current) {
6404 log_sg("attribute_v2_block_parts=%d actual=%d", parts, part_nr);
6405 break;
6407 log_debug("attribute_v2_block_length_quoted=%lu have=%lu part=%lu",
6408 (unsigned long) quoted_length,
6409 (unsigned long) strlen(quoted),
6410 (unsigned long) strlen(current));
6411 fc_assert(strlen(quoted) + strlen(current) <= quoted_length);
6412 strcat(quoted, current);
6414 fc_assert_msg(quoted_length == strlen(quoted),
6415 "attribute_v2_block_length_quoted=%lu actual=%lu",
6416 (unsigned long) quoted_length,
6417 (unsigned long) strlen(quoted));
6419 actual_length =
6420 unquote_block(quoted,
6421 plr->attribute_block.data,
6422 plr->attribute_block.length);
6423 fc_assert(actual_length == plr->attribute_block.length);
6424 free(quoted);
6428 /****************************************************************************
6429 Save player (client) attributes data.
6430 ****************************************************************************/
6431 static void sg_save_player_attributes(struct savedata *saving,
6432 struct player *plr)
6434 int plrno = player_number(plr);
6436 /* Check status and return if not OK (sg_success != TRUE). */
6437 sg_check_ret();
6439 /* This is a big heap of opaque data from the client. Although the binary
6440 * format is not user editable, keep the lines short enough for debugging,
6441 * and hope that data compression will keep the file a reasonable size.
6442 * Note that the "quoted" format is a multiple of 3.
6444 #define PART_SIZE (3*256)
6445 #define PART_ADJUST (3)
6446 if (plr->attribute_block.data) {
6447 char part[PART_SIZE + PART_ADJUST];
6448 int parts;
6449 int current_part_nr;
6450 char *quoted = quote_block(plr->attribute_block.data,
6451 plr->attribute_block.length);
6452 char *quoted_at = strchr(quoted, ':');
6453 size_t bytes_left = strlen(quoted);
6454 size_t bytes_at_colon = 1 + (quoted_at - quoted);
6455 size_t bytes_adjust = bytes_at_colon % PART_ADJUST;
6457 secfile_insert_int(saving->file, plr->attribute_block.length,
6458 "player%d.attribute_v2_block_length", plrno);
6459 secfile_insert_int(saving->file, bytes_left,
6460 "player%d.attribute_v2_block_length_quoted", plrno);
6462 /* Try to wring some compression efficiencies out of the "quoted" format.
6463 * The first line has a variable length decimal, mis-aligning triples.
6465 if ((bytes_left - bytes_adjust) > PART_SIZE) {
6466 /* first line can be longer */
6467 parts = 1 + (bytes_left - bytes_adjust - 1) / PART_SIZE;
6468 } else {
6469 parts = 1;
6472 secfile_insert_int(saving->file, parts,
6473 "player%d.attribute_v2_block_parts", plrno);
6475 if (parts > 1) {
6476 size_t size_of_current_part = PART_SIZE + bytes_adjust;
6478 /* first line can be longer */
6479 memcpy(part, quoted, size_of_current_part);
6480 part[size_of_current_part] = '\0';
6481 secfile_insert_str(saving->file, part,
6482 "player%d.attribute_v2_block_data.part%d",
6483 plrno, 0);
6484 bytes_left -= size_of_current_part;
6485 quoted_at = &quoted[size_of_current_part];
6486 current_part_nr = 1;
6487 } else {
6488 quoted_at = quoted;
6489 current_part_nr = 0;
6492 for (; current_part_nr < parts; current_part_nr++) {
6493 size_t size_of_current_part = MIN(bytes_left, PART_SIZE);
6495 memcpy(part, quoted_at, size_of_current_part);
6496 part[size_of_current_part] = '\0';
6497 secfile_insert_str(saving->file, part,
6498 "player%d.attribute_v2_block_data.part%d",
6499 plrno,
6500 current_part_nr);
6501 bytes_left -= size_of_current_part;
6502 quoted_at = &quoted_at[size_of_current_part];
6504 fc_assert(bytes_left == 0);
6505 free(quoted);
6507 #undef PART_ADJUST
6508 #undef PART_SIZE
6511 /****************************************************************************
6512 Load vision data
6513 ****************************************************************************/
6514 static void sg_load_player_vision(struct loaddata *loading,
6515 struct player *plr)
6517 int plrno = player_number(plr);
6518 int total_ncities =
6519 secfile_lookup_int_default(loading->file, -1,
6520 "player%d.dc_total", plrno);
6521 int i;
6523 /* Check status and return if not OK (sg_success != TRUE). */
6524 sg_check_ret();
6526 if (!plr->is_alive) {
6527 if (game.server.revealmap & REVEAL_MAP_DEAD
6528 && player_list_size(team_members(plr->team)) == 1) {
6529 /* Reveal all for dead players. */
6530 map_know_and_see_all(plr);
6534 if (!plr->is_alive
6535 || -1 == total_ncities
6536 || FALSE == game.info.fogofwar
6537 || !secfile_lookup_bool_default(loading->file, TRUE,
6538 "game.save_private_map")) {
6539 /* We have:
6540 * - a dead player;
6541 * - fogged cities are not saved for any reason;
6542 * - a savegame with fog of war turned off;
6543 * - or game.save_private_map is not set to FALSE in the scenario /
6544 * savegame. The players private knowledge is set to be what he could
6545 * see without fog of war. */
6546 whole_map_iterate(ptile) {
6547 if (map_is_known(ptile, plr)) {
6548 struct city *pcity = tile_city(ptile);
6550 update_player_tile_last_seen(plr, ptile);
6551 update_player_tile_knowledge(plr, ptile);
6553 if (NULL != pcity) {
6554 update_dumb_city(plr, pcity);
6557 } whole_map_iterate_end;
6559 /* Nothing more to do; */
6560 return;
6563 /* Load player map (terrain). */
6564 LOAD_MAP_CHAR(ch, ptile,
6565 map_get_player_tile(ptile, plr)->terrain
6566 = char2terrain(ch), loading->file,
6567 "player%d.map_t%04d", plrno);
6569 /* Load player map (resources). */
6570 LOAD_MAP_CHAR(ch, ptile,
6571 map_get_player_tile(ptile, plr)->resource
6572 = char2resource(ch), loading->file,
6573 "player%d.map_res%04d", plrno);
6575 if (loading->version >= 30) {
6576 /* 2.6.0 or newer */
6578 /* Load player map (extras). */
6579 halfbyte_iterate_extras(j, loading->extra.size) {
6580 LOAD_MAP_CHAR(ch, ptile,
6581 sg_extras_set(&map_get_player_tile(ptile, plr)->extras,
6582 ch, loading->extra.order + 4 * j),
6583 loading->file, "player%d.map_e%02d_%04d", plrno, j);
6584 } halfbyte_iterate_extras_end;
6585 } else {
6586 /* Load player map (specials). */
6587 halfbyte_iterate_special(j, loading->special.size) {
6588 LOAD_MAP_CHAR(ch, ptile,
6589 sg_special_set(ptile, &map_get_player_tile(ptile, plr)->extras,
6590 ch, loading->special.order + 4 * j, FALSE),
6591 loading->file, "player%d.map_spe%02d_%04d", plrno, j);
6592 } halfbyte_iterate_special_end;
6594 /* Load player map (bases). */
6595 halfbyte_iterate_bases(j, loading->base.size) {
6596 LOAD_MAP_CHAR(ch, ptile,
6597 sg_bases_set(&map_get_player_tile(ptile, plr)->extras,
6598 ch, loading->base.order + 4 * j),
6599 loading->file, "player%d.map_b%02d_%04d", plrno, j);
6600 } halfbyte_iterate_bases_end;
6602 /* Load player map (roads). */
6603 if (loading->version >= 20) {
6604 /* 2.5.0 or newer */
6605 halfbyte_iterate_roads(j, loading->road.size) {
6606 LOAD_MAP_CHAR(ch, ptile,
6607 sg_roads_set(&map_get_player_tile(ptile, plr)->extras,
6608 ch, loading->road.order + 4 * j),
6609 loading->file, "player%d.map_r%02d_%04d", plrno, j);
6610 } halfbyte_iterate_roads_end;
6614 if (game.server.foggedborders) {
6615 /* Load player map (border). */
6616 int x, y;
6618 for (y = 0; y < game.map.ysize; y++) {
6619 const char *buffer
6620 = secfile_lookup_str(loading->file, "player%d.map_owner%04d",
6621 plrno, y);
6622 const char *buffer2
6623 = secfile_lookup_str(loading->file, "player%d.extras_owner%04d",
6624 plrno, y);
6625 const char *ptr = buffer;
6626 const char *ptr2 = buffer2;
6628 sg_failure_ret(NULL != buffer,
6629 "Savegame corrupt - map line %d not found.", y);
6630 for (x = 0; x < game.map.xsize; x++) {
6631 char token[TOKEN_SIZE];
6632 char token2[TOKEN_SIZE];
6633 int number;
6634 struct tile *ptile = native_pos_to_tile(x, y);
6636 scanin(&ptr, ",", token, sizeof(token));
6637 sg_failure_ret('\0' != token[0],
6638 "Savegame corrupt - map size not correct.");
6639 if (strcmp(token, "-") == 0) {
6640 map_get_player_tile(ptile, plr)->owner = NULL;
6641 } else {
6642 sg_failure_ret(str_to_int(token, &number),
6643 "Savegame corrupt - got tile owner=%s in (%d, %d).",
6644 token, x, y);
6645 map_get_player_tile(ptile, plr)->owner = player_by_number(number);
6648 if (loading->version >= 30) {
6649 scanin(&ptr2, ",", token2, sizeof(token2));
6650 sg_failure_ret('\0' != token2[0],
6651 "Savegame corrupt - map size not correct.");
6652 if (strcmp(token2, "-") == 0) {
6653 map_get_player_tile(ptile, plr)->extras_owner = NULL;
6654 } else {
6655 sg_failure_ret(str_to_int(token2, &number),
6656 "Savegame corrupt - got extras owner=%s in (%d, %d).",
6657 token, x, y);
6658 map_get_player_tile(ptile, plr)->extras_owner = player_by_number(number);
6660 } else {
6661 map_get_player_tile(ptile, plr)->extras_owner
6662 = map_get_player_tile(ptile, plr)->owner;
6668 /* Load player map (update time). */
6669 for (i = 0; i < 4; i++) {
6670 /* put 4-bit segments of 16-bit "updated" field */
6671 if (i == 0) {
6672 LOAD_MAP_CHAR(ch, ptile,
6673 map_get_player_tile(ptile, plr)->last_updated
6674 = ascii_hex2bin(ch, i),
6675 loading->file, "player%d.map_u%02d_%04d", plrno, i);
6676 } else {
6677 LOAD_MAP_CHAR(ch, ptile,
6678 map_get_player_tile(ptile, plr)->last_updated
6679 |= ascii_hex2bin(ch, i),
6680 loading->file, "player%d.map_u%02d_%04d", plrno, i);
6684 /* Load player map known cities. */
6685 for (i = 0; i < total_ncities; i++) {
6686 struct vision_site *pdcity;
6687 char buf[32];
6688 fc_snprintf(buf, sizeof(buf), "player%d.dc%d", plrno, i);
6690 pdcity = vision_site_new(0, NULL, NULL);
6691 if (sg_load_player_vision_city(loading, plr, pdcity, buf)) {
6692 change_playertile_site(map_get_player_tile(pdcity->location, plr),
6693 pdcity);
6694 identity_number_reserve(pdcity->identity);
6695 } else {
6696 /* Error loading the data. */
6697 log_sg("Skipping seen city %d for player %d.", i, plrno);
6698 if (pdcity != NULL) {
6699 vision_site_destroy(pdcity);
6704 /* Repair inconsistent player maps. */
6705 whole_map_iterate(ptile) {
6706 if (map_is_known_and_seen(ptile, plr, V_MAIN)) {
6707 struct city *pcity = tile_city(ptile);
6709 update_player_tile_knowledge(plr, ptile);
6710 reality_check_city(plr, ptile);
6712 if (NULL != pcity) {
6713 update_dumb_city(plr, pcity);
6716 } whole_map_iterate_end;
6719 /****************************************************************************
6720 Load data for one seen city. sg_save_player_vision_city() is not defined.
6721 ****************************************************************************/
6722 static bool sg_load_player_vision_city(struct loaddata *loading,
6723 struct player *plr,
6724 struct vision_site *pdcity,
6725 const char *citystr)
6727 const char *string;
6728 int i, id, size;
6729 citizens city_size;
6730 int nat_x, nat_y;
6731 const char *stylename;
6733 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_x, "%s.x",
6734 citystr),
6735 FALSE, "%s", secfile_error());
6736 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_y, "%s.y",
6737 citystr),
6738 FALSE, "%s", secfile_error());
6739 pdcity->location = native_pos_to_tile(nat_x, nat_y);
6740 sg_warn_ret_val(NULL != pdcity->location, FALSE,
6741 "%s invalid tile (%d,%d)", citystr, nat_x, nat_y);
6743 sg_warn_ret_val(secfile_lookup_int(loading->file, &id, "%s.owner",
6744 citystr),
6745 FALSE, "%s", secfile_error());
6746 pdcity->owner = player_by_number(id);
6747 sg_warn_ret_val(NULL != pdcity->owner, FALSE,
6748 "%s has invalid owner (%d); skipping.", citystr, id);
6750 sg_warn_ret_val(secfile_lookup_int(loading->file, &pdcity->identity,
6751 "%s.id", citystr),
6752 FALSE, "%s", secfile_error());
6753 sg_warn_ret_val(IDENTITY_NUMBER_ZERO < pdcity->identity, FALSE,
6754 "%s has invalid id (%d); skipping.", citystr, id);
6756 sg_warn_ret_val(secfile_lookup_int(loading->file, &size,
6757 "%s.size", citystr),
6758 FALSE, "%s", secfile_error());
6759 city_size = (citizens)size; /* set the correct type */
6760 sg_warn_ret_val(size == (int)city_size, FALSE,
6761 "Invalid city size: %d; set to %d.", size, city_size);
6762 vision_site_size_set(pdcity, city_size);
6764 /* Initialise list of improvements */
6765 BV_CLR_ALL(pdcity->improvements);
6766 string = secfile_lookup_str(loading->file, "%s.improvements", citystr);
6767 sg_warn_ret_val(string != NULL, FALSE, "%s", secfile_error());
6768 sg_warn_ret_val(strlen(string) == loading->improvement.size, FALSE,
6769 "Invalid length of '%s.improvements' (%lu ~= %lu).",
6770 citystr, (unsigned long) strlen(string),
6771 (unsigned long) loading->improvement.size);
6772 for (i = 0; i < loading->improvement.size; i++) {
6773 sg_warn_ret_val(string[i] == '1' || string[i] == '0', FALSE,
6774 "Undefined value '%c' within '%s.improvements'.",
6775 string[i], citystr)
6777 if (string[i] == '1') {
6778 struct impr_type *pimprove =
6779 improvement_by_rule_name(loading->improvement.order[i]);
6780 if (pimprove) {
6781 BV_SET(pdcity->improvements, improvement_index(pimprove));
6786 /* Use the section as backup name. */
6787 sz_strlcpy(pdcity->name, secfile_lookup_str_default(loading->file, citystr,
6788 "%s.name", citystr));
6790 pdcity->occupied = secfile_lookup_bool_default(loading->file, FALSE,
6791 "%s.occupied", citystr);
6792 pdcity->walls = secfile_lookup_bool_default(loading->file, FALSE,
6793 "%s.walls", citystr);
6794 pdcity->happy = secfile_lookup_bool_default(loading->file, FALSE,
6795 "%s.happy", citystr);
6796 pdcity->unhappy = secfile_lookup_bool_default(loading->file, FALSE,
6797 "%s.unhappy", citystr);
6798 stylename = secfile_lookup_str_default(loading->file, NULL,
6799 "%s.style", citystr);
6800 if (stylename != NULL) {
6801 pdcity->style = city_style_by_rule_name(stylename);
6802 } else {
6803 pdcity->style = 0;
6805 if (pdcity->style < 0) {
6806 pdcity->style = 0;
6809 pdcity->city_image = secfile_lookup_int_default(loading->file, -100,
6810 "%s.city_image", citystr);
6812 return TRUE;
6815 /****************************************************************************
6816 Save vision data
6817 ****************************************************************************/
6818 static void sg_save_player_vision(struct savedata *saving,
6819 struct player *plr)
6821 int i, plrno = player_number(plr);
6823 /* Check status and return if not OK (sg_success != TRUE). */
6824 sg_check_ret();
6826 if (!game.info.fogofwar || !game.server.save_options.save_private_map) {
6827 /* The player can see all, there's no reason to save the private map. */
6828 return;
6831 if (!plr->is_alive) {
6832 /* Nothing to save. */
6833 return;
6836 /* Save the map (terrain). */
6837 SAVE_MAP_CHAR(ptile,
6838 terrain2char(map_get_player_tile(ptile, plr)->terrain),
6839 saving->file, "player%d.map_t%04d", plrno);
6841 /* Save the map (resources). */
6842 SAVE_MAP_CHAR(ptile,
6843 resource2char(map_get_player_tile(ptile, plr)->resource),
6844 saving->file, "player%d.map_res%04d", plrno);
6846 if (game.server.foggedborders) {
6847 /* Save the map (borders). */
6848 int x, y;
6850 for (y = 0; y < game.map.ysize; y++) {
6851 char line[game.map.xsize * TOKEN_SIZE];
6853 line[0] = '\0';
6854 for (x = 0; x < game.map.xsize; x++) {
6855 char token[TOKEN_SIZE];
6856 struct tile *ptile = native_pos_to_tile(x, y);
6857 struct player_tile *plrtile = map_get_player_tile(ptile, plr);
6859 if (plrtile == NULL || plrtile->owner == NULL) {
6860 strcpy(token, "-");
6861 } else {
6862 fc_snprintf(token, sizeof(token), "%d",
6863 player_number(plrtile->owner));
6865 strcat(line, token);
6866 if (x < game.map.xsize) {
6867 strcat(line, ",");
6870 secfile_insert_str(saving->file, line, "player%d.map_owner%04d",
6871 plrno, y);
6874 for (y = 0; y < game.map.ysize; y++) {
6875 char line[game.map.xsize * TOKEN_SIZE];
6877 line[0] = '\0';
6878 for (x = 0; x < game.map.xsize; x++) {
6879 char token[TOKEN_SIZE];
6880 struct tile *ptile = native_pos_to_tile(x, y);
6881 struct player_tile *plrtile = map_get_player_tile(ptile, plr);
6883 if (plrtile == NULL || plrtile->extras_owner == NULL) {
6884 strcpy(token, "-");
6885 } else {
6886 fc_snprintf(token, sizeof(token), "%d",
6887 player_number(plrtile->extras_owner));
6889 strcat(line, token);
6890 if (x < game.map.xsize) {
6891 strcat(line, ",");
6894 secfile_insert_str(saving->file, line, "player%d.extras_owner%04d",
6895 plrno, y);
6899 /* Save the map (extras). */
6900 halfbyte_iterate_extras(j, game.control.num_extra_types) {
6901 int mod[4];
6902 int l;
6904 for (l = 0; l < 4; l++) {
6905 if (4 * j + 1 > game.control.num_extra_types) {
6906 mod[l] = -1;
6907 } else {
6908 mod[l] = 4 * j + l;
6912 SAVE_MAP_CHAR(ptile,
6913 sg_extras_get(map_get_player_tile(ptile, plr)->extras, mod),
6914 saving->file, "player%d.map_e%02d_%04d", plrno, j);
6915 } halfbyte_iterate_extras_end;
6917 /* Save the map (update time). */
6918 for (i = 0; i < 4; i++) {
6919 /* put 4-bit segments of 16-bit "updated" field */
6920 SAVE_MAP_CHAR(ptile,
6921 bin2ascii_hex(
6922 map_get_player_tile(ptile, plr)->last_updated, i),
6923 saving->file, "player%d.map_u%02d_%04d", plrno, i);
6926 /* Save known cities. */
6927 i = 0;
6928 whole_map_iterate(ptile) {
6929 struct vision_site *pdcity = map_get_player_city(ptile, plr);
6930 char impr_buf[MAX_NUM_ITEMS + 1];
6931 char buf[32];
6933 fc_snprintf(buf, sizeof(buf), "player%d.dc%d", plrno, i);
6935 if (NULL != pdcity && plr != vision_site_owner(pdcity)) {
6936 int nat_x, nat_y;
6938 index_to_native_pos(&nat_x, &nat_y, tile_index(ptile));
6939 secfile_insert_int(saving->file, nat_y, "%s.y", buf);
6940 secfile_insert_int(saving->file, nat_x, "%s.x", buf);
6942 secfile_insert_int(saving->file, pdcity->identity, "%s.id", buf);
6943 secfile_insert_int(saving->file, player_number(vision_site_owner(pdcity)),
6944 "%s.owner", buf);
6946 secfile_insert_int(saving->file, vision_site_size_get(pdcity),
6947 "%s.size", buf);
6948 secfile_insert_bool(saving->file, pdcity->occupied,
6949 "%s.occupied", buf);
6950 secfile_insert_bool(saving->file, pdcity->walls, "%s.walls", buf);
6951 secfile_insert_bool(saving->file, pdcity->happy, "%s.happy", buf);
6952 secfile_insert_bool(saving->file, pdcity->unhappy, "%s.unhappy", buf);
6953 secfile_insert_str(saving->file, city_style_rule_name(pdcity->style),
6954 "%s.style", buf);
6955 secfile_insert_int(saving->file, pdcity->city_image, "%s.city_image", buf);
6957 /* Save improvement list as bitvector. Note that improvement order
6958 * is saved in savefile.improvement.order. */
6959 improvement_iterate(pimprove) {
6960 impr_buf[improvement_index(pimprove)]
6961 = BV_ISSET(pdcity->improvements, improvement_index(pimprove))
6962 ? '1' : '0';
6963 } improvement_iterate_end;
6964 impr_buf[improvement_count()] = '\0';
6965 sg_failure_ret(strlen(impr_buf) < sizeof(impr_buf),
6966 "Invalid size of the improvement vector (%s.improvements: "
6967 "%lu < %lu).", buf, (long unsigned int) strlen(impr_buf),
6968 (long unsigned int) sizeof(impr_buf));
6969 secfile_insert_str(saving->file, impr_buf, "%s.improvements", buf);
6970 secfile_insert_str(saving->file, pdcity->name, "%s.name", buf);
6972 i++;
6974 } whole_map_iterate_end;
6976 secfile_insert_int(saving->file, i, "player%d.dc_total", plrno);
6979 /* =======================================================================
6980 * Load / save the researches.
6981 * ======================================================================= */
6983 /****************************************************************************
6984 Load '[research]'.
6985 ****************************************************************************/
6986 static void sg_load_researches(struct loaddata *loading)
6988 struct research *presearch;
6989 int count;
6990 int number;
6991 const char *string;
6992 int i, j;
6994 /* Check status and return if not OK (sg_success != TRUE). */
6995 sg_check_ret();
6997 /* Initialize all researches. */
6998 researches_iterate(pinitres) {
6999 init_tech(pinitres, FALSE);
7000 } researches_iterate_end;
7002 /* May be unsaved (e.g. scenario case). */
7003 count = secfile_lookup_int_default(loading->file, 0, "research.count");
7004 for (i = 0; i < count; i++) {
7005 sg_failure_ret(secfile_lookup_int(loading->file, &number,
7006 "research.r%d.number", i),
7007 "%s", secfile_error());
7008 presearch = research_by_number(number);
7009 sg_failure_ret(presearch != NULL,
7010 "Invalid research number %d in 'research.r%d.number'",
7011 number, i);
7013 presearch->tech_goal = technology_load(loading->file,
7014 "research.r%d.goal", i);
7015 sg_failure_ret(secfile_lookup_int(loading->file,
7016 &presearch->techs_researched,
7017 "research.r%d.techs", i),
7018 "%s", secfile_error());
7019 sg_failure_ret(secfile_lookup_int(loading->file,
7020 &presearch->future_tech,
7021 "research.r%d.futuretech", i),
7022 "%s", secfile_error());
7023 sg_failure_ret(secfile_lookup_int(loading->file,
7024 &presearch->bulbs_researched,
7025 "research.r%d.bulbs", i),
7026 "%s", secfile_error());
7027 sg_failure_ret(secfile_lookup_int(loading->file,
7028 &presearch->bulbs_researching_saved,
7029 "research.r%d.bulbs_before", i),
7030 "%s", secfile_error());
7031 presearch->researching_saved = technology_load(loading->file,
7032 "research.r%d.saved", i);
7033 presearch->researching = technology_load(loading->file,
7034 "research.r%d.now", i);
7035 sg_failure_ret(secfile_lookup_bool(loading->file,
7036 &presearch->got_tech,
7037 "research.r%d.got_tech", i),
7038 "%s", secfile_error());
7040 string = secfile_lookup_str(loading->file, "research.r%d.done",
7042 sg_failure_ret(string != NULL, "%s", secfile_error());
7043 sg_failure_ret(strlen(string) == loading->technology.size,
7044 "Invalid length of 'research.r%d.done' (%lu ~= %lu).",
7045 i, (unsigned long) strlen(string),
7046 (unsigned long) loading->technology.size);
7047 for (j = 0; j < loading->technology.size; j++) {
7048 sg_failure_ret(string[j] == '1' || string[j] == '0',
7049 "Undefined value '%c' within 'research.r%d.done'.",
7050 string[j], i);
7052 if (string[j] == '1') {
7053 struct advance *padvance =
7054 advance_by_rule_name(loading->technology.order[j]);
7056 if (padvance) {
7057 research_invention_set(presearch, advance_number(padvance),
7058 TECH_KNOWN);
7064 /* In case of tech_leakage, we can update research only after all the
7065 * researches have been loaded */
7066 researches_iterate(pupres) {
7067 research_update(pupres);
7068 } researches_iterate_end;
7071 /****************************************************************************
7072 Save '[research]'.
7073 ****************************************************************************/
7074 static void sg_save_researches(struct savedata *saving)
7076 char invs[A_LAST];
7077 int i = 0;
7079 /* Check status and return if not OK (sg_success != TRUE). */
7080 sg_check_ret();
7082 if (saving->save_players) {
7083 researches_iterate(presearch) {
7084 secfile_insert_int(saving->file, research_number(presearch),
7085 "research.r%d.number", i);
7086 technology_save(saving->file, "research.r%d.goal",
7087 i, presearch->tech_goal);
7088 secfile_insert_int(saving->file, presearch->techs_researched,
7089 "research.r%d.techs", i);
7090 secfile_insert_int(saving->file, presearch->future_tech,
7091 "research.r%d.futuretech", i);
7092 secfile_insert_int(saving->file, presearch->bulbs_researching_saved,
7093 "research.r%d.bulbs_before", i);
7094 technology_save(saving->file, "research.r%d.saved",
7095 i, presearch->researching_saved);
7096 secfile_insert_int(saving->file, presearch->bulbs_researched,
7097 "research.r%d.bulbs", i);
7098 technology_save(saving->file, "research.r%d.now",
7099 i, presearch->researching);
7100 secfile_insert_bool(saving->file, presearch->got_tech,
7101 "research.r%d.got_tech", i);
7102 /* Save technology lists as bytevector. Note that technology order is
7103 * saved in savefile.technology.order */
7104 advance_index_iterate(A_NONE, tech_id) {
7105 invs[tech_id] = (research_invention_state(presearch, tech_id)
7106 == TECH_KNOWN ? '1' : '0');
7107 } advance_index_iterate_end;
7108 invs[game.control.num_tech_types] = '\0';
7109 secfile_insert_str(saving->file, invs, "research.r%d.done", i);
7110 i++;
7111 } researches_iterate_end;
7112 secfile_insert_int(saving->file, i, "research.count");
7116 /* =======================================================================
7117 * Load / save the event cache. Should be the last thing to do.
7118 * ======================================================================= */
7120 /****************************************************************************
7121 Load '[event_cache]'.
7122 ****************************************************************************/
7123 static void sg_load_event_cache(struct loaddata *loading)
7125 /* Check status and return if not OK (sg_success != TRUE). */
7126 sg_check_ret();
7128 event_cache_load(loading->file, "event_cache");
7131 /****************************************************************************
7132 Save '[event_cache]'.
7133 ****************************************************************************/
7134 static void sg_save_event_cache(struct savedata *saving)
7136 /* Check status and return if not OK (sg_success != TRUE). */
7137 sg_check_ret();
7139 if (saving->scenario) {
7140 /* Do _not_ save events in a scenario. */
7141 return;
7144 event_cache_save(saving->file, "event_cache");
7147 /* =======================================================================
7148 * Load / save the open treaties
7149 * ======================================================================= */
7151 /****************************************************************************
7152 Load '[treaty_xxx]'.
7153 ****************************************************************************/
7154 static void sg_load_treaties(struct loaddata *loading)
7156 int tidx;
7157 const char *plr0;
7158 struct treaty_list *treaties = get_all_treaties();
7160 for (tidx = 0; (plr0 = secfile_lookup_str_default(loading->file, NULL,
7161 "treaty%d.plr0", tidx)) != NULL ;
7162 tidx++) {
7163 const char *plr1;
7164 const char *ct;
7165 int cidx;
7166 struct player *p0, *p1;
7168 plr1 = secfile_lookup_str(loading->file, "treaty%d.plr1", tidx);
7170 p0 = player_by_name(plr0);
7171 p1 = player_by_name(plr1);
7173 if (p0 == NULL || p1 == NULL) {
7174 log_error("Treaty between unknown players %s and %s", plr0, plr1);
7175 } else {
7176 struct Treaty *ptreaty = fc_malloc(sizeof(*ptreaty));
7178 init_treaty(ptreaty, p0, p1);
7179 treaty_list_prepend(treaties, ptreaty);
7181 for (cidx = 0; (ct = secfile_lookup_str_default(loading->file, NULL,
7182 "treaty%d.clause%d.type",
7183 tidx, cidx)) != NULL ;
7184 cidx++ ) {
7185 enum clause_type type = clause_type_by_name(ct, fc_strcasecmp);
7186 const char *plrx;
7188 if (!clause_type_is_valid(type)) {
7189 log_error("Invalid clause type \"%s\"", ct);
7190 } else {
7191 struct player *pgiver = NULL;
7193 plrx = secfile_lookup_str(loading->file, "treaty%d.clause%d.from",
7194 tidx, cidx);
7196 if (!fc_strcasecmp(plrx, plr0)) {
7197 pgiver = p0;
7198 } else if (!fc_strcasecmp(plrx, plr1)) {
7199 pgiver = p1;
7200 } else {
7201 log_error("Clause giver %s is not participant of the treaty"
7202 "between %s and %s", plrx, plr0, plr1);
7205 if (pgiver != NULL) {
7206 int value;
7208 value = secfile_lookup_int_default(loading->file, 0,
7209 "treaty%d.clause%d.value",
7210 tidx, cidx);
7212 add_clause(ptreaty, pgiver, type, value);
7216 /* These must be after clauses have been added so that acceptance
7217 * does not get cleared by what seems like changes to the treaty. */
7218 ptreaty->accept0 = secfile_lookup_bool_default(loading->file, FALSE,
7219 "treaty%d.accept0", tidx);
7220 ptreaty->accept1 = secfile_lookup_bool_default(loading->file, FALSE,
7221 "treaty%d.accept1", tidx);
7227 /****************************************************************************
7228 Save '[treaty_xxx]'.
7229 ****************************************************************************/
7230 static void sg_save_treaties(struct savedata *saving)
7232 struct treaty_list *treaties = get_all_treaties();
7233 int tidx = 0;
7235 treaty_list_iterate(treaties, ptr) {
7236 char tpath[512];
7237 int cidx = 0;
7239 fc_snprintf(tpath, sizeof(tpath), "treaty%d", tidx++);
7241 secfile_insert_str(saving->file, player_name(ptr->plr0), "%s.plr0", tpath);
7242 secfile_insert_str(saving->file, player_name(ptr->plr1), "%s.plr1", tpath);
7243 secfile_insert_bool(saving->file, ptr->accept0, "%s.accept0", tpath);
7244 secfile_insert_bool(saving->file, ptr->accept1, "%s.accept1", tpath);
7246 clause_list_iterate(ptr->clauses, pclaus) {
7247 char cpath[512];
7249 fc_snprintf(cpath, sizeof(cpath), "%s.clause%d", tpath, cidx++);
7251 secfile_insert_str(saving->file, clause_type_name(pclaus->type), "%s.type", cpath);
7252 secfile_insert_str(saving->file, player_name(pclaus->from), "%s.from", cpath);
7253 secfile_insert_int(saving->file, pclaus->value, "%s.value", cpath);
7254 } clause_list_iterate_end;
7255 } treaty_list_iterate_end;
7258 /* =======================================================================
7259 * Load / save the history report
7260 * ======================================================================= */
7262 /****************************************************************************
7263 Load '[history]'.
7264 ****************************************************************************/
7265 static void sg_load_history(struct loaddata *loading)
7267 struct history_report *hist = history_report_get();
7268 int turn;
7270 turn = secfile_lookup_int_default(loading->file, -2, "history.turn");
7272 if (turn + 1 >= game.info.turn) {
7273 const char *str;
7275 hist->turn = turn;
7276 str = secfile_lookup_str(loading->file, "history.title");
7277 sg_failure_ret(str != NULL, "%s", secfile_error());
7278 strncpy(hist->title, str, REPORT_TITLESIZE);
7279 str = secfile_lookup_str(loading->file, "history.body");
7280 sg_failure_ret(str != NULL, "%s", secfile_error());
7281 strncpy(hist->body, str, REPORT_BODYSIZE);
7285 /****************************************************************************
7286 Save '[history]'.
7287 ****************************************************************************/
7288 static void sg_save_history(struct savedata *saving)
7290 struct history_report *hist = history_report_get();
7292 secfile_insert_int(saving->file, hist->turn, "history.turn");
7294 if (hist->turn + 1 >= game.info.turn) {
7295 secfile_insert_str(saving->file, hist->title, "history.title");
7296 secfile_insert_str(saving->file, hist->body, "history.body");
7300 /* =======================================================================
7301 * Load / save the mapimg definitions.
7302 * ======================================================================= */
7304 /****************************************************************************
7305 Load '[mapimg]'.
7306 ****************************************************************************/
7307 static void sg_load_mapimg(struct loaddata *loading)
7309 int mapdef_count, i;
7311 /* Check status and return if not OK (sg_success != TRUE). */
7312 sg_check_ret();
7314 /* Clear all defined map images. */
7315 while (mapimg_count() > 0) {
7316 mapimg_delete(0);
7319 mapdef_count = secfile_lookup_int_default(loading->file, 0,
7320 "mapimg.count");
7321 log_verbose("Saved map image definitions: %d.", mapdef_count);
7323 if (0 >= mapdef_count) {
7324 return;
7327 for (i = 0; i < mapdef_count; i++) {
7328 const char *p;
7330 p = secfile_lookup_str(loading->file, "mapimg.mapdef%d", i);
7331 if (NULL == p) {
7332 log_verbose("[Mapimg %4d] Missing definition.", i);
7333 continue;
7336 if (!mapimg_define(p, FALSE)) {
7337 log_error("Invalid map image definition %4d: %s.", i, p);
7340 log_verbose("Mapimg %4d loaded.", i);
7344 /****************************************************************************
7345 Save '[mapimg]'.
7346 ****************************************************************************/
7347 static void sg_save_mapimg(struct savedata *saving)
7349 /* Check status and return if not OK (sg_success != TRUE). */
7350 sg_check_ret();
7352 secfile_insert_int(saving->file, mapimg_count(), "mapimg.count");
7353 if (mapimg_count() > 0) {
7354 int i;
7356 for (i = 0; i < mapimg_count(); i++) {
7357 char buf[MAX_LEN_MAPDEF];
7359 mapimg_id2str(i, buf, sizeof(buf));
7360 secfile_insert_str(saving->file, buf, "mapimg.mapdef%d", i);
7365 /* =======================================================================
7366 * Sanity checks for loading / saving a game.
7367 * ======================================================================= */
7369 /****************************************************************************
7370 Sanity check for loaded game.
7371 ****************************************************************************/
7372 static void sg_load_sanitycheck(struct loaddata *loading)
7374 int players;
7376 /* Check status and return if not OK (sg_success != TRUE). */
7377 sg_check_ret();
7379 if (game.info.is_new_game) {
7380 /* Nothing to do for new games (or not started scenarios). */
7381 return;
7384 /* Old savegames may have maxplayers lower than current player count,
7385 * fix. */
7386 players = normal_player_count();
7387 if (game.server.max_players < players) {
7388 log_verbose("Max players lower than current players, fixing");
7389 game.server.max_players = players;
7392 /* Fix ferrying sanity */
7393 players_iterate(pplayer) {
7394 unit_list_iterate_safe(pplayer->units, punit) {
7395 if (!unit_transport_get(punit)
7396 && !can_unit_exist_at_tile(punit, unit_tile(punit))) {
7397 log_sg("Removing %s unferried %s in %s at (%d, %d)",
7398 nation_rule_name(nation_of_player(pplayer)),
7399 unit_rule_name(punit),
7400 terrain_rule_name(unit_tile(punit)->terrain),
7401 TILE_XY(unit_tile(punit)));
7402 bounce_unit(punit, TRUE);
7404 } unit_list_iterate_safe_end;
7405 } players_iterate_end;
7407 /* Fix stacking issues. We don't rely on the savegame preserving
7408 * alliance invariants (old savegames often did not) so if there are any
7409 * unallied units on the same tile we just bounce them. */
7410 players_iterate(pplayer) {
7411 players_iterate(aplayer) {
7412 resolve_unit_stacks(pplayer, aplayer, TRUE);
7413 } players_iterate_end;
7415 /* Backward compatibility: if we had any open-ended orders (pillage)
7416 * in the savegame, assign specific targets now */
7417 unit_list_iterate(pplayer->units, punit) {
7418 unit_assign_specific_activity_target(punit,
7419 &punit->activity,
7420 &punit->activity_target);
7421 } unit_list_iterate_end;
7422 } players_iterate_end;
7424 /* Recalculate the potential buildings for each city. Has caused some
7425 * problems with game random state.
7426 * This also changes the game state if you save the game directly after
7427 * loading it and compare the results. */
7428 players_iterate(pplayer) {
7429 bool saved_ai_control = pplayer->ai_controlled;
7431 /* Recalculate for all players. */
7432 pplayer->ai_controlled = FALSE;
7434 /* Building advisor needs data phase open in order to work */
7435 adv_data_phase_init(pplayer, FALSE);
7436 building_advisor(pplayer);
7437 /* Close data phase again so it can be opened again when game starts. */
7438 adv_data_phase_done(pplayer);
7440 pplayer->ai_controlled = saved_ai_control;
7441 } players_iterate_end;
7443 /* Check worked tiles map */
7444 #ifdef DEBUG
7445 if (loading->worked_tiles != NULL) {
7446 /* check the entire map for unused worked tiles */
7447 whole_map_iterate(ptile) {
7448 if (loading->worked_tiles[ptile->index] != -1) {
7449 log_error("[city id: %d] Unused worked tile at (%d, %d).",
7450 loading->worked_tiles[ptile->index], TILE_XY(ptile));
7452 } whole_map_iterate_end;
7454 #endif /* DEBUG */
7456 /* Check researching technologies and goals. */
7457 researches_iterate(presearch) {
7458 if (presearch->researching != A_UNSET
7459 && !is_future_tech(presearch->researching)
7460 && (valid_advance_by_number(presearch->researching) == NULL
7461 || (research_invention_state(presearch, presearch->researching)
7462 != TECH_PREREQS_KNOWN))) {
7463 log_sg(_("%s had invalid researching technology."),
7464 research_name_translation(presearch));
7465 presearch->researching = A_UNSET;
7467 if (presearch->tech_goal != A_UNSET
7468 && !is_future_tech(presearch->tech_goal)
7469 && (valid_advance_by_number(presearch->researching) == NULL
7470 || !research_invention_reachable(presearch, presearch->tech_goal)
7471 || (research_invention_state(presearch, presearch->tech_goal)
7472 == TECH_KNOWN))) {
7473 log_sg(_("%s had invalid technology goal."),
7474 research_name_translation(presearch));
7475 presearch->tech_goal = A_UNSET;
7477 } researches_iterate_end;
7479 if (0 == strlen(server.game_identifier)
7480 || !is_base64url(server.game_identifier)) {
7481 /* This uses fc_rand(), so random state has to be initialized before. */
7482 randomize_base64url_string(server.game_identifier,
7483 sizeof(server.game_identifier));
7486 /* Check if some player has more than one of some UTYF_UNIQUE unit type */
7487 players_iterate(pplayer) {
7488 int unique_count[U_LAST];
7490 memset(unique_count, 0, sizeof(unique_count));
7492 unit_list_iterate(pplayer->units, punit) {
7493 unique_count[utype_index(unit_type_get(punit))]++;
7494 } unit_list_iterate_end;
7496 unit_type_iterate(ut) {
7497 if (unique_count[utype_index(ut)] > 1 && utype_has_flag(ut, UTYF_UNIQUE)) {
7498 log_sg(_("%s has multiple units of type %s though it should be possible "
7499 "to have only one."),
7500 player_name(pplayer), utype_name_translation(ut));
7502 } unit_type_iterate_end;
7503 } players_iterate_end;
7505 /* Restore game random state, just in case various initialization code
7506 * inexplicably altered the previously existing state. */
7507 if (!game.info.is_new_game) {
7508 fc_rand_set_state(loading->rstate);
7510 if (loading->version < 30) {
7511 /* For older savegames we have to recalculate the score with current data,
7512 * instead of using beginning-of-turn saved scores. */
7513 players_iterate(pplayer) {
7514 calc_civ_score(pplayer);
7515 } players_iterate_end;
7519 /* At the end do the default sanity checks. */
7520 sanity_check();
7523 /****************************************************************************
7524 Sanity check for saved game.
7525 ****************************************************************************/
7526 static void sg_save_sanitycheck(struct savedata *saving)
7528 /* Check status and return if not OK (sg_success != TRUE). */
7529 sg_check_ret();