Lower default cmdlevel to basic on game start.
[freeciv.git] / server / savegame2.c
blob39def2a9a3830ee241094e4bab2cd79a12e90c52
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(TRUE, _("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 /* Load improvements. */
1597 loading->improvement.size
1598 = secfile_lookup_int_default(loading->file, 0,
1599 "savefile.improvement_size");
1600 if (loading->improvement.size) {
1601 loading->improvement.order
1602 = secfile_lookup_str_vec(loading->file, &loading->improvement.size,
1603 "savefile.improvement_vector");
1604 sg_failure_ret(loading->improvement.size != 0,
1605 "Failed to load improvement order: %s",
1606 secfile_error());
1609 /* Load technologies. */
1610 loading->technology.size
1611 = secfile_lookup_int_default(loading->file, 0,
1612 "savefile.technology_size");
1613 if (loading->technology.size) {
1614 loading->technology.order
1615 = secfile_lookup_str_vec(loading->file, &loading->technology.size,
1616 "savefile.technology_vector");
1617 sg_failure_ret(loading->improvement.size != 0,
1618 "Failed to load technology order: %s",
1619 secfile_error());
1622 /* Load traits. */
1623 loading->trait.size
1624 = secfile_lookup_int_default(loading->file, 0,
1625 "savefile.trait_size");
1626 if (loading->trait.size) {
1627 loading->trait.order
1628 = secfile_lookup_str_vec(loading->file, &loading->trait.size,
1629 "savefile.trait_vector");
1630 sg_failure_ret(loading->trait.size != 0,
1631 "Failed to load trait order: %s",
1632 secfile_error());
1635 /* Load extras. */
1636 loading->extra.size
1637 = secfile_lookup_int_default(loading->file, 0,
1638 "savefile.extras_size");
1639 if (loading->extra.size) {
1640 const char **modname;
1641 size_t nmod;
1642 int j;
1644 modname = secfile_lookup_str_vec(loading->file, &loading->extra.size,
1645 "savefile.extras_vector");
1646 sg_failure_ret(loading->extra.size != 0,
1647 "Failed to load extras order: %s",
1648 secfile_error());
1649 sg_failure_ret(!(game.control.num_extra_types < loading->extra.size),
1650 "Number of extras defined by the ruleset (= %d) are "
1651 "lower than the number in the savefile (= %d).",
1652 game.control.num_extra_types, (int)loading->extra.size);
1653 /* make sure that the size of the array is divisible by 4 */
1654 nmod = 4 * ((loading->extra.size + 3) / 4);
1655 loading->extra.order = fc_calloc(nmod, sizeof(*loading->extra.order));
1656 for (j = 0; j < loading->extra.size; j++) {
1657 loading->extra.order[j] = extra_type_by_rule_name(modname[j]);
1659 free(modname);
1660 for (; j < nmod; j++) {
1661 loading->extra.order[j] = NULL;
1665 /* Load multipliers. */
1666 loading->multiplier.size
1667 = secfile_lookup_int_default(loading->file, 0,
1668 "savefile.multipliers_size");
1669 if (loading->multiplier.size) {
1670 const char **modname;
1671 int j;
1673 modname = secfile_lookup_str_vec(loading->file, &loading->multiplier.size,
1674 "savefile.multipliers_vector");
1675 sg_failure_ret(loading->multiplier.size != 0,
1676 "Failed to load multipliers order: %s",
1677 secfile_error());
1678 /* It's OK for the set of multipliers in the savefile to differ
1679 * from those in the ruleset. */
1680 loading->multiplier.order = fc_calloc(loading->multiplier.size,
1681 sizeof(*loading->multiplier.order));
1682 for (j = 0; j < loading->multiplier.size; j++) {
1683 loading->multiplier.order[j] = multiplier_by_rule_name(modname[j]);
1684 if (!loading->multiplier.order[j]) {
1685 log_verbose("Multiplier \"%s\" in savegame but not in ruleset, "
1686 "discarding", modname[j]);
1689 free(modname);
1692 /* Load specials. */
1693 loading->special.size
1694 = secfile_lookup_int_default(loading->file, 0,
1695 "savefile.specials_size");
1696 if (loading->special.size) {
1697 const char **modname;
1698 size_t nmod;
1699 enum tile_special_type j;
1701 modname = secfile_lookup_str_vec(loading->file, &loading->special.size,
1702 "savefile.specials_vector");
1703 sg_failure_ret(loading->special.size != 0,
1704 "Failed to load specials order: %s",
1705 secfile_error());
1706 /* make sure that the size of the array is divisible by 4 */
1707 /* Allocating extra 4 slots, just a couple of bytes,
1708 * in case of special.size being divisible by 4 already is intentional.
1709 * Added complexity would cost those couple of bytes in code size alone,
1710 * and we actually need at least one slot immediately after last valid
1711 * one. That's where S_LAST is (or was in version that saved the game)
1712 * and in some cases S_LAST gets written to savegame, at least as
1713 * activity target special when activity targets some base or road
1714 * instead. By having current S_LAST in that index allows us to map
1715 * that old S_LAST to current S_LAST, just like any real special within
1716 * special.size gets mapped. */
1717 nmod = loading->special.size + (4 - (loading->special.size % 4));
1718 loading->special.order = fc_calloc(nmod,
1719 sizeof(*loading->special.order));
1720 for (j = 0; j < loading->special.size; j++) {
1721 if (!strcasecmp("Road", modname[j])) {
1722 loading->special.order[j] = S_OLD_ROAD;
1723 } else if (!strcasecmp("Railroad", modname[j])) {
1724 loading->special.order[j] = S_OLD_RAILROAD;
1725 } else if (!strcasecmp("River", modname[j])) {
1726 loading->special.order[j] = S_OLD_RIVER;
1727 } else {
1728 loading->special.order[j] = special_by_rule_name(modname[j]);
1731 free(modname);
1732 for (; j < nmod; j++) {
1733 loading->special.order[j] = S_LAST;
1737 /* Load bases. */
1738 loading->base.size
1739 = secfile_lookup_int_default(loading->file, 0,
1740 "savefile.bases_size");
1741 if (loading->base.size) {
1742 const char **modname;
1743 size_t nmod;
1744 int j;
1746 modname = secfile_lookup_str_vec(loading->file, &loading->base.size,
1747 "savefile.bases_vector");
1748 sg_failure_ret(loading->base.size != 0,
1749 "Failed to load bases order: %s",
1750 secfile_error());
1751 /* make sure that the size of the array is divisible by 4 */
1752 nmod = 4 * ((loading->base.size + 3) / 4);
1753 loading->base.order = fc_calloc(nmod, sizeof(*loading->base.order));
1754 for (j = 0; j < loading->base.size; j++) {
1755 struct extra_type *pextra = extra_type_by_rule_name(modname[j]);
1757 sg_failure_ret(pextra != NULL
1758 || game.control.num_base_types >= loading->base.size,
1759 "Unknown base type %s in savefile.",
1760 modname[j]);
1762 if (pextra != NULL) {
1763 loading->base.order[j] = extra_base_get(pextra);
1764 } else {
1765 loading->base.order[j] = NULL;
1768 free(modname);
1769 for (; j < nmod; j++) {
1770 loading->base.order[j] = NULL;
1774 /* Load roads. */
1775 loading->road.size
1776 = secfile_lookup_int_default(loading->file, 0,
1777 "savefile.roads_size");
1778 if (loading->road.size) {
1779 const char **modname;
1780 size_t nmod;
1781 int j;
1783 modname = secfile_lookup_str_vec(loading->file, &loading->road.size,
1784 "savefile.roads_vector");
1785 sg_failure_ret(loading->road.size != 0,
1786 "Failed to load roads order: %s",
1787 secfile_error());
1788 sg_failure_ret(!(game.control.num_road_types < loading->road.size),
1789 "Number of roads defined by the ruleset (= %d) are "
1790 "lower than the number in the savefile (= %d).",
1791 game.control.num_road_types, (int)loading->road.size);
1792 /* make sure that the size of the array is divisible by 4 */
1793 nmod = 4 * ((loading->road.size + 3) / 4);
1794 loading->road.order = fc_calloc(nmod, sizeof(*loading->road.order));
1795 for (j = 0; j < loading->road.size; j++) {
1796 struct extra_type *pextra = extra_type_by_rule_name(modname[j]);
1798 if (pextra != NULL) {
1799 loading->road.order[j] = extra_road_get(pextra);
1800 } else {
1801 loading->road.order[j] = NULL;
1804 free(modname);
1805 for (; j < nmod; j++) {
1806 loading->road.order[j] = NULL;
1810 /* Load specialists. */
1811 loading->specialist.size
1812 = secfile_lookup_int_default(loading->file, 0,
1813 "savefile.specialists_size");
1814 if (loading->specialist.size) {
1815 const char **modname;
1816 size_t nmod;
1817 int j;
1819 modname = secfile_lookup_str_vec(loading->file, &loading->specialist.size,
1820 "savefile.specialists_vector");
1821 sg_failure_ret(loading->specialist.size != 0,
1822 "Failed to load specialists order: %s",
1823 secfile_error());
1824 sg_failure_ret(!(game.control.num_specialist_types < loading->specialist.size),
1825 "Number of specialists defined by the ruleset (= %d) are "
1826 "lower than the number in the savefile (= %d).",
1827 game.control.num_specialist_types, (int)loading->specialist.size);
1828 /* make sure that the size of the array is divisible by 4 */
1829 /* That's not really needed with specialists at the moment, but done this way
1830 * for consistency with other types, and to be prepared for the time it needs
1831 * to be this way. */
1832 nmod = 4 * ((loading->specialist.size + 3) / 4);
1833 loading->specialist.order = fc_calloc(nmod, sizeof(*loading->specialist.order));
1834 for (j = 0; j < loading->specialist.size; j++) {
1835 loading->specialist.order[j] = specialist_by_rule_name(modname[j]);
1837 free(modname);
1838 for (; j < nmod; j++) {
1839 loading->specialist.order[j] = NULL;
1843 /* Load diplomatic state type order. */
1844 loading->ds_t.size
1845 = secfile_lookup_int_default(loading->file, 0,
1846 "savefile.diplstate_type_size");
1848 sg_failure_ret(loading->ds_t.size > 0,
1849 "Failed to load diplomatic state type order: %s",
1850 secfile_error());
1852 if (loading->ds_t.size) {
1853 const char **modname;
1854 int j;
1856 modname = secfile_lookup_str_vec(loading->file, &loading->ds_t.size,
1857 "savefile.diplstate_type_vector");
1859 loading->ds_t.order = fc_calloc(loading->ds_t.size,
1860 sizeof(*loading->ds_t.order));
1862 for (j = 0; j < loading->ds_t.size; j++) {
1863 loading->ds_t.order[j] = diplstate_type_by_name(modname[j],
1864 fc_strcasecmp);
1867 free(modname);
1870 terrain_type_iterate(pterr) {
1871 pterr->identifier_load = '\0';
1872 } terrain_type_iterate_end;
1874 i = 0;
1875 while ((terr_name = secfile_lookup_str_default(loading->file, NULL,
1876 "savefile.terrident%d.name", i)) != NULL) {
1877 struct terrain *pterr = terrain_by_rule_name(terr_name);
1879 if (pterr != NULL) {
1880 const char *iptr = secfile_lookup_str_default(loading->file, NULL,
1881 "savefile.terrident%d.identifier", i);
1883 pterr->identifier_load = *iptr;
1884 } else {
1885 log_error("Identifier for unknown terrain type %s.", terr_name);
1887 i++;
1890 terrain_type_iterate(pterr) {
1891 terrain_type_iterate(pterr2) {
1892 if (pterr != pterr2 && pterr->identifier_load != '\0') {
1893 sg_failure_ret((pterr->identifier_load != pterr2->identifier_load),
1894 "%s and %s share a saved identifier",
1895 terrain_rule_name(pterr), terrain_rule_name(pterr2));
1897 } terrain_type_iterate_end;
1898 } terrain_type_iterate_end;
1901 /****************************************************************************
1902 Save '[savefile]'.
1903 ****************************************************************************/
1904 static void sg_save_savefile(struct savedata *saving)
1906 int i;
1908 /* Check status and return if not OK (sg_success != TRUE). */
1909 sg_check_ret();
1911 /* Save savefile options. */
1912 sg_save_savefile_options(saving, savefile_options_default);
1914 secfile_insert_int(saving->file, current_compat_ver(), "savefile.version");
1916 /* Save reason of the savefile generation. */
1917 secfile_insert_str(saving->file, saving->save_reason, "savefile.reason");
1919 /* Save as accurate freeciv revision information as possible */
1920 secfile_insert_str(saving->file, freeciv_datafile_version(), "savefile.revision");
1922 /* Save rulesetdir at this point as this ruleset is required by this
1923 * savefile. */
1924 secfile_insert_str(saving->file, game.server.rulesetdir, "savefile.rulesetdir");
1926 if (game.control.version[0] != '\0') {
1927 /* Current ruleset has version information, save it.
1928 * This is never loaded, but exist in savegame file only for debugging purposes. */
1929 secfile_insert_str(saving->file, game.control.version, "savefile.rulesetversion");
1932 /* Save improvement order in savegame, so we are not dependent on ruleset
1933 * order. If the game isn't started improvements aren't loaded so we can
1934 * not save the order. */
1935 secfile_insert_int(saving->file, improvement_count(),
1936 "savefile.improvement_size");
1937 if (improvement_count() > 0) {
1938 const char* buf[improvement_count()];
1940 improvement_iterate(pimprove) {
1941 buf[improvement_index(pimprove)] = improvement_rule_name(pimprove);
1942 } improvement_iterate_end;
1944 secfile_insert_str_vec(saving->file, buf, improvement_count(),
1945 "savefile.improvement_vector");
1948 /* Save technology order in savegame, so we are not dependent on ruleset
1949 * order. If the game isn't started advances aren't loaded so we can not
1950 * save the order. */
1951 secfile_insert_int(saving->file, game.control.num_tech_types,
1952 "savefile.technology_size");
1953 if (game.control.num_tech_types > 0) {
1954 const char* buf[game.control.num_tech_types];
1956 buf[A_NONE] = "A_NONE";
1957 advance_iterate(A_FIRST, a) {
1958 buf[advance_index(a)] = advance_rule_name(a);
1959 } advance_iterate_end;
1960 secfile_insert_str_vec(saving->file, buf, game.control.num_tech_types,
1961 "savefile.technology_vector");
1964 /* Save activities order in the savegame. */
1965 secfile_insert_int(saving->file, ACTIVITY_LAST,
1966 "savefile.activities_size");
1967 if (ACTIVITY_LAST > 0) {
1968 const char **modname;
1969 int j;
1971 i = 0;
1973 modname = fc_calloc(ACTIVITY_LAST, sizeof(*modname));
1975 for (j = 0; j < ACTIVITY_LAST; j++) {
1976 modname[i++] = unit_activity_name(j);
1979 secfile_insert_str_vec(saving->file, modname,
1980 ACTIVITY_LAST,
1981 "savefile.activities_vector");
1982 free(modname);
1985 /* Save specialists order in the savegame. */
1986 secfile_insert_int(saving->file, specialist_count(),
1987 "savefile.specialists_size");
1989 const char **modname;
1991 i = 0;
1992 modname = fc_calloc(specialist_count(), sizeof(*modname));
1994 specialist_type_iterate(sp) {
1995 modname[i++] = specialist_rule_name(specialist_by_number(sp));
1996 } specialist_type_iterate_end;
1998 secfile_insert_str_vec(saving->file, modname, specialist_count(),
1999 "savefile.specialists_vector");
2001 free(modname);
2004 /* Save trait order in savegame. */
2005 secfile_insert_int(saving->file, TRAIT_COUNT,
2006 "savefile.trait_size");
2008 const char **modname;
2009 enum trait tr;
2010 int j;
2012 modname = fc_calloc(TRAIT_COUNT, sizeof(*modname));
2014 for (tr = trait_begin(), j = 0; tr != trait_end(); tr = trait_next(tr), j++) {
2015 modname[j] = trait_name(tr);
2018 secfile_insert_str_vec(saving->file, modname, TRAIT_COUNT,
2019 "savefile.trait_vector");
2020 free(modname);
2023 /* Save extras order in the savegame. */
2024 secfile_insert_int(saving->file, game.control.num_extra_types,
2025 "savefile.extras_size");
2026 if (game.control.num_extra_types > 0) {
2027 const char **modname;
2029 i = 0;
2030 modname = fc_calloc(game.control.num_extra_types, sizeof(*modname));
2032 extra_type_iterate(pextra) {
2033 modname[i++] = extra_rule_name(pextra);
2034 } extra_type_iterate_end;
2036 secfile_insert_str_vec(saving->file, modname,
2037 game.control.num_extra_types,
2038 "savefile.extras_vector");
2039 free(modname);
2042 /* Save multipliers order in the savegame. */
2043 secfile_insert_int(saving->file, multiplier_count(),
2044 "savefile.multipliers_size");
2045 if (multiplier_count() > 0) {
2046 const char **modname;
2048 i = 0;
2049 modname = fc_calloc(multiplier_count(), sizeof(*modname));
2051 multipliers_iterate(pmul) {
2052 modname[multiplier_index(pmul)] = multiplier_rule_name(pmul);
2053 } multipliers_iterate_end;
2055 secfile_insert_str_vec(saving->file, modname,
2056 multiplier_count(),
2057 "savefile.multipliers_vector");
2058 free(modname);
2061 /* Save diplstate type order in the savegame. */
2062 secfile_insert_int(saving->file, DS_LAST,
2063 "savefile.diplstate_type_size");
2064 if (DS_LAST > 0) {
2065 const char **modname;
2066 int j;
2068 i = 0;
2069 modname = fc_calloc(DS_LAST, sizeof(*modname));
2071 for (j = 0; j < DS_LAST; j++) {
2072 modname[i++] = diplstate_type_name(j);
2075 secfile_insert_str_vec(saving->file, modname,
2076 DS_LAST,
2077 "savefile.diplstate_type_vector");
2078 free(modname);
2081 /* Save city_option order in the savegame. */
2082 secfile_insert_int(saving->file, CITYO_LAST,
2083 "savefile.city_options_size");
2084 if (CITYO_LAST > 0) {
2085 const char **modname;
2086 int j;
2088 i = 0;
2089 modname = fc_calloc(CITYO_LAST, sizeof(*modname));
2091 for (j = 0; j < CITYO_LAST; j++) {
2092 modname[i++] = city_options_name(j);
2095 secfile_insert_str_vec(saving->file, modname,
2096 CITYO_LAST,
2097 "savefile.city_options_vector");
2098 free(modname);
2101 /* Save terrain character mapping in the savegame. */
2102 i = 0;
2103 terrain_type_iterate(pterr) {
2104 char buf[2];
2106 secfile_insert_str(saving->file, terrain_rule_name(pterr), "savefile.terrident%d.name", i);
2107 buf[0] = terrain_identifier(pterr);
2108 buf[1] = '\0';
2109 secfile_insert_str(saving->file, buf, "savefile.terrident%d.identifier", i++);
2110 } terrain_type_iterate_end;
2113 /****************************************************************************
2114 Save options for this savegame. sg_load_savefile_options() is not defined.
2115 ****************************************************************************/
2116 static void sg_save_savefile_options(struct savedata *saving,
2117 const char *option)
2119 /* Check status and return if not OK (sg_success != TRUE). */
2120 sg_check_ret();
2122 if (option == NULL) {
2123 /* no additional option */
2124 return;
2127 sz_strlcat(saving->secfile_options, option);
2128 secfile_replace_str(saving->file, saving->secfile_options,
2129 "savefile.options");
2132 /* =======================================================================
2133 * Load / save game status.
2134 * ======================================================================= */
2136 /****************************************************************************
2137 Load '[ruledata]'.
2138 ****************************************************************************/
2139 static void sg_load_ruledata(struct loaddata *loading)
2141 int i;
2142 const char *name;
2144 for (i = 0;
2145 (name = secfile_lookup_str_default(loading->file, NULL,
2146 "ruledata.government%d.name", i));
2147 i++) {
2148 struct government *gov = government_by_rule_name(name);
2150 if (gov != NULL) {
2151 gov->changed_to_times = secfile_lookup_int_default(loading->file, 0,
2152 "ruledata.government%d.changes", i);
2157 /****************************************************************************
2158 Load '[game]'.
2159 ****************************************************************************/
2160 static void sg_load_game(struct loaddata *loading)
2162 int game_version;
2163 const char *string;
2164 const char *level;
2165 int i;
2167 /* Check status and return if not OK (sg_success != TRUE). */
2168 sg_check_ret();
2170 /* Load version. */
2171 game_version
2172 = secfile_lookup_int_default(loading->file, 0, "game.version");
2173 /* We require at least version 2.2.99 */
2174 sg_failure_ret(20299 <= game_version, "Saved game is too old, at least "
2175 "version 2.2.99 required.");
2177 /* Load server state. */
2178 string = secfile_lookup_str_default(loading->file, "S_S_INITIAL",
2179 "game.server_state");
2180 loading->server_state = server_states_by_name(string, strcmp);
2181 if (!server_states_is_valid(loading->server_state)) {
2182 /* Don't take any risk! */
2183 loading->server_state = S_S_INITIAL;
2186 string = secfile_lookup_str_default(loading->file,
2187 default_meta_patches_string(),
2188 "game.meta_patches");
2189 set_meta_patches_string(string);
2190 game.server.meta_info.user_message_set
2191 = secfile_lookup_bool_default(loading->file, FALSE,
2192 "game.meta_usermessage");
2193 if (game.server.meta_info.user_message_set) {
2194 string = secfile_lookup_str_default(loading->file,
2195 default_meta_message_string(),
2196 "game.meta_message");
2197 set_user_meta_message_string(string);
2200 if (0 == strcmp(DEFAULT_META_SERVER_ADDR, srvarg.metaserver_addr)) {
2201 /* Do not overwrite this if the user requested a specific metaserver
2202 * from the command line (option --Metaserver). */
2203 sz_strlcpy(srvarg.metaserver_addr,
2204 secfile_lookup_str_default(loading->file,
2205 DEFAULT_META_SERVER_ADDR,
2206 "game.meta_server"));
2209 if ('\0' == srvarg.serverid[0]) {
2210 /* Do not overwrite this if the user requested a specific metaserver
2211 * from the command line (option --serverid). */
2212 sz_strlcpy(srvarg.serverid,
2213 secfile_lookup_str_default(loading->file, "",
2214 "game.serverid"));
2216 sz_strlcpy(server.game_identifier,
2217 secfile_lookup_str_default(loading->file, "", "game.id"));
2218 /* We are not checking game_identifier legality just yet.
2219 * That's done when we are sure that rand seed has been initialized,
2220 * so that we can generate new game_identifier, if needed.
2221 * See sq_load_sanitycheck(). */
2223 level = secfile_lookup_str_default(loading->file, NULL,
2224 "game.level");
2225 if (level != NULL) {
2226 game.info.skill_level = ai_level_by_name(level, fc_strcasecmp);
2227 } else {
2228 game.info.skill_level = ai_level_invalid();
2231 if (!ai_level_is_valid(game.info.skill_level)) {
2232 game.info.skill_level
2233 = ai_level_convert(secfile_lookup_int_default(loading->file,
2234 GAME_HARDCODED_DEFAULT_SKILL_LEVEL,
2235 "game.skill_level"));
2237 game.info.phase_mode
2238 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_PHASE_MODE,
2239 "game.phase_mode");
2240 game.server.phase_mode_stored
2241 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_PHASE_MODE,
2242 "game.phase_mode_stored");
2243 game.info.phase
2244 = secfile_lookup_int_default(loading->file, 0,
2245 "game.phase");
2246 game.server.scoreturn
2247 = secfile_lookup_int_default(loading->file,
2248 game.info.turn + GAME_DEFAULT_SCORETURN,
2249 "game.scoreturn");
2251 game.server.timeoutint
2252 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_TIMEOUTINT,
2253 "game.timeoutint");
2254 game.server.timeoutintinc
2255 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_TIMEOUTINTINC,
2256 "game.timeoutintinc");
2257 game.server.timeoutinc
2258 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_TIMEOUTINC,
2259 "game.timeoutinc");
2260 game.server.timeoutincmult
2261 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_TIMEOUTINCMULT,
2262 "game.timeoutincmult");
2263 game.server.timeoutcounter
2264 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_TIMEOUTCOUNTER,
2265 "game.timeoutcounter");
2267 game.info.turn
2268 = secfile_lookup_int_default(loading->file, 0, "game.turn");
2269 sg_failure_ret(secfile_lookup_int(loading->file, &game.info.year,
2270 "game.year"), "%s", secfile_error());
2271 game.info.year_0_hack
2272 = secfile_lookup_bool_default(loading->file, FALSE, "game.year_0_hack");
2274 game.info.globalwarming
2275 = secfile_lookup_int_default(loading->file, 0, "game.globalwarming");
2276 game.info.heating
2277 = secfile_lookup_int_default(loading->file, 0, "game.heating");
2278 game.info.warminglevel
2279 = secfile_lookup_int_default(loading->file, 0, "game.warminglevel");
2281 game.info.nuclearwinter
2282 = secfile_lookup_int_default(loading->file, 0, "game.nuclearwinter");
2283 game.info.cooling
2284 = secfile_lookup_int_default(loading->file, 0, "game.cooling");
2285 game.info.coolinglevel
2286 = secfile_lookup_int_default(loading->file, 0, "game.coolinglevel");
2288 /* Global advances. */
2289 string = secfile_lookup_str_default(loading->file, NULL,
2290 "game.global_advances");
2291 if (string != NULL) {
2292 sg_failure_ret(strlen(string) == loading->technology.size,
2293 "Invalid length of 'game.global_advances' (%lu ~= %lu).",
2294 (unsigned long) strlen(string),
2295 (unsigned long) loading->technology.size);
2296 for (i = 0; i < loading->technology.size; i++) {
2297 sg_failure_ret(string[i] == '1' || string[i] == '0',
2298 "Undefined value '%c' within 'game.global_advances'.",
2299 string[i]);
2300 if (string[i] == '1') {
2301 struct advance *padvance =
2302 advance_by_rule_name(loading->technology.order[i]);
2304 if (padvance != NULL) {
2305 game.info.global_advances[advance_number(padvance)] = TRUE;
2311 game.info.is_new_game
2312 = !secfile_lookup_bool_default(loading->file, TRUE, "game.save_players");
2314 game.server.turn_change_time
2315 = secfile_lookup_int_default(loading->file, 0, "game.last_turn_change_time") / 100;
2318 /****************************************************************************
2319 Save '[ruledata]'.
2320 ****************************************************************************/
2321 static void sg_save_ruledata(struct savedata *saving)
2323 int set_count = 0;
2325 governments_iterate(pgov) {
2326 char path[256];
2328 fc_snprintf(path, sizeof(path),
2329 "ruledata.government%d", set_count++);
2331 secfile_insert_str(saving->file, government_rule_name(pgov),
2332 "%s.name", path);
2333 secfile_insert_int(saving->file, pgov->changed_to_times,
2334 "%s.changes", path);
2335 } governments_iterate_end;
2338 /****************************************************************************
2339 Save '[game]'.
2340 ****************************************************************************/
2341 static void sg_save_game(struct savedata *saving)
2343 int game_version;
2344 const char *user_message;
2345 enum server_states srv_state;
2346 char global_advances[game.control.num_tech_types + 1];
2347 int i;
2349 /* Check status and return if not OK (sg_success != TRUE). */
2350 sg_check_ret();
2352 game_version = MAJOR_VERSION *10000 + MINOR_VERSION *100 + PATCH_VERSION;
2353 secfile_insert_int(saving->file, game_version, "game.version");
2355 /* Game state: once the game is no longer a new game (ie, has been
2356 * started the first time), it should always be considered a running
2357 * game for savegame purposes. */
2358 if (saving->scenario && !game.scenario.players) {
2359 srv_state = S_S_INITIAL;
2360 } else {
2361 srv_state = game.info.is_new_game ? server_state() : S_S_RUNNING;
2363 secfile_insert_str(saving->file, server_states_name(srv_state),
2364 "game.server_state");
2366 secfile_insert_str(saving->file, get_meta_patches_string(),
2367 "game.meta_patches");
2368 secfile_insert_bool(saving->file, game.server.meta_info.user_message_set,
2369 "game.meta_usermessage");
2370 user_message = get_user_meta_message_string();
2371 if (user_message != NULL) {
2372 secfile_insert_str(saving->file, user_message, "game.meta_message");
2374 secfile_insert_str(saving->file, meta_addr_port(), "game.meta_server");
2376 secfile_insert_str(saving->file, server.game_identifier, "game.id");
2377 secfile_insert_str(saving->file, srvarg.serverid, "game.serverid");
2379 secfile_insert_str(saving->file, ai_level_name(game.info.skill_level),
2380 "game.level");
2381 secfile_insert_int(saving->file, game.info.phase_mode,
2382 "game.phase_mode");
2383 secfile_insert_int(saving->file, game.server.phase_mode_stored,
2384 "game.phase_mode_stored");
2385 secfile_insert_int(saving->file, game.info.phase,
2386 "game.phase");
2387 secfile_insert_int(saving->file, game.server.scoreturn,
2388 "game.scoreturn");
2390 secfile_insert_int(saving->file, game.server.timeoutint,
2391 "game.timeoutint");
2392 secfile_insert_int(saving->file, game.server.timeoutintinc,
2393 "game.timeoutintinc");
2394 secfile_insert_int(saving->file, game.server.timeoutinc,
2395 "game.timeoutinc");
2396 secfile_insert_int(saving->file, game.server.timeoutincmult,
2397 "game.timeoutincmult");
2398 secfile_insert_int(saving->file, game.server.timeoutcounter,
2399 "game.timeoutcounter");
2401 secfile_insert_int(saving->file, game.info.turn, "game.turn");
2402 secfile_insert_int(saving->file, game.info.year, "game.year");
2403 secfile_insert_bool(saving->file, game.info.year_0_hack,
2404 "game.year_0_hack");
2406 secfile_insert_int(saving->file, game.info.globalwarming,
2407 "game.globalwarming");
2408 secfile_insert_int(saving->file, game.info.heating,
2409 "game.heating");
2410 secfile_insert_int(saving->file, game.info.warminglevel,
2411 "game.warminglevel");
2413 secfile_insert_int(saving->file, game.info.nuclearwinter,
2414 "game.nuclearwinter");
2415 secfile_insert_int(saving->file, game.info.cooling,
2416 "game.cooling");
2417 secfile_insert_int(saving->file, game.info.coolinglevel,
2418 "game.coolinglevel");
2419 /* For debugging purposes only.
2420 * Do not save it if it's 0 (not known);
2421 * this confuses people reading this 'document' less than
2422 * saving 0. */
2423 if (game.server.seed != 0) {
2424 secfile_insert_int(saving->file, game.server.seed,
2425 "game.random_seed");
2428 /* Global advances. */
2429 for (i = 0; i < game.control.num_tech_types; i++) {
2430 global_advances[i] = game.info.global_advances[i] ? '1' : '0';
2432 global_advances[i] = '\0';
2433 secfile_insert_str(saving->file, global_advances, "game.global_advances");
2435 if (!game_was_started()) {
2436 saving->save_players = FALSE;
2437 } else {
2438 if (saving->scenario) {
2439 saving->save_players = game.scenario.players;
2440 } else {
2441 saving->save_players = TRUE;
2443 #ifndef SAVE_DUMMY_TURN_CHANGE_TIME
2444 secfile_insert_int(saving->file, game.server.turn_change_time * 100,
2445 "game.last_turn_change_time");
2446 #else /* SAVE_DUMMY_TURN_CHANGE_TIME */
2447 secfile_insert_int(saving->file, game.info.turn * 10,
2448 "game.last_turn_change_time");
2449 #endif /* SAVE_DUMMY_TURN_CHANGE_TIME */
2451 secfile_insert_bool(saving->file, saving->save_players,
2452 "game.save_players");
2455 /* =======================================================================
2456 * Load / save random status.
2457 * ======================================================================= */
2459 /****************************************************************************
2460 Load '[random]'.
2461 ****************************************************************************/
2462 static void sg_load_random(struct loaddata *loading)
2464 /* Check status and return if not OK (sg_success != TRUE). */
2465 sg_check_ret();
2467 if (secfile_lookup_bool_default(loading->file, FALSE, "random.save")) {
2468 const char *string;
2469 int i;
2471 /* Since random state was previously saved, save it also when resaving.
2472 * This affects only pre-2.6 scenarios where scenario.save_random
2473 * is not defined.
2474 * - If this is 2.6 or later scenario -> it would have saved random.save = TRUE
2475 * only if scenario.save_random is already TRUE
2477 * Do NOT touch this in case of regular savegame. They always have random.save
2478 * set, but if one starts to make scenario based on a savegame, we want
2479 * default scenario settings in the beginning (default save_random = FALSE).
2481 if (game.scenario.is_scenario) {
2482 game.scenario.save_random = TRUE;
2485 sg_failure_ret(secfile_lookup_int(loading->file, &loading->rstate.j,
2486 "random.index_J"), "%s", secfile_error());
2487 sg_failure_ret(secfile_lookup_int(loading->file, &loading->rstate.k,
2488 "random.index_K"), "%s", secfile_error());
2489 sg_failure_ret(secfile_lookup_int(loading->file, &loading->rstate.x,
2490 "random.index_X"), "%s", secfile_error());
2492 for (i = 0; i < 8; i++) {
2493 string = secfile_lookup_str(loading->file, "random.table%d",i);
2494 sg_failure_ret(NULL != string, "%s", secfile_error());
2495 sscanf(string, "%8x %8x %8x %8x %8x %8x %8x", &loading->rstate.v[7*i],
2496 &loading->rstate.v[7*i+1], &loading->rstate.v[7*i+2],
2497 &loading->rstate.v[7*i+3], &loading->rstate.v[7*i+4],
2498 &loading->rstate.v[7*i+5], &loading->rstate.v[7*i+6]);
2500 loading->rstate.is_init = TRUE;
2501 fc_rand_set_state(loading->rstate);
2502 } else {
2503 /* No random values - mark the setting. */
2504 (void) secfile_entry_by_path(loading->file, "random.save");
2506 /* We're loading a game without a seed (which is okay, if it's a scenario).
2507 * We need to generate the game seed now because it will be needed later
2508 * during the load. */
2509 init_game_seed();
2510 loading->rstate = fc_rand_state();
2514 /****************************************************************************
2515 Save '[random]'.
2516 ****************************************************************************/
2517 static void sg_save_random(struct savedata *saving)
2519 /* Check status and return if not OK (sg_success != TRUE). */
2520 sg_check_ret();
2522 if (fc_rand_is_init() && (!saving->scenario || game.scenario.save_random)) {
2523 int i;
2524 RANDOM_STATE rstate = fc_rand_state();
2526 secfile_insert_bool(saving->file, TRUE, "random.save");
2527 fc_assert(rstate.is_init);
2529 secfile_insert_int(saving->file, rstate.j, "random.index_J");
2530 secfile_insert_int(saving->file, rstate.k, "random.index_K");
2531 secfile_insert_int(saving->file, rstate.x, "random.index_X");
2533 for (i = 0; i < 8; i++) {
2534 char vec[100];
2536 fc_snprintf(vec, sizeof(vec),
2537 "%8x %8x %8x %8x %8x %8x %8x", rstate.v[7 * i],
2538 rstate.v[7 * i + 1], rstate.v[7 * i + 2],
2539 rstate.v[7 * i + 3], rstate.v[7 * i + 4],
2540 rstate.v[7 * i + 5], rstate.v[7 * i + 6]);
2541 secfile_insert_str(saving->file, vec, "random.table%d", i);
2543 } else {
2544 secfile_insert_bool(saving->file, FALSE, "random.save");
2548 /* =======================================================================
2549 * Load / save lua script data.
2550 * ======================================================================= */
2552 /****************************************************************************
2553 Load '[script]'.
2554 ****************************************************************************/
2555 static void sg_load_script(struct loaddata *loading)
2557 /* Check status and return if not OK (sg_success != TRUE). */
2558 sg_check_ret();
2560 script_server_state_load(loading->file);
2563 /****************************************************************************
2564 Save '[script]'.
2565 ****************************************************************************/
2566 static void sg_save_script(struct savedata *saving)
2568 /* Check status and return if not OK (sg_success != TRUE). */
2569 sg_check_ret();
2571 script_server_state_save(saving->file);
2574 /* =======================================================================
2575 * Load / save scenario data.
2576 * ======================================================================= */
2578 /****************************************************************************
2579 Load '[scenario]'.
2580 ****************************************************************************/
2581 static void sg_load_scenario(struct loaddata *loading)
2583 const char *buf;
2584 bool lake_flood_default;
2586 /* Check status and return if not OK (sg_success != TRUE). */
2587 sg_check_ret();
2589 if (NULL == secfile_section_lookup(loading->file, "scenario")) {
2590 game.scenario.is_scenario = FALSE;
2592 return;
2595 /* Default is that when there's scenario section (which we already checked)
2596 * this is a scenario. Only if it explicitly says that it's not, we consider
2597 * this regular savegame */
2598 game.scenario.is_scenario = secfile_lookup_bool_default(loading->file, TRUE, "scenario.is_scenario");
2600 if (!game.scenario.is_scenario) {
2601 return;
2604 buf = secfile_lookup_str_default(loading->file, "", "scenario.name");
2605 if (buf[0] != '\0') {
2606 sz_strlcpy(game.scenario.name, buf);
2609 buf = secfile_lookup_str_default(loading->file, "",
2610 "scenario.authors");
2611 if (buf[0] != '\0') {
2612 sz_strlcpy(game.scenario.authors, buf);
2613 } else {
2614 game.scenario.authors[0] = '\0';
2617 buf = secfile_lookup_str_default(loading->file, "",
2618 "scenario.description");
2619 if (buf[0] != '\0') {
2620 sz_strlcpy(game.scenario_desc.description, buf);
2621 } else {
2622 game.scenario_desc.description[0] = '\0';
2625 game.scenario.save_random
2626 = secfile_lookup_bool_default(loading->file, FALSE, "scenario.save_random");
2627 game.scenario.players
2628 = secfile_lookup_bool_default(loading->file, TRUE, "scenario.players");
2629 game.scenario.startpos_nations
2630 = secfile_lookup_bool_default(loading->file, FALSE,
2631 "scenario.startpos_nations");
2633 game.scenario.prevent_new_cities
2634 = secfile_lookup_bool_default(loading->file, FALSE,
2635 "scenario.prevent_new_cities");
2636 if (loading->version < 20599) {
2637 /* Lake flooding may break some old scenarios where rivers made out of
2638 * lake terrains, so play safe there */
2639 lake_flood_default = FALSE;
2640 } else {
2641 /* If lake flooding is a problem for a newer scenario, it could explicitly
2642 * disable it. */
2643 lake_flood_default = TRUE;
2645 game.scenario.lake_flooding
2646 = secfile_lookup_bool_default(loading->file, lake_flood_default,
2647 "scenario.lake_flooding");
2648 game.scenario.handmade
2649 = secfile_lookup_bool_default(loading->file, FALSE,
2650 "scenario.handmade");
2651 game.scenario.allow_ai_type_fallback
2652 = secfile_lookup_bool_default(loading->file, FALSE,
2653 "scenario.allow_ai_type_fallback");
2655 sg_failure_ret(loading->server_state == S_S_INITIAL
2656 || (loading->server_state == S_S_RUNNING
2657 && game.scenario.players == TRUE),
2658 "Invalid scenario definition (server state '%s' and "
2659 "players are %s).",
2660 server_states_name(loading->server_state),
2661 game.scenario.players ? "saved" : "not saved");
2663 /* Remove all defined players. They are recreated with the skill level
2664 * defined by the scenario. */
2665 (void) aifill(0);
2668 /****************************************************************************
2669 Save '[scenario]'.
2670 ****************************************************************************/
2671 static void sg_save_scenario(struct savedata *saving)
2673 struct entry *mod_entry;
2674 int game_version;
2676 /* Check status and return if not OK (sg_success != TRUE). */
2677 sg_check_ret();
2679 if (!saving->scenario || !game.scenario.is_scenario) {
2680 secfile_insert_bool(saving->file, FALSE, "scenario.is_scenario");
2681 return;
2684 secfile_insert_bool(saving->file, TRUE, "scenario.is_scenario");
2686 game_version = MAJOR_VERSION * 10000 + MINOR_VERSION * 100 + PATCH_VERSION;
2687 secfile_insert_int(saving->file, game_version, "scenario.game_version");
2689 /* Name is mandatory to the level that is saved even if empty. */
2690 mod_entry = secfile_insert_str(saving->file, game.scenario.name, "scenario.name");
2691 entry_str_set_gt_marking(mod_entry, TRUE);
2693 /* Authors list is saved only if it exist */
2694 if (game.scenario.authors[0] != '\0') {
2695 mod_entry = secfile_insert_str(saving->file, game.scenario.authors,
2696 "scenario.authors");
2697 entry_str_set_gt_marking(mod_entry, TRUE);
2700 /* Description is saved only if it exist */
2701 if (game.scenario_desc.description[0] != '\0') {
2702 mod_entry = secfile_insert_str(saving->file, game.scenario_desc.description,
2703 "scenario.description");
2704 entry_str_set_gt_marking(mod_entry, TRUE);
2707 secfile_insert_bool(saving->file, game.scenario.save_random, "scenario.save_random");
2708 secfile_insert_bool(saving->file, game.scenario.players, "scenario.players");
2709 secfile_insert_bool(saving->file, game.scenario.startpos_nations,
2710 "scenario.startpos_nations");
2711 if (game.scenario.prevent_new_cities) {
2712 secfile_insert_bool(saving->file, game.scenario.prevent_new_cities,
2713 "scenario.prevent_new_cities");
2715 secfile_insert_bool(saving->file, game.scenario.lake_flooding,
2716 "scenario.lake_flooding");
2717 if (game.scenario.handmade) {
2718 secfile_insert_bool(saving->file, game.scenario.handmade,
2719 "scenario.handmade");
2721 if (game.scenario.allow_ai_type_fallback) {
2722 secfile_insert_bool(saving->file, game.scenario.allow_ai_type_fallback,
2723 "scenario.allow_ai_type_fallback");
2727 /* =======================================================================
2728 * Load / save game settings.
2729 * ======================================================================= */
2731 /****************************************************************************
2732 Load '[settings]'.
2733 ****************************************************************************/
2734 static void sg_load_settings(struct loaddata *loading)
2736 /* Check status and return if not OK (sg_success != TRUE). */
2737 sg_check_ret();
2739 settings_game_load(loading->file, "settings");
2741 /* Save current status of fogofwar. */
2742 game.server.fogofwar_old = game.info.fogofwar;
2744 /* Add all compatibility settings here. */
2747 /****************************************************************************
2748 Save [settings].
2749 ****************************************************************************/
2750 static void sg_save_settings(struct savedata *saving)
2752 enum map_generator real_generator = game.map.server.generator;
2754 /* Check status and return if not OK (sg_success != TRUE). */
2755 sg_check_ret();
2757 if (saving->scenario) {
2758 game.map.server.generator = MAPGEN_SCENARIO; /* We want a scenario. */
2761 settings_game_save(saving->file, "settings");
2762 /* Restore real map generator. */
2763 game.map.server.generator = real_generator;
2765 /* Add all compatibility settings here. */
2768 /* =======================================================================
2769 * Load / save the main map.
2770 * ======================================================================= */
2772 /****************************************************************************
2773 Load '[map'].
2774 ****************************************************************************/
2775 static void sg_load_map(struct loaddata *loading)
2777 /* Check status and return if not OK (sg_success != TRUE). */
2778 sg_check_ret();
2780 /* This defaults to TRUE even if map has not been generated. Also,
2781 * old versions have also explicitly saved TRUE even in pre-game.
2782 * We rely on that
2783 * 1) scenario maps have it explicity right.
2784 * 2) when map is actually generated, it re-initialize this to FALSE. */
2785 game.map.server.have_huts
2786 = secfile_lookup_bool_default(loading->file, TRUE, "map.have_huts");
2788 if (S_S_INITIAL == loading->server_state
2789 && MAPGEN_SCENARIO == game.map.server.generator) {
2790 /* Generator MAPGEN_SCENARIO is used;
2791 * this map was done with the map editor. */
2793 /* Load tiles. */
2794 sg_load_map_tiles(loading);
2795 sg_load_map_startpos(loading);
2797 if (loading->version >= 30) {
2798 /* 2.6.0 or newer */
2799 sg_load_map_tiles_extras(loading);
2800 } else {
2801 sg_load_map_tiles_bases(loading);
2802 if (loading->version >= 20) {
2803 /* 2.5.0 or newer */
2804 sg_load_map_tiles_roads(loading);
2806 if (has_capability("specials", loading->secfile_options)) {
2807 /* Load specials. */
2808 sg_load_map_tiles_specials(loading, FALSE);
2812 if (has_capability("specials", loading->secfile_options)) {
2813 /* Load resources. */
2814 sg_load_map_tiles_resources(loading);
2815 } else if (has_capability("riversoverlay", loading->secfile_options)) {
2816 /* Load only rivers overlay. */
2817 sg_load_map_tiles_specials(loading, TRUE);
2820 /* Nothing more needed for a scenario. */
2821 return;
2824 if (S_S_INITIAL == loading->server_state) {
2825 /* Nothing more to do if it is not a scenario but in initial state. */
2826 return;
2829 sg_load_map_tiles(loading);
2830 sg_load_map_startpos(loading);
2831 if (loading->version >= 30) {
2832 /* 2.6.0 or newer */
2833 sg_load_map_tiles_extras(loading);
2834 } else {
2835 sg_load_map_tiles_bases(loading);
2836 if (loading->version >= 20) {
2837 /* 2.5.0 or newer */
2838 sg_load_map_tiles_roads(loading);
2840 sg_load_map_tiles_specials(loading, FALSE);
2842 sg_load_map_tiles_resources(loading);
2843 sg_load_map_known(loading);
2844 sg_load_map_owner(loading);
2845 sg_load_map_worked(loading);
2848 /****************************************************************************
2849 Save 'map'.
2850 ****************************************************************************/
2851 static void sg_save_map(struct savedata *saving)
2853 /* Check status and return if not OK (sg_success != TRUE). */
2854 sg_check_ret();
2856 if (map_is_empty()) {
2857 /* No map. */
2858 return;
2861 if (saving->scenario) {
2862 secfile_insert_bool(saving->file, game.map.server.have_huts, "map.have_huts");
2863 } else {
2864 secfile_insert_bool(saving->file, TRUE, "map.have_huts");
2867 /* For debugging purposes only.
2868 * Do not save it if it's 0 (not known);
2869 * this confuses people reading this 'document' less than
2870 * saving 0. */
2871 if (game.map.server.seed) {
2872 secfile_insert_int(saving->file, game.map.server.seed,
2873 "map.random_seed");
2876 sg_save_map_tiles(saving);
2877 sg_save_map_startpos(saving);
2878 sg_save_map_tiles_extras(saving);
2879 if (game.scenario.have_resources) {
2880 sg_save_savefile_options(saving, " specials");
2881 sg_save_map_tiles_resources(saving);
2884 sg_save_map_owner(saving);
2885 sg_save_map_worked(saving);
2886 sg_save_map_known(saving);
2889 /****************************************************************************
2890 Load tiles of the map.
2891 ****************************************************************************/
2892 static void sg_load_map_tiles(struct loaddata *loading)
2894 /* Check status and return if not OK (sg_success != TRUE). */
2895 sg_check_ret();
2897 /* Initialize the map for the current topology. 'map.xsize' and
2898 * 'map.ysize' must be set. */
2899 map_init_topology();
2901 /* Allocate map. */
2902 map_allocate();
2904 /* get the terrain type */
2905 LOAD_MAP_CHAR(ch, ptile, ptile->terrain = char2terrain(ch), loading->file,
2906 "map.t%04d");
2907 assign_continent_numbers();
2909 /* Check for special tile sprites. */
2910 whole_map_iterate(ptile) {
2911 const char *spec_sprite;
2912 const char *label;
2913 int nat_x, nat_y;
2915 index_to_native_pos(&nat_x, &nat_y, tile_index(ptile));
2916 spec_sprite = secfile_lookup_str(loading->file, "map.spec_sprite_%d_%d",
2917 nat_x, nat_y);
2918 label = secfile_lookup_str_default(loading->file, NULL, "map.label_%d_%d",
2919 nat_x, nat_y);
2920 if (NULL != ptile->spec_sprite) {
2921 ptile->spec_sprite = fc_strdup(spec_sprite);
2923 if (label != NULL) {
2924 tile_set_label(ptile, label);
2926 } whole_map_iterate_end;
2929 /****************************************************************************
2930 Save all map tiles
2931 ****************************************************************************/
2932 static void sg_save_map_tiles(struct savedata *saving)
2934 /* Check status and return if not OK (sg_success != TRUE). */
2935 sg_check_ret();
2937 /* Save the terrain type. */
2938 SAVE_MAP_CHAR(ptile, terrain2char(ptile->terrain), saving->file,
2939 "map.t%04d");
2941 /* Save special tile sprites. */
2942 whole_map_iterate(ptile) {
2943 int nat_x, nat_y;
2945 index_to_native_pos(&nat_x, &nat_y, tile_index(ptile));
2946 if (ptile->spec_sprite) {
2947 secfile_insert_str(saving->file, ptile->spec_sprite,
2948 "map.spec_sprite_%d_%d", nat_x, nat_y);
2950 if (ptile->label != NULL) {
2951 secfile_insert_str(saving->file, ptile->label,
2952 "map.label_%d_%d", nat_x, nat_y);
2954 } whole_map_iterate_end;
2957 /****************************************************************************
2958 Load extras to map
2959 ****************************************************************************/
2960 static void sg_load_map_tiles_extras(struct loaddata *loading)
2962 /* Check status and return if not OK (sg_success != TRUE). */
2963 sg_check_ret();
2965 /* Load extras. */
2966 halfbyte_iterate_extras(j, loading->extra.size) {
2967 LOAD_MAP_CHAR(ch, ptile, sg_extras_set(&ptile->extras, ch, loading->extra.order + 4 * j),
2968 loading->file, "map.e%02d_%04d", j);
2969 } halfbyte_iterate_extras_end;
2972 /****************************************************************************
2973 Save information about extras on map
2974 ****************************************************************************/
2975 static void sg_save_map_tiles_extras(struct savedata *saving)
2977 /* Check status and return if not OK (sg_success != TRUE). */
2978 sg_check_ret();
2980 /* Save extras. */
2981 halfbyte_iterate_extras(j, game.control.num_extra_types) {
2982 int mod[4];
2983 int l;
2985 for (l = 0; l < 4; l++) {
2986 if (4 * j + 1 > game.control.num_extra_types) {
2987 mod[l] = -1;
2988 } else {
2989 mod[l] = 4 * j + l;
2992 SAVE_MAP_CHAR(ptile, sg_extras_get(ptile->extras, mod),
2993 saving->file, "map.e%02d_%04d", j);
2994 } halfbyte_iterate_extras_end;
2997 /****************************************************************************
2998 Load bases to map
2999 ****************************************************************************/
3000 static void sg_load_map_tiles_bases(struct loaddata *loading)
3002 /* Check status and return if not OK (sg_success != TRUE). */
3003 sg_check_ret();
3005 /* Load bases. */
3006 halfbyte_iterate_bases(j, loading->base.size) {
3007 LOAD_MAP_CHAR(ch, ptile, sg_bases_set(&ptile->extras, ch,
3008 loading->base.order + 4 * j),
3009 loading->file, "map.b%02d_%04d", j);
3010 } halfbyte_iterate_bases_end;
3013 /****************************************************************************
3014 Load roads to map
3015 ****************************************************************************/
3016 static void sg_load_map_tiles_roads(struct loaddata *loading)
3018 /* Check status and return if not OK (sg_success != TRUE). */
3019 sg_check_ret();
3021 /* Load roads. */
3022 halfbyte_iterate_roads(j, loading->road.size) {
3023 LOAD_MAP_CHAR(ch, ptile, sg_roads_set(&ptile->extras, ch,
3024 loading->road.order + 4 * j),
3025 loading->file, "map.r%02d_%04d", j);
3026 } halfbyte_iterate_roads_end;
3029 /****************************************************************************
3030 Load information about specials on map
3031 ****************************************************************************/
3032 static void sg_load_map_tiles_specials(struct loaddata *loading,
3033 bool rivers_overlay)
3035 /* Check status and return if not OK (sg_success != TRUE). */
3036 sg_check_ret();
3038 /* If 'rivers_overlay' is set to TRUE, load only the rivers overlay map
3039 * from the savegame file.
3041 * A scenario may define the terrain of the map but not list the specials
3042 * on it (thus allowing users to control the placement of specials).
3043 * However rivers are a special case and must be included in the map along
3044 * with the scenario. Thus in those cases this function should be called
3045 * to load the river information separate from any other special data.
3047 * This does not need to be called from map_load(), because map_load()
3048 * loads the rivers overlay along with the rest of the specials. Call this
3049 * only if you've already called map_load_tiles(), and want to load only
3050 * the rivers overlay but no other specials. Scenarios that encode things
3051 * this way should have the "riversoverlay" capability. */
3052 halfbyte_iterate_special(j, loading->special.size) {
3053 LOAD_MAP_CHAR(ch, ptile, sg_special_set(ptile, &ptile->extras, ch,
3054 loading->special.order + 4 * j,
3055 rivers_overlay),
3056 loading->file, "map.spe%02d_%04d", j);
3057 } halfbyte_iterate_special_end;
3060 /****************************************************************************
3061 Load information about resources on map.
3062 ****************************************************************************/
3063 static void sg_load_map_tiles_resources(struct loaddata *loading)
3065 /* Check status and return if not OK (sg_success != TRUE). */
3066 sg_check_ret();
3068 LOAD_MAP_CHAR(ch, ptile, ptile->resource = char2resource(ch),
3069 loading->file, "map.res%04d");
3071 /* After the resources are loaded, indicate those currently valid. */
3072 whole_map_iterate(ptile) {
3073 if (NULL == ptile->resource || NULL == ptile->terrain) {
3074 continue;
3077 if (terrain_has_resource(ptile->terrain, ptile->resource)) {
3078 /* cannot use set_special() for internal values */
3079 ptile->resource_valid = TRUE;
3081 } whole_map_iterate_end;
3083 game.map.server.have_resources = TRUE;
3084 game.scenario.have_resources = TRUE;
3087 /****************************************************************************
3088 Load information about resources on map.
3089 ****************************************************************************/
3090 static void sg_save_map_tiles_resources(struct savedata *saving)
3092 /* Check status and return if not OK (sg_success != TRUE). */
3093 sg_check_ret();
3095 SAVE_MAP_CHAR(ptile, resource2char(ptile->resource), saving->file,
3096 "map.res%04d");
3099 /****************************************************************************
3100 Load starting positions for the players from a savegame file. There should
3101 be at least enough for every player.
3102 ****************************************************************************/
3103 static void sg_load_map_startpos(struct loaddata *loading)
3105 struct nation_type *pnation;
3106 struct startpos *psp;
3107 struct tile *ptile;
3108 const char SEPARATOR = '#';
3109 const char *nation_names;
3110 int nat_x, nat_y;
3111 bool exclude;
3112 int i, startpos_count;
3114 /* Check status and return if not OK (sg_success != TRUE). */
3115 sg_check_ret();
3117 startpos_count
3118 = secfile_lookup_int_default(loading->file, 0, "map.startpos_count");
3120 if (0 == startpos_count) {
3121 /* Nothing to do. */
3122 return;
3125 for (i = 0; i < startpos_count; i++) {
3126 if (!secfile_lookup_int(loading->file, &nat_x, "map.startpos%d.x", i)
3127 || !secfile_lookup_int(loading->file, &nat_y,
3128 "map.startpos%d.y", i)) {
3129 log_sg("Warning: Undefined coordinates for startpos %d", i);
3130 continue;
3133 ptile = native_pos_to_tile(nat_x, nat_y);
3134 if (NULL == ptile) {
3135 log_error("Start position native coordinates (%d, %d) do not exist "
3136 "in this map. Skipping...", nat_x, nat_y);
3137 continue;
3140 exclude = secfile_lookup_bool_default(loading->file, FALSE,
3141 "map.startpos%d.exclude", i);
3143 psp = map_startpos_new(ptile);
3145 nation_names = secfile_lookup_str(loading->file,
3146 "map.startpos%d.nations", i);
3147 if (NULL != nation_names && '\0' != nation_names[0]) {
3148 const size_t size = strlen(nation_names) + 1;
3149 char buf[size], *start, *end;
3151 memcpy(buf, nation_names, size);
3152 for (start = buf - 1; NULL != start; start = end) {
3153 start++;
3154 if ((end = strchr(start, SEPARATOR))) {
3155 *end = '\0';
3158 pnation = nation_by_rule_name(start);
3159 if (NO_NATION_SELECTED != pnation) {
3160 if (exclude) {
3161 startpos_disallow(psp, pnation);
3162 } else {
3163 startpos_allow(psp, pnation);
3165 } else {
3166 log_verbose("Missing nation \"%s\".", start);
3172 if (0 < map_startpos_count()
3173 && loading->server_state == S_S_INITIAL
3174 && map_startpos_count() < game.server.max_players) {
3175 log_verbose("Number of starts (%d) are lower than rules.max_players "
3176 "(%d), lowering rules.max_players.",
3177 map_startpos_count(), game.server.max_players);
3178 game.server.max_players = map_startpos_count();
3181 /* Re-initialize nation availability in light of start positions.
3182 * This has to be after loading [scenario] and [map].startpos and
3183 * before we seek nations for players. */
3184 update_nations_with_startpos();
3187 /****************************************************************************
3188 Save the map start positions.
3189 ****************************************************************************/
3190 static void sg_save_map_startpos(struct savedata *saving)
3192 struct tile *ptile;
3193 const char SEPARATOR = '#';
3194 int i = 0;
3196 /* Check status and return if not OK (sg_success != TRUE). */
3197 sg_check_ret();
3199 if (!game.server.save_options.save_starts) {
3200 return;
3203 secfile_insert_int(saving->file, map_startpos_count(),
3204 "map.startpos_count");
3206 map_startpos_iterate(psp) {
3207 int nat_x, nat_y;
3209 ptile = startpos_tile(psp);
3211 index_to_native_pos(&nat_x, &nat_y, tile_index(ptile));
3212 secfile_insert_int(saving->file, nat_x, "map.startpos%d.x", i);
3213 secfile_insert_int(saving->file, nat_y, "map.startpos%d.y", i);
3215 secfile_insert_bool(saving->file, startpos_is_excluding(psp),
3216 "map.startpos%d.exclude", i);
3217 if (startpos_allows_all(psp)) {
3218 secfile_insert_str(saving->file, "", "map.startpos%d.nations", i);
3219 } else {
3220 const struct nation_hash *nations = startpos_raw_nations(psp);
3221 char nation_names[MAX_LEN_NAME * nation_hash_size(nations)];
3223 nation_names[0] = '\0';
3224 nation_hash_iterate(nations, pnation) {
3225 if ('\0' == nation_names[0]) {
3226 fc_strlcpy(nation_names, nation_rule_name(pnation),
3227 sizeof(nation_names));
3228 } else {
3229 cat_snprintf(nation_names, sizeof(nation_names),
3230 "%c%s", SEPARATOR, nation_rule_name(pnation));
3232 } nation_hash_iterate_end;
3233 secfile_insert_str(saving->file, nation_names,
3234 "map.startpos%d.nations", i);
3236 i++;
3237 } map_startpos_iterate_end;
3239 fc_assert(map_startpos_count() == i);
3242 /****************************************************************************
3243 Load tile owner information
3244 ****************************************************************************/
3245 static void sg_load_map_owner(struct loaddata *loading)
3247 int x, y;
3248 struct player *owner = NULL;
3249 struct tile *claimer = NULL;
3250 struct player *eowner = NULL;
3252 /* Check status and return if not OK (sg_success != TRUE). */
3253 sg_check_ret();
3255 if (game.info.is_new_game) {
3256 /* No owner/source information for a new game / scenario. */
3257 return;
3260 /* Owner and ownership source are stored as plain numbers */
3261 for (y = 0; y < game.map.ysize; y++) {
3262 const char *buffer1 = secfile_lookup_str(loading->file,
3263 "map.owner%04d", y);
3264 const char *buffer2 = secfile_lookup_str(loading->file,
3265 "map.source%04d", y);
3266 const char *buffer3 = secfile_lookup_str(loading->file,
3267 "map.eowner%04d", y);
3268 const char *ptr1 = buffer1;
3269 const char *ptr2 = buffer2;
3270 const char *ptr3 = buffer3;
3272 sg_failure_ret(buffer1 != NULL, "%s", secfile_error());
3273 sg_failure_ret(buffer2 != NULL, "%s", secfile_error());
3274 if (loading->version >= 30) {
3275 sg_failure_ret(buffer3 != NULL, "%s", secfile_error());
3278 for (x = 0; x < game.map.xsize; x++) {
3279 char token1[TOKEN_SIZE];
3280 char token2[TOKEN_SIZE];
3281 char token3[TOKEN_SIZE];
3282 int number;
3283 struct tile *ptile = native_pos_to_tile(x, y);
3285 scanin(&ptr1, ",", token1, sizeof(token1));
3286 sg_failure_ret(token1[0] != '\0',
3287 "Map size not correct (map.owner%d).", y);
3288 if (strcmp(token1, "-") == 0) {
3289 owner = NULL;
3290 } else {
3291 sg_failure_ret(str_to_int(token1, &number),
3292 "Got map owner %s in (%d, %d).", token1, x, y);
3293 owner = player_by_number(number);
3296 scanin(&ptr2, ",", token2, sizeof(token2));
3297 sg_failure_ret(token2[0] != '\0',
3298 "Map size not correct (map.source%d).", y);
3299 if (strcmp(token2, "-") == 0) {
3300 claimer = NULL;
3301 } else {
3302 sg_failure_ret(str_to_int(token2, &number),
3303 "Got map source %s in (%d, %d).", token2, x, y);
3304 claimer = index_to_tile(number);
3307 if (loading->version >= 30) {
3308 scanin(&ptr3, ",", token3, sizeof(token3));
3309 sg_failure_ret(token3[0] != '\0',
3310 "Map size not correct (map.eowner%d).", y);
3311 if (strcmp(token3, "-") == 0) {
3312 eowner = NULL;
3313 } else {
3314 sg_failure_ret(str_to_int(token3, &number),
3315 "Got base owner %s in (%d, %d).", token3, x, y);
3316 eowner = player_by_number(number);
3318 } else {
3319 eowner = owner;
3322 map_claim_ownership(ptile, owner, claimer, FALSE);
3323 tile_claim_bases(ptile, eowner);
3324 log_debug("extras_owner(%d, %d) = %s", TILE_XY(ptile), player_name(eowner));
3329 /****************************************************************************
3330 Save tile owner information
3331 ****************************************************************************/
3332 static void sg_save_map_owner(struct savedata *saving)
3334 int x, y;
3336 /* Check status and return if not OK (sg_success != TRUE). */
3337 sg_check_ret();
3339 if (saving->scenario && !saving->save_players) {
3340 /* Nothing to do for a scenario without saved players. */
3341 return;
3344 /* Store owner and ownership source as plain numbers. */
3345 for (y = 0; y < game.map.ysize; y++) {
3346 char line[game.map.xsize * TOKEN_SIZE];
3348 line[0] = '\0';
3349 for (x = 0; x < game.map.xsize; x++) {
3350 char token[TOKEN_SIZE];
3351 struct tile *ptile = native_pos_to_tile(x, y);
3353 if (!saving->save_players || tile_owner(ptile) == NULL) {
3354 strcpy(token, "-");
3355 } else {
3356 fc_snprintf(token, sizeof(token), "%d",
3357 player_number(tile_owner(ptile)));
3359 strcat(line, token);
3360 if (x + 1 < game.map.xsize) {
3361 strcat(line, ",");
3364 secfile_insert_str(saving->file, line, "map.owner%04d", y);
3367 for (y = 0; y < game.map.ysize; y++) {
3368 char line[game.map.xsize * TOKEN_SIZE];
3370 line[0] = '\0';
3371 for (x = 0; x < game.map.xsize; x++) {
3372 char token[TOKEN_SIZE];
3373 struct tile *ptile = native_pos_to_tile(x, y);
3375 if (ptile->claimer == NULL) {
3376 strcpy(token, "-");
3377 } else {
3378 fc_snprintf(token, sizeof(token), "%d", tile_index(ptile->claimer));
3380 strcat(line, token);
3381 if (x + 1 < game.map.xsize) {
3382 strcat(line, ",");
3385 secfile_insert_str(saving->file, line, "map.source%04d", y);
3388 for (y = 0; y < game.map.ysize; y++) {
3389 char line[game.map.xsize * TOKEN_SIZE];
3391 line[0] = '\0';
3392 for (x = 0; x < game.map.xsize; x++) {
3393 char token[TOKEN_SIZE];
3394 struct tile *ptile = native_pos_to_tile(x, y);
3396 if (!saving->save_players || extra_owner(ptile) == NULL) {
3397 strcpy(token, "-");
3398 } else {
3399 fc_snprintf(token, sizeof(token), "%d",
3400 player_number(extra_owner(ptile)));
3402 strcat(line, token);
3403 if (x + 1 < game.map.xsize) {
3404 strcat(line, ",");
3407 secfile_insert_str(saving->file, line, "map.eowner%04d", y);
3411 /****************************************************************************
3412 Load worked tiles information
3413 ****************************************************************************/
3414 static void sg_load_map_worked(struct loaddata *loading)
3416 int x, y;
3418 /* Check status and return if not OK (sg_success != TRUE). */
3419 sg_check_ret();
3421 sg_failure_ret(loading->worked_tiles == NULL,
3422 "City worked map not loaded!");
3424 loading->worked_tiles = fc_malloc(MAP_INDEX_SIZE *
3425 sizeof(*loading->worked_tiles));
3427 for (y = 0; y < game.map.ysize; y++) {
3428 const char *buffer = secfile_lookup_str(loading->file, "map.worked%04d",
3430 const char *ptr = buffer;
3432 sg_failure_ret(NULL != buffer,
3433 "Savegame corrupt - map line %d not found.", y);
3434 for (x = 0; x < game.map.xsize; x++) {
3435 char token[TOKEN_SIZE];
3436 int number;
3437 struct tile *ptile = native_pos_to_tile(x, y);
3439 scanin(&ptr, ",", token, sizeof(token));
3440 sg_failure_ret('\0' != token[0],
3441 "Savegame corrupt - map size not correct.");
3442 if (strcmp(token, "-") == 0) {
3443 number = -1;
3444 } else {
3445 sg_failure_ret(str_to_int(token, &number) && 0 < number,
3446 "Savegame corrupt - got tile worked by city "
3447 "id=%s in (%d, %d).", token, x, y);
3450 loading->worked_tiles[ptile->index] = number;
3455 /****************************************************************************
3456 Save worked tiles information
3457 ****************************************************************************/
3458 static void sg_save_map_worked(struct savedata *saving)
3460 int x, y;
3462 /* Check status and return if not OK (sg_success != TRUE). */
3463 sg_check_ret();
3465 if (saving->scenario && !saving->save_players) {
3466 /* Nothing to do for a scenario without saved players. */
3467 return;
3470 /* additionally save the tiles worked by the cities */
3471 for (y = 0; y < game.map.ysize; y++) {
3472 char line[game.map.xsize * TOKEN_SIZE];
3474 line[0] = '\0';
3475 for (x = 0; x < game.map.xsize; x++) {
3476 char token[TOKEN_SIZE];
3477 struct tile *ptile = native_pos_to_tile(x, y);
3478 struct city *pcity = tile_worked(ptile);
3480 if (pcity == NULL) {
3481 strcpy(token, "-");
3482 } else {
3483 fc_snprintf(token, sizeof(token), "%d", pcity->id);
3485 strcat(line, token);
3486 if (x < game.map.xsize) {
3487 strcat(line, ",");
3490 secfile_insert_str(saving->file, line, "map.worked%04d", y);
3494 /****************************************************************************
3495 Load tile known status
3496 ****************************************************************************/
3497 static void sg_load_map_known(struct loaddata *loading)
3499 /* Check status and return if not OK (sg_success != TRUE). */
3500 sg_check_ret();
3502 players_iterate(pplayer) {
3503 /* Allocate player private map here; it is needed in different modules
3504 * besides this one ((i.e. sg_load_player_*()). */
3505 player_map_init(pplayer);
3506 } players_iterate_end;
3508 if (secfile_lookup_bool_default(loading->file, TRUE,
3509 "game.save_known")) {
3510 int lines = player_slot_max_used_number()/32 + 1, j, p, l, i;
3511 unsigned int *known = fc_calloc(lines * MAP_INDEX_SIZE, sizeof(*known));
3513 for (l = 0; l < lines; l++) {
3514 for (j = 0; j < 8; j++) {
3515 for (i = 0; i < 4; i++) {
3516 /* Only bother trying to load the map for this halfbyte if at least
3517 * one of the corresponding player slots is in use. */
3518 if (player_slot_is_used(player_slot_by_number(l*32 + j*4 + i))) {
3519 LOAD_MAP_CHAR(ch, ptile,
3520 known[l * MAP_INDEX_SIZE + tile_index(ptile)]
3521 |= ascii_hex2bin(ch, j),
3522 loading->file, "map.k%02d_%04d", l * 8 + j);
3523 break;
3529 players_iterate(pplayer) {
3530 dbv_clr_all(&pplayer->tile_known);
3531 } players_iterate_end;
3533 /* HACK: we read the known data from hex into 32-bit integers, and
3534 * now we convert it to the known tile data of each player. */
3535 whole_map_iterate(ptile) {
3536 players_iterate(pplayer) {
3537 p = player_index(pplayer);
3538 l = player_index(pplayer) / 32;
3540 if (known[l * MAP_INDEX_SIZE + tile_index(ptile)] & (1u << (p % 32))) {
3541 map_set_known(ptile, pplayer);
3543 } players_iterate_end;
3544 } whole_map_iterate_end;
3546 FC_FREE(known);
3550 /****************************************************************************
3551 Save tile known status for whole map and all players
3552 ****************************************************************************/
3553 static void sg_save_map_known(struct savedata *saving)
3555 /* Check status and return if not OK (sg_success != TRUE). */
3556 sg_check_ret();
3558 if (!saving->save_players) {
3559 secfile_insert_bool(saving->file, FALSE, "game.save_known");
3560 return;
3561 } else {
3562 int lines = player_slot_max_used_number()/32 + 1;
3564 secfile_insert_bool(saving->file, game.server.save_options.save_known,
3565 "game.save_known");
3566 if (game.server.save_options.save_known) {
3567 int j, p, l, i;
3568 unsigned int *known = fc_calloc(lines * MAP_INDEX_SIZE, sizeof(*known));
3570 /* HACK: we convert the data into a 32-bit integer, and then save it as
3571 * hex. */
3573 whole_map_iterate(ptile) {
3574 players_iterate(pplayer) {
3575 if (map_is_known(ptile, pplayer)) {
3576 p = player_index(pplayer);
3577 l = p / 32;
3578 known[l * MAP_INDEX_SIZE + tile_index(ptile)]
3579 |= (1u << (p % 32)); /* "p % 32" = "p - l * 32" */
3581 } players_iterate_end;
3582 } whole_map_iterate_end;
3584 for (l = 0; l < lines; l++) {
3585 for (j = 0; j < 8; j++) {
3586 for (i = 0; i < 4; i++) {
3587 /* Only bother saving the map for this halfbyte if at least one
3588 * of the corresponding player slots is in use */
3589 if (player_slot_is_used(player_slot_by_number(l*32 + j*4 + i))) {
3590 /* put 4-bit segments of the 32-bit "known" field */
3591 SAVE_MAP_CHAR(ptile, bin2ascii_hex(known[l * MAP_INDEX_SIZE
3592 + tile_index(ptile)], j),
3593 saving->file, "map.k%02d_%04d", l * 8 + j);
3594 break;
3600 FC_FREE(known);
3605 /* =======================================================================
3606 * Load / save player data.
3608 * This is splitted into two parts as some data can only be loaded if the
3609 * number of players is known and the corresponding player slots are
3610 * defined.
3611 * ======================================================================= */
3613 /****************************************************************************
3614 Load '[player]' (basic data).
3615 ****************************************************************************/
3616 static void sg_load_players_basic(struct loaddata *loading)
3618 int i, k, nplayers;
3619 const char *string;
3620 bool shuffle_loaded = TRUE;
3622 /* Check status and return if not OK (sg_success != TRUE). */
3623 sg_check_ret();
3625 if (S_S_INITIAL == loading->server_state
3626 || game.info.is_new_game) {
3627 /* Nothing more to do. */
3628 return;
3631 /* Load destroyed wonders: */
3632 string = secfile_lookup_str(loading->file,
3633 "players.destroyed_wonders");
3634 sg_failure_ret(string != NULL, "%s", secfile_error());
3635 sg_failure_ret(strlen(string) == loading->improvement.size,
3636 "Invalid length for 'players.destroyed_wonders' "
3637 "(%lu ~= %lu)", (unsigned long) strlen(string),
3638 (unsigned long) loading->improvement.size);
3639 for (k = 0; k < loading->improvement.size; k++) {
3640 sg_failure_ret(string[k] == '1' || string[k] == '0',
3641 "Undefined value '%c' within "
3642 "'players.destroyed_wonders'.", string[k]);
3644 if (string[k] == '1') {
3645 struct impr_type *pimprove =
3646 improvement_by_rule_name(loading->improvement.order[k]);
3647 if (pimprove) {
3648 game.info.great_wonder_owners[improvement_index(pimprove)]
3649 = WONDER_DESTROYED;
3654 server.identity_number
3655 = secfile_lookup_int_default(loading->file, server.identity_number,
3656 "players.identity_number_used");
3658 /* First remove all defined players. */
3659 players_iterate(pplayer) {
3660 server_remove_player(pplayer);
3661 } players_iterate_end;
3663 /* Now, load the players from the savefile. */
3664 player_slots_iterate(pslot) {
3665 struct player *pplayer;
3666 struct rgbcolor *prgbcolor = NULL;
3667 int pslot_id = player_slot_index(pslot);
3669 if (NULL == secfile_section_lookup(loading->file, "player%d",
3670 pslot_id)) {
3671 continue;
3674 /* Get player AI type. */
3675 string = secfile_lookup_str(loading->file, "player%d.ai_type",
3676 player_slot_index(pslot));
3677 sg_failure_ret(string != NULL, "%s", secfile_error());
3679 /* Get player color */
3680 if (!rgbcolor_load(loading->file, &prgbcolor, "player%d.color",
3681 pslot_id)) {
3682 if (loading->version >= 10 && game_was_started()) {
3683 /* 2.4.0 or later savegame. This is not an error in 2.3 savefiles,
3684 * as they predate the introduction of configurable player colors. */
3685 log_sg("Game has started, yet player %d has no color defined.",
3686 pslot_id);
3687 /* This will be fixed up later */
3688 } else {
3689 log_verbose("No color defined for player %d.", pslot_id);
3690 /* Colors will be assigned on game start, or at end of savefile
3691 * loading if game has already started */
3695 /* Create player. */
3696 pplayer = server_create_player(player_slot_index(pslot), string,
3697 prgbcolor, game.scenario.allow_ai_type_fallback);
3698 sg_failure_ret(pplayer != NULL, "Invalid AI type: '%s'!", string);
3700 server_player_init(pplayer, FALSE, FALSE);
3702 /* Free the color definition. */
3703 rgbcolor_destroy(prgbcolor);
3705 /* Multipliers (policies) */
3707 /* First initialise player values with ruleset defaults; this will
3708 * cover any in the ruleset not known when the savefile was created. */
3709 multipliers_iterate(pmul) {
3710 pplayer->multipliers[multiplier_index(pmul)]
3711 = pplayer->multipliers_target[multiplier_index(pmul)] = pmul->def;
3712 } multipliers_iterate_end;
3714 /* Now override with any values from the savefile. */
3715 for (k = 0; k < loading->multiplier.size; k++) {
3716 const struct multiplier *pmul = loading->multiplier.order[k];
3718 if (pmul) {
3719 Multiplier_type_id idx = multiplier_index(pmul);
3720 int val =
3721 secfile_lookup_int_default(loading->file, pmul->def,
3722 "player%d.multiplier%d.val",
3723 player_slot_index(pslot), k);
3724 int rval = (((CLIP(pmul->start, val, pmul->stop)
3725 - pmul->start) / pmul->step) * pmul->step) + pmul->start;
3727 if (rval != val) {
3728 log_verbose("Player %d had illegal value for multiplier \"%s\": "
3729 "was %d, clamped to %d", pslot_id,
3730 multiplier_rule_name(pmul), val, rval);
3732 pplayer->multipliers[idx] = rval;
3734 val =
3735 secfile_lookup_int_default(loading->file,
3736 pplayer->multipliers[idx],
3737 "player%d.multiplier%d.target",
3738 player_slot_index(pslot), k);
3739 rval = (((CLIP(pmul->start, val, pmul->stop)
3740 - pmul->start) / pmul->step) * pmul->step) + pmul->start;
3742 if (rval != val) {
3743 log_verbose("Player %d had illegal value for multiplier_target "
3744 "\"%s\": was %d, clamped to %d", pslot_id,
3745 multiplier_rule_name(pmul), val, rval);
3747 pplayer->multipliers_target[idx] = rval;
3748 } /* else silently discard multiplier not in current ruleset */
3750 } player_slots_iterate_end;
3752 /* check number of players */
3753 nplayers = secfile_lookup_int_default(loading->file, 0, "players.nplayers");
3754 sg_failure_ret(player_count() == nplayers, "The value of players.nplayers "
3755 "(%d) from the loaded game does not match the number of "
3756 "players present (%d).", nplayers, player_count());
3758 /* Load team informations. */
3759 players_iterate(pplayer) {
3760 int team;
3761 struct team_slot *tslot = NULL;
3763 sg_failure_ret(secfile_lookup_int(loading->file, &team,
3764 "player%d.team_no",
3765 player_number(pplayer))
3766 && (tslot = team_slot_by_number(team)),
3767 "Invalid team definition for player %s (nb %d).",
3768 player_name(pplayer), player_number(pplayer));
3769 team_add_player(pplayer, team_new(tslot));
3770 } players_iterate_end;
3772 /* Loading the shuffle list is quite complex. At the time of saving the
3773 * shuffle data is saved as
3774 * shuffled_player_<number> = player_slot_id
3775 * where number is an increasing number and player_slot_id is a number
3776 * between 0 and the maximum number of player slots. Now we have to create
3777 * a list
3778 * shuffler_players[number] = player_slot_id
3779 * where all player slot IDs are used exactly one time. The code below
3780 * handles this ... */
3781 if (secfile_lookup_int_default(loading->file, -1,
3782 "players.shuffled_player_%d", 0) >= 0) {
3783 int shuffled_players[player_slot_count()];
3784 bool shuffled_player_set[player_slot_count()];
3786 player_slots_iterate(pslot) {
3787 int plrid = player_slot_index(pslot);
3789 /* Array to save used numbers. */
3790 shuffled_player_set[plrid] = FALSE;
3791 /* List of all player IDs (needed for set_shuffled_players()). It is
3792 * initialised with the value -1 to indicate that no value is set. */
3793 shuffled_players[plrid] = -1;
3794 } player_slots_iterate_end;
3796 /* Load shuffled player list. */
3797 for (i = 0; i < player_count(); i++){
3798 int shuffle
3799 = secfile_lookup_int_default(loading->file, -1,
3800 "players.shuffled_player_%d", i);
3802 if (shuffle == -1) {
3803 log_sg("Missing player shuffle information (index %d) "
3804 "- reshuffle player list!", i);
3805 shuffle_loaded = FALSE;
3806 break;
3807 } else if (shuffled_player_set[shuffle]) {
3808 log_sg("Player shuffle %d used two times "
3809 "- reshuffle player list!", shuffle);
3810 shuffle_loaded = FALSE;
3811 break;
3813 /* Set this ID as used. */
3814 shuffled_player_set[shuffle] = TRUE;
3816 /* Save the player ID in the shuffle list. */
3817 shuffled_players[i] = shuffle;
3820 if (shuffle_loaded) {
3821 /* Insert missing numbers. */
3822 int shuffle_index = player_count();
3823 for (i = 0; i < player_slot_count(); i++){
3824 if (!shuffled_player_set[i]) {
3825 shuffled_players[shuffle_index] = i;
3826 shuffle_index++;
3828 /* shuffle_index must not grow behind the size of shuffled_players. */
3829 sg_failure_ret(shuffle_index <= player_slot_count(),
3830 "Invalid player shuffle data!");
3833 #ifdef DEBUG
3834 log_debug("[load shuffle] player_count() = %d", player_count());
3835 player_slots_iterate(pslot) {
3836 int plrid = player_slot_index(pslot);
3837 log_debug("[load shuffle] id: %3d => slot: %3d | slot %3d: %s",
3838 plrid, shuffled_players[plrid], plrid,
3839 shuffled_player_set[plrid] ? "is used" : "-");
3840 } player_slots_iterate_end;
3841 #endif /* DEBUG */
3843 /* Set shuffle list from savegame. */
3844 set_shuffled_players(shuffled_players);
3848 if (!shuffle_loaded) {
3849 /* No shuffled players included or error loading them, so shuffle them
3850 * (this may include scenarios). */
3851 shuffle_players();
3855 /****************************************************************************
3856 Load '[player]'.
3857 ****************************************************************************/
3858 static void sg_load_players(struct loaddata *loading)
3860 /* Check status and return if not OK (sg_success != TRUE). */
3861 sg_check_ret();
3863 if (game.info.is_new_game) {
3864 /* Nothing to do. */
3865 return;
3868 players_iterate(pplayer) {
3869 sg_load_player_main(loading, pplayer);
3870 sg_load_player_cities(loading, pplayer);
3871 sg_load_player_units(loading, pplayer);
3872 sg_load_player_attributes(loading, pplayer);
3874 /* Check the sucess of the functions above. */
3875 sg_check_ret();
3877 /* print out some informations */
3878 if (pplayer->ai_controlled) {
3879 log_normal(_("%s has been added as %s level AI-controlled player "
3880 "(%s)."), player_name(pplayer),
3881 ai_level_translated_name(pplayer->ai_common.skill_level),
3882 ai_name(pplayer->ai));
3883 } else {
3884 log_normal(_("%s has been added as human player."),
3885 player_name(pplayer));
3887 } players_iterate_end;
3889 /* Also load the transport status of the units here. It must be a special
3890 * case as all units must be known (unit on an allied transporter). */
3891 players_iterate(pplayer) {
3892 /* Load unit transport status. */
3893 sg_load_player_units_transport(loading, pplayer);
3894 } players_iterate_end;
3896 /* Savegame may contain nation assignments that are incompatible with the
3897 * current nationset -- for instance, if it predates the introduction of
3898 * nationsets. Ensure they are compatible, one way or another. */
3899 fit_nationset_to_players();
3901 /* Some players may have invalid nations in the ruleset. Once all players
3902 * are loaded, pick one of the remaining nations for them. */
3903 players_iterate(pplayer) {
3904 if (pplayer->nation == NO_NATION_SELECTED) {
3905 player_set_nation(pplayer, pick_a_nation(NULL, FALSE, TRUE,
3906 NOT_A_BARBARIAN));
3907 /* TRANS: Minor error message: <Leader> ... <Poles>. */
3908 log_sg(_("%s had invalid nation; changing to %s."),
3909 player_name(pplayer), nation_plural_for_player(pplayer));
3911 ai_traits_init(pplayer);
3913 } players_iterate_end;
3915 /* Sanity check alliances, prevent allied-with-ally-of-enemy. */
3916 players_iterate_alive(plr) {
3917 players_iterate_alive(aplayer) {
3918 if (pplayers_allied(plr, aplayer)) {
3919 enum dipl_reason can_ally = pplayer_can_make_treaty(plr, aplayer,
3920 DS_ALLIANCE);
3921 if (can_ally == DIPL_ALLIANCE_PROBLEM_US
3922 || can_ally == DIPL_ALLIANCE_PROBLEM_THEM) {
3923 log_sg("Illegal alliance structure detected: "
3924 "%s alliance to %s reduced to peace treaty.",
3925 nation_rule_name(nation_of_player(plr)),
3926 nation_rule_name(nation_of_player(aplayer)));
3927 player_diplstate_get(plr, aplayer)->type = DS_PEACE;
3928 player_diplstate_get(aplayer, plr)->type = DS_PEACE;
3931 } players_iterate_alive_end;
3932 } players_iterate_alive_end;
3934 /* Update cached city illness. This can depend on trade routes,
3935 * so can't be calculated until all players have been loaded. */
3936 if (game.info.illness_on) {
3937 cities_iterate(pcity) {
3938 pcity->server.illness
3939 = city_illness_calc(pcity, NULL, NULL,
3940 &(pcity->illness_trade), NULL);
3941 } cities_iterate_end;
3944 /* Update all city information. This must come after all cities are
3945 * loaded (in player_load) but before player (dumb) cities are loaded
3946 * in player_load_vision(). */
3947 players_iterate(plr) {
3948 city_list_iterate(plr->cities, pcity) {
3949 city_refresh(pcity);
3950 sanity_check_city(pcity);
3951 CALL_PLR_AI_FUNC(city_got, plr, plr, pcity);
3952 } city_list_iterate_end;
3953 } players_iterate_end;
3955 /* Since the cities must be placed on the map to put them on the
3956 player map we do this afterwards */
3957 players_iterate(pplayer) {
3958 sg_load_player_vision(loading, pplayer);
3959 /* Check the sucess of the function above. */
3960 sg_check_ret();
3961 } players_iterate_end;
3963 /* Check shared vision. */
3964 players_iterate(pplayer) {
3965 BV_CLR_ALL(pplayer->gives_shared_vision);
3966 BV_CLR_ALL(pplayer->server.really_gives_vision);
3967 } players_iterate_end;
3969 players_iterate(pplayer) {
3970 int plr1 = player_index(pplayer);
3972 players_iterate(pplayer2) {
3973 int plr2 = player_index(pplayer2);
3974 if (secfile_lookup_bool_default(loading->file, FALSE,
3975 "player%d.diplstate%d.gives_shared_vision", plr1, plr2)) {
3976 give_shared_vision(pplayer, pplayer2);
3978 } players_iterate_end;
3979 } players_iterate_end;
3981 initialize_globals();
3982 unit_ordering_apply();
3984 /* All vision is ready; this calls city_thaw_workers_queue(). */
3985 map_calculate_borders();
3987 /* Make sure everything is consistent. */
3988 players_iterate(pplayer) {
3989 unit_list_iterate(pplayer->units, punit) {
3990 if (!can_unit_continue_current_activity(punit)) {
3991 log_sg("Unit doing illegal activity in savegame!");
3992 log_sg("Activity: %s, Target: %s",
3993 unit_activity_name(punit->activity),
3994 punit->activity_target ? extra_rule_name(
3995 punit->activity_target)
3996 : "missing");
3997 punit->activity = ACTIVITY_IDLE;
3999 } unit_list_iterate_end;
4000 } players_iterate_end;
4002 cities_iterate(pcity) {
4003 city_refresh(pcity);
4004 city_thaw_workers(pcity); /* may auto_arrange_workers() */
4005 } cities_iterate_end;
4007 /* Player colors are always needed once game has started. Pre-2.4 savegames
4008 * lack them. This cannot be in compatibility conversion layer as we need
4009 * all the player data available to be able to assign best colors. */
4010 if (game_was_started()) {
4011 assign_player_colors();
4015 /****************************************************************************
4016 Save '[player]'.
4017 ****************************************************************************/
4018 static void sg_save_players(struct savedata *saving)
4020 /* Check status and return if not OK (sg_success != TRUE). */
4021 sg_check_ret();
4023 if ((saving->scenario && !saving->save_players)
4024 || !game_was_started()) {
4025 /* Nothing to do for a scenario without saved players or a game in
4026 * INITIAL state. */
4027 return;
4030 secfile_insert_int(saving->file, player_count(), "players.nplayers");
4032 /* Save destroyed wonders as bitvector. Note that improvement order
4033 * is saved in 'savefile.improvement.order'. */
4035 char destroyed[B_LAST+1];
4037 improvement_iterate(pimprove) {
4038 if (is_great_wonder(pimprove)
4039 && great_wonder_is_destroyed(pimprove)) {
4040 destroyed[improvement_index(pimprove)] = '1';
4041 } else {
4042 destroyed[improvement_index(pimprove)] = '0';
4044 } improvement_iterate_end;
4045 destroyed[improvement_count()] = '\0';
4046 secfile_insert_str(saving->file, destroyed,
4047 "players.destroyed_wonders");
4050 secfile_insert_int(saving->file, server.identity_number,
4051 "players.identity_number_used");
4053 /* Save player order. */
4055 int i = 0;
4056 shuffled_players_iterate(pplayer) {
4057 secfile_insert_int(saving->file, player_number(pplayer),
4058 "players.shuffled_player_%d", i);
4059 i++;
4060 } shuffled_players_iterate_end;
4063 /* Sort units. */
4064 unit_ordering_calc();
4066 /* Save players. */
4067 players_iterate(pplayer) {
4068 sg_save_player_main(saving, pplayer);
4069 sg_save_player_cities(saving, pplayer);
4070 sg_save_player_units(saving, pplayer);
4071 sg_save_player_attributes(saving, pplayer);
4072 sg_save_player_vision(saving, pplayer);
4073 } players_iterate_end;
4076 /****************************************************************************
4077 Main player data loading function
4078 ****************************************************************************/
4079 static void sg_load_player_main(struct loaddata *loading,
4080 struct player *plr)
4082 int i, plrno = player_number(plr);
4083 const char *string;
4084 struct government *gov;
4085 const char *level;
4086 const char *barb_str;
4088 /* Check status and return if not OK (sg_success != TRUE). */
4089 sg_check_ret();
4091 /* Basic player data. */
4092 string = secfile_lookup_str(loading->file, "player%d.name", plrno);
4093 sg_failure_ret(string != NULL, "%s", secfile_error());
4094 server_player_set_name(plr, string);
4095 sz_strlcpy(plr->username,
4096 secfile_lookup_str_default(loading->file, "",
4097 "player%d.username", plrno));
4098 sg_failure_ret(secfile_lookup_bool(loading->file, &plr->unassigned_user,
4099 "player%d.unassigned_user", plrno),
4100 "%s", secfile_error());
4101 sz_strlcpy(plr->ranked_username,
4102 secfile_lookup_str_default(loading->file, "",
4103 "player%d.ranked_username",
4104 plrno));
4105 sg_failure_ret(secfile_lookup_bool(loading->file, &plr->unassigned_ranked,
4106 "player%d.unassigned_ranked", plrno),
4107 "%s", secfile_error());
4108 string = secfile_lookup_str_default(loading->file, "",
4109 "player%d.delegation_username",
4110 plrno);
4111 /* Defaults to no delegation. */
4112 if (strlen(string)) {
4113 player_delegation_set(plr, string);
4116 /* Nation */
4117 string = secfile_lookup_str(loading->file, "player%d.nation", plrno);
4118 player_set_nation(plr, nation_by_rule_name(string));
4119 if (plr->nation != NULL) {
4120 ai_traits_init(plr);
4123 /* Government */
4124 string = secfile_lookup_str(loading->file, "player%d.government_name",
4125 plrno);
4126 gov = government_by_rule_name(string);
4127 sg_failure_ret(gov != NULL, "Player%d: unsupported government \"%s\".",
4128 plrno, string);
4129 plr->government = gov;
4131 /* Target government */
4132 string = secfile_lookup_str(loading->file,
4133 "player%d.target_government_name", plrno);
4134 if (string) {
4135 plr->target_government = government_by_rule_name(string);
4136 } else {
4137 plr->target_government = NULL;
4139 plr->revolution_finishes
4140 = secfile_lookup_int_default(loading->file, -1,
4141 "player%d.revolution_finishes", plrno);
4143 sg_failure_ret(secfile_lookup_bool(loading->file,
4144 &plr->server.got_first_city,
4145 "player%d.got_first_city", plrno),
4146 "%s", secfile_error());
4148 sg_failure_ret(secfile_lookup_bool(loading->file, &plr->ai_controlled,
4149 "player%d.ai.control", plrno),
4150 "%s", secfile_error());
4152 /* Load diplomatic data (diplstate + embassy + vision).
4153 * Shared vision is loaded in sg_load_players(). */
4154 BV_CLR_ALL(plr->real_embassy);
4155 players_iterate(pplayer) {
4156 char buf[32];
4157 int unconverted;
4158 struct player_diplstate *ds = player_diplstate_get(plr, pplayer);
4159 i = player_index(pplayer);
4161 /* load diplomatic status */
4162 fc_snprintf(buf, sizeof(buf), "player%d.diplstate%d", plrno, i);
4164 unconverted =
4165 secfile_lookup_int_default(loading->file, -1, "%s.type", buf);
4166 if (unconverted >= 0 && unconverted < loading->ds_t.size) {
4167 /* Look up what state the unconverted number represents. */
4168 ds->type = loading->ds_t.order[unconverted];
4169 } else {
4170 log_sg("No valid diplomatic state type between players %d and %d",
4171 plrno, i);
4173 ds->type = DS_WAR;
4176 unconverted =
4177 secfile_lookup_int_default(loading->file, -1, "%s.max_state", buf);
4178 if (unconverted >= 0 && unconverted < loading->ds_t.size) {
4179 /* Look up what state the unconverted number represents. */
4180 ds->max_state = loading->ds_t.order[unconverted];
4181 } else {
4182 log_sg("No valid diplomatic max_state between players %d and %d",
4183 plrno, i);
4185 ds->max_state = DS_WAR;
4188 ds->first_contact_turn =
4189 secfile_lookup_int_default(loading->file, 0,
4190 "%s.first_contact_turn", buf);
4191 ds->turns_left =
4192 secfile_lookup_int_default(loading->file, -2, "%s.turns_left", buf);
4193 ds->has_reason_to_cancel =
4194 secfile_lookup_int_default(loading->file, 0,
4195 "%s.has_reason_to_cancel", buf);
4196 ds->contact_turns_left =
4197 secfile_lookup_int_default(loading->file, 0,
4198 "%s.contact_turns_left", buf);
4200 if (secfile_lookup_bool_default(loading->file, FALSE, "%s.embassy",
4201 buf)) {
4202 BV_SET(plr->real_embassy, i);
4204 /* 'gives_shared_vision' is loaded in sg_load_players() as all cities
4205 * must be known. */
4206 } players_iterate_end;
4208 /* load ai data */
4209 players_iterate(aplayer) {
4210 char buf[32];
4212 fc_snprintf(buf, sizeof(buf), "player%d.ai%d", plrno,
4213 player_index(aplayer));
4215 plr->ai_common.love[player_index(aplayer)] =
4216 secfile_lookup_int_default(loading->file, 1, "%s.love", buf);
4217 CALL_FUNC_EACH_AI(player_load_relations, plr, aplayer, loading->file, plrno);
4218 } players_iterate_end;
4220 CALL_FUNC_EACH_AI(player_load, plr, loading->file, plrno);
4222 /* Some sane defaults */
4223 plr->ai_common.fuzzy = 0;
4224 plr->ai_common.expand = 100;
4225 plr->ai_common.science_cost = 100;
4228 level = secfile_lookup_str_default(loading->file, NULL,
4229 "player%d.ai.level", plrno);
4230 if (level != NULL) {
4231 plr->ai_common.skill_level = ai_level_by_name(level, fc_strcasecmp);
4233 /* In builds where level "Experimental" is not supported, convert it to "Hard" */
4234 if (!ai_level_is_valid(plr->ai_common.skill_level)
4235 && !fc_strcasecmp(level, "Experimental")) {
4236 plr->ai_common.skill_level = AI_LEVEL_HARD;
4238 } else {
4239 plr->ai_common.skill_level = ai_level_invalid();
4242 if (!ai_level_is_valid(plr->ai_common.skill_level)) {
4243 plr->ai_common.skill_level
4244 = ai_level_convert(secfile_lookup_int_default(loading->file,
4245 game.info.skill_level,
4246 "player%d.ai.skill_level",
4247 plrno));
4250 barb_str = secfile_lookup_str_default(loading->file, "None",
4251 "player%d.ai.barb_type", plrno);
4252 plr->ai_common.barbarian_type = barbarian_type_by_name(barb_str, fc_strcasecmp);
4254 if (!barbarian_type_is_valid(plr->ai_common.barbarian_type)) {
4255 log_sg("Player%d: Invalid barbarian type \"%s\". "
4256 "Changed to \"None\".", plrno, barb_str);
4257 plr->ai_common.barbarian_type = NOT_A_BARBARIAN;
4260 if (is_barbarian(plr)) {
4261 server.nbarbarians++;
4264 if (plr->ai_controlled) {
4265 set_ai_level_directer(plr, plr->ai_common.skill_level);
4266 CALL_PLR_AI_FUNC(gained_control, plr, plr);
4269 /* Load nation style. */
4271 struct nation_style *style;
4273 string = secfile_lookup_str(loading->file, "player%d.style_by_name", plrno);
4275 /* Handle pre-2.6 savegames */
4276 if (string == NULL) {
4277 string = secfile_lookup_str(loading->file, "player%d.city_style_by_name",
4278 plrno);
4281 sg_failure_ret(string != NULL, "%s", secfile_error());
4282 style = style_by_rule_name(string);
4283 if (style == NULL) {
4284 style = style_by_number(0);
4285 log_sg("Player%d: unsupported city_style_name \"%s\". "
4286 "Changed to \"%s\".", plrno, string, style_rule_name(style));
4288 plr->style = style;
4291 sg_failure_ret(secfile_lookup_int(loading->file, &plr->nturns_idle,
4292 "player%d.idle_turns", plrno),
4293 "%s", secfile_error());
4294 plr->is_male = secfile_lookup_bool_default(loading->file, TRUE,
4295 "player%d.is_male", plrno);
4296 sg_failure_ret(secfile_lookup_bool(loading->file, &plr->is_alive,
4297 "player%d.is_alive", plrno),
4298 "%s", secfile_error());
4299 sg_failure_ret(secfile_lookup_int(loading->file, &plr->turns_alive,
4300 "player%d.turns_alive", plrno),
4301 "%s", secfile_error());
4302 sg_failure_ret(secfile_lookup_int(loading->file, &plr->last_war_action,
4303 "player%d.last_war", plrno),
4304 "%s", secfile_error());
4305 plr->phase_done = secfile_lookup_bool_default(loading->file, FALSE,
4306 "player%d.phase_done", plrno);
4307 sg_failure_ret(secfile_lookup_int(loading->file, &plr->economic.gold,
4308 "player%d.gold", plrno),
4309 "%s", secfile_error());
4310 sg_failure_ret(secfile_lookup_int(loading->file, &plr->economic.tax,
4311 "player%d.rates.tax", plrno),
4312 "%s", secfile_error());
4313 sg_failure_ret(secfile_lookup_int(loading->file, &plr->economic.science,
4314 "player%d.rates.science", plrno),
4315 "%s", secfile_error());
4316 sg_failure_ret(secfile_lookup_int(loading->file, &plr->economic.luxury,
4317 "player%d.rates.luxury", plrno),
4318 "%s", secfile_error());
4319 plr->server.bulbs_last_turn =
4320 secfile_lookup_int_default(loading->file, 0,
4321 "player%d.research.bulbs_last_turn", plrno);
4323 /* Traits */
4324 if (plr->nation) {
4325 for (i = 0; i < loading->trait.size; i++) {
4326 enum trait tr = trait_by_name(loading->trait.order[i], fc_strcasecmp);
4328 if (trait_is_valid(tr)) {
4329 int val = secfile_lookup_int_default(loading->file, -1, "player%d.trait%d.val",
4330 plrno, i);
4332 if (val != -1) {
4333 plr->ai_common.traits[tr].val = val;
4336 sg_failure_ret(secfile_lookup_int(loading->file, &val,
4337 "player%d.trait%d.mod", plrno, i),
4338 "%s", secfile_error());
4339 plr->ai_common.traits[tr].mod = val;
4344 /* Achievements */
4346 int count;
4348 count = secfile_lookup_int_default(loading->file, -1,
4349 "player%d.achievement_count", plrno);
4351 if (count > 0) {
4352 for (i = 0; i < count; i++) {
4353 const char *name;
4354 struct achievement *pach;
4355 bool first;
4357 name = secfile_lookup_str(loading->file,
4358 "player%d.achievement%d.name", plrno, i);
4359 pach = achievement_by_rule_name(name);
4361 sg_failure_ret(pach != NULL,
4362 "Unknown achievement \"%s\".", name);
4364 sg_failure_ret(secfile_lookup_bool(loading->file, &first,
4365 "player%d.achievement%d.first",
4366 plrno, i),
4367 "achievement error: %s", secfile_error());
4369 sg_failure_ret(pach->first == NULL || !first,
4370 "Multiple players listed as first to get achievement \"%s\".",
4371 name);
4373 BV_SET(pach->achievers, player_index(plr));
4375 if (first) {
4376 pach->first = plr;
4382 /* Player score. */
4383 plr->score.happy =
4384 secfile_lookup_int_default(loading->file, 0,
4385 "score%d.happy", plrno);
4386 plr->score.content =
4387 secfile_lookup_int_default(loading->file, 0,
4388 "score%d.content", plrno);
4389 plr->score.unhappy =
4390 secfile_lookup_int_default(loading->file, 0,
4391 "score%d.unhappy", plrno);
4392 plr->score.angry =
4393 secfile_lookup_int_default(loading->file, 0,
4394 "score%d.angry", plrno);
4396 /* Make sure that the score about specialists in current ruleset that
4397 * were not present at saving time are set to zero. */
4398 specialist_type_iterate(sp) {
4399 plr->score.specialists[sp] = 0;
4400 } specialist_type_iterate_end;
4402 for (i = 0; i < loading->specialist.size; i++) {
4403 plr->score.specialists[specialist_index(loading->specialist.order[i])]
4404 = secfile_lookup_int_default(loading->file, 0,
4405 "score%d.specialist%d", plrno, i);
4408 plr->score.wonders =
4409 secfile_lookup_int_default(loading->file, 0,
4410 "score%d.wonders", plrno);
4411 plr->score.techs =
4412 secfile_lookup_int_default(loading->file, 0,
4413 "score%d.techs", plrno);
4414 plr->score.techout =
4415 secfile_lookup_int_default(loading->file, 0,
4416 "score%d.techout", plrno);
4417 plr->score.landarea =
4418 secfile_lookup_int_default(loading->file, 0,
4419 "score%d.landarea", plrno);
4420 plr->score.settledarea =
4421 secfile_lookup_int_default(loading->file, 0,
4422 "score%d.settledarea", plrno);
4423 plr->score.population =
4424 secfile_lookup_int_default(loading->file, 0,
4425 "score%d.population", plrno);
4426 plr->score.cities =
4427 secfile_lookup_int_default(loading->file, 0,
4428 "score%d.cities", plrno);
4429 plr->score.units =
4430 secfile_lookup_int_default(loading->file, 0,
4431 "score%d.units", plrno);
4432 plr->score.pollution =
4433 secfile_lookup_int_default(loading->file, 0,
4434 "score%d.pollution", plrno);
4435 plr->score.literacy =
4436 secfile_lookup_int_default(loading->file, 0,
4437 "score%d.literacy", plrno);
4438 plr->score.bnp =
4439 secfile_lookup_int_default(loading->file, 0,
4440 "score%d.bnp", plrno);
4441 plr->score.mfg =
4442 secfile_lookup_int_default(loading->file, 0,
4443 "score%d.mfg", plrno);
4444 plr->score.spaceship =
4445 secfile_lookup_int_default(loading->file, 0,
4446 "score%d.spaceship", plrno);
4447 plr->score.units_built =
4448 secfile_lookup_int_default(loading->file, 0,
4449 "score%d.units_built", plrno);
4450 plr->score.units_killed =
4451 secfile_lookup_int_default(loading->file, 0,
4452 "score%d.units_killed", plrno);
4453 plr->score.units_lost =
4454 secfile_lookup_int_default(loading->file, 0,
4455 "score%d.units_lost", plrno);
4456 plr->score.culture =
4457 secfile_lookup_int_default(loading->file, 0,
4458 "score%d.culture", plrno);
4459 plr->score.game =
4460 secfile_lookup_int_default(loading->file, 0,
4461 "score%d.total", plrno);
4463 /* Load space ship data. */
4465 struct player_spaceship *ship = &plr->spaceship;
4466 char prefix[32];
4467 const char *st;
4468 int ei;
4470 fc_snprintf(prefix, sizeof(prefix), "player%d.spaceship", plrno);
4471 spaceship_init(ship);
4472 sg_failure_ret(secfile_lookup_int(loading->file,
4473 &ei,
4474 "%s.state", prefix),
4475 "%s", secfile_error());
4476 ship->state = ei;
4478 if (ship->state != SSHIP_NONE) {
4479 sg_failure_ret(secfile_lookup_int(loading->file, &ship->structurals,
4480 "%s.structurals", prefix),
4481 "%s", secfile_error());
4482 sg_failure_ret(secfile_lookup_int(loading->file, &ship->components,
4483 "%s.components", prefix),
4484 "%s", secfile_error());
4485 sg_failure_ret(secfile_lookup_int(loading->file, &ship->modules,
4486 "%s.modules", prefix),
4487 "%s", secfile_error());
4488 sg_failure_ret(secfile_lookup_int(loading->file, &ship->fuel,
4489 "%s.fuel", prefix),
4490 "%s", secfile_error());
4491 sg_failure_ret(secfile_lookup_int(loading->file, &ship->propulsion,
4492 "%s.propulsion", prefix),
4493 "%s", secfile_error());
4494 sg_failure_ret(secfile_lookup_int(loading->file, &ship->habitation,
4495 "%s.habitation", prefix),
4496 "%s", secfile_error());
4497 sg_failure_ret(secfile_lookup_int(loading->file, &ship->life_support,
4498 "%s.life_support", prefix),
4499 "%s", secfile_error());
4500 sg_failure_ret(secfile_lookup_int(loading->file, &ship->solar_panels,
4501 "%s.solar_panels", prefix),
4502 "%s", secfile_error());
4504 st = secfile_lookup_str(loading->file, "%s.structure", prefix);
4505 sg_failure_ret(st != NULL, "%s", secfile_error())
4506 for (i = 0; i < NUM_SS_STRUCTURALS && st[i]; i++) {
4507 sg_failure_ret(st[i] == '1' || st[i] == '0',
4508 "Undefined value '%c' within '%s.structure'.", st[i],
4509 prefix)
4511 if (!(st[i] == '0')) {
4512 BV_SET(ship->structure, i);
4515 if (ship->state >= SSHIP_LAUNCHED) {
4516 sg_failure_ret(secfile_lookup_int(loading->file, &ship->launch_year,
4517 "%s.launch_year", prefix),
4518 "%s", secfile_error());
4520 spaceship_calc_derived(ship);
4524 /* Load lost wonder data. */
4525 string = secfile_lookup_str(loading->file, "player%d.lost_wonders", plrno);
4526 /* If not present, probably an old savegame; nothing to be done */
4527 if (string) {
4528 int k;
4529 sg_failure_ret(strlen(string) == loading->improvement.size,
4530 "Invalid length for 'player%d.lost_wonders' "
4531 "(%lu ~= %lu)", plrno, (unsigned long) strlen(string),
4532 (unsigned long) loading->improvement.size);
4533 for (k = 0; k < loading->improvement.size; k++) {
4534 sg_failure_ret(string[k] == '1' || string[k] == '0',
4535 "Undefined value '%c' within "
4536 "'player%d.lost_wonders'.", plrno, string[k]);
4538 if (string[k] == '1') {
4539 struct impr_type *pimprove =
4540 improvement_by_rule_name(loading->improvement.order[k]);
4541 if (pimprove) {
4542 plr->wonders[improvement_index(pimprove)] = WONDER_LOST;
4548 plr->culture =
4549 secfile_lookup_int_default(loading->file, 0, "player%d.culture", plrno);
4550 plr->server.huts =
4551 secfile_lookup_int_default(loading->file, 0, "player%d.hut_count", plrno);
4554 /****************************************************************************
4555 Main player data saving function.
4556 ****************************************************************************/
4557 static void sg_save_player_main(struct savedata *saving,
4558 struct player *plr)
4560 int i, k, plrno = player_number(plr);
4561 struct player_spaceship *ship = &plr->spaceship;
4563 /* Check status and return if not OK (sg_success != TRUE). */
4564 sg_check_ret();
4566 secfile_insert_str(saving->file, ai_name(plr->ai),
4567 "player%d.ai_type", plrno);
4568 secfile_insert_str(saving->file, player_name(plr),
4569 "player%d.name", plrno);
4570 secfile_insert_str(saving->file, plr->username,
4571 "player%d.username", plrno);
4572 secfile_insert_bool(saving->file, plr->unassigned_user,
4573 "player%d.unassigned_user", plrno);
4574 if (plr->rgb != NULL) {
4575 rgbcolor_save(saving->file, plr->rgb, "player%d.color", plrno);
4576 } else {
4577 /* Colorless players are ok in pregame */
4578 if (game_was_started()) {
4579 log_sg("Game has started, yet player %d has no color defined.", plrno);
4582 secfile_insert_str(saving->file, plr->ranked_username,
4583 "player%d.ranked_username", plrno);
4584 secfile_insert_bool(saving->file, plr->unassigned_ranked,
4585 "player%d.unassigned_ranked", plrno);
4586 secfile_insert_str(saving->file,
4587 player_delegation_get(plr) ? player_delegation_get(plr)
4588 : "",
4589 "player%d.delegation_username", plrno);
4590 secfile_insert_str(saving->file, nation_rule_name(nation_of_player(plr)),
4591 "player%d.nation", plrno);
4592 secfile_insert_int(saving->file, plr->team ? team_index(plr->team) : -1,
4593 "player%d.team_no", plrno);
4595 secfile_insert_str(saving->file,
4596 government_rule_name(government_of_player(plr)),
4597 "player%d.government_name", plrno);
4599 if (plr->target_government) {
4600 secfile_insert_str(saving->file,
4601 government_rule_name(plr->target_government),
4602 "player%d.target_government_name", plrno);
4605 secfile_insert_str(saving->file, style_rule_name(plr->style),
4606 "player%d.style_by_name", plrno);
4608 secfile_insert_int(saving->file, plr->nturns_idle,
4609 "player%d.idle_turns", plrno);
4610 secfile_insert_bool(saving->file, plr->is_male,
4611 "player%d.is_male", plrno);
4612 secfile_insert_bool(saving->file, plr->is_alive,
4613 "player%d.is_alive", plrno);
4614 secfile_insert_int(saving->file, plr->turns_alive,
4615 "player%d.turns_alive", plrno);
4616 secfile_insert_int(saving->file, plr->last_war_action,
4617 "player%d.last_war", plrno);
4618 secfile_insert_bool(saving->file, plr->ai_controlled,
4619 "player%d.ai.control", plrno);
4620 secfile_insert_bool(saving->file, plr->phase_done,
4621 "player%d.phase_done", plrno);
4623 players_iterate(pplayer) {
4624 char buf[32];
4625 struct player_diplstate *ds = player_diplstate_get(plr, pplayer);
4627 i = player_index(pplayer);
4629 /* save diplomatic state */
4630 fc_snprintf(buf, sizeof(buf), "player%d.diplstate%d", plrno, i);
4632 secfile_insert_int(saving->file, ds->type,
4633 "%s.type", buf);
4634 secfile_insert_int(saving->file, ds->max_state,
4635 "%s.max_state", buf);
4636 secfile_insert_int(saving->file, ds->first_contact_turn,
4637 "%s.first_contact_turn", buf);
4638 secfile_insert_int(saving->file, ds->turns_left,
4639 "%s.turns_left", buf);
4640 secfile_insert_int(saving->file, ds->has_reason_to_cancel,
4641 "%s.has_reason_to_cancel", buf);
4642 secfile_insert_int(saving->file, ds->contact_turns_left,
4643 "%s.contact_turns_left", buf);
4644 secfile_insert_bool(saving->file, player_has_real_embassy(plr, pplayer),
4645 "%s.embassy", buf);
4646 secfile_insert_bool(saving->file, gives_shared_vision(plr, pplayer),
4647 "%s.gives_shared_vision", buf);
4648 } players_iterate_end;
4650 players_iterate(aplayer) {
4651 i = player_index(aplayer);
4652 /* save ai data */
4653 secfile_insert_int(saving->file, plr->ai_common.love[i],
4654 "player%d.ai%d.love", plrno, i);
4655 CALL_FUNC_EACH_AI(player_save_relations, plr, aplayer, saving->file, plrno);
4656 } players_iterate_end;
4658 CALL_FUNC_EACH_AI(player_save, plr, saving->file, plrno);
4660 /* Multipliers (policies) */
4661 i = multiplier_count();
4663 for (k = 0; k < i; k++) {
4664 secfile_insert_int(saving->file, plr->multipliers[k],
4665 "player%d.multiplier%d.val", plrno, k);
4666 secfile_insert_int(saving->file, plr->multipliers_target[k],
4667 "player%d.multiplier%d.target", plrno, k);
4670 secfile_insert_str(saving->file, ai_level_name(plr->ai_common.skill_level),
4671 "player%d.ai.level", plrno);
4672 secfile_insert_str(saving->file, barbarian_type_name(plr->ai_common.barbarian_type),
4673 "player%d.ai.barb_type", plrno);
4674 secfile_insert_int(saving->file, plr->economic.gold,
4675 "player%d.gold", plrno);
4676 secfile_insert_int(saving->file, plr->economic.tax,
4677 "player%d.rates.tax", plrno);
4678 secfile_insert_int(saving->file, plr->economic.science,
4679 "player%d.rates.science", plrno);
4680 secfile_insert_int(saving->file, plr->economic.luxury,
4681 "player%d.rates.luxury", plrno);
4682 secfile_insert_int(saving->file, plr->server.bulbs_last_turn,
4683 "player%d.research.bulbs_last_turn", plrno);
4685 /* Save traits */
4687 enum trait tr;
4688 int j;
4690 for (tr = trait_begin(), j = 0; tr != trait_end(); tr = trait_next(tr), j++) {
4691 secfile_insert_int(saving->file, plr->ai_common.traits[tr].val,
4692 "player%d.trait%d.val", plrno, j);
4693 secfile_insert_int(saving->file, plr->ai_common.traits[tr].mod,
4694 "player%d.trait%d.mod", plrno, j);
4698 /* Save achievements */
4700 int j = 0;
4702 achievements_iterate(pach) {
4703 if (achievement_player_has(pach, plr)) {
4704 secfile_insert_str(saving->file, achievement_rule_name(pach),
4705 "player%d.achievement%d.name", plrno, j);
4706 if (pach->first == plr) {
4707 secfile_insert_bool(saving->file, TRUE,
4708 "player%d.achievement%d.first", plrno, j);
4709 } else {
4710 secfile_insert_bool(saving->file, FALSE,
4711 "player%d.achievement%d.first", plrno, j);
4714 j++;
4716 } achievements_iterate_end;
4718 secfile_insert_int(saving->file, j,
4719 "player%d.achievement_count", plrno);
4722 secfile_insert_bool(saving->file, plr->server.got_first_city,
4723 "player%d.got_first_city", plrno);
4724 secfile_insert_int(saving->file, plr->revolution_finishes,
4725 "player%d.revolution_finishes", plrno);
4727 /* Player score */
4728 secfile_insert_int(saving->file, plr->score.happy,
4729 "score%d.happy", plrno);
4730 secfile_insert_int(saving->file, plr->score.content,
4731 "score%d.content", plrno);
4732 secfile_insert_int(saving->file, plr->score.unhappy,
4733 "score%d.unhappy", plrno);
4734 secfile_insert_int(saving->file, plr->score.angry,
4735 "score%d.angry", plrno);
4736 specialist_type_iterate(sp) {
4737 secfile_insert_int(saving->file, plr->score.specialists[sp],
4738 "score%d.specialists%d", plrno, sp);
4739 } specialist_type_iterate_end;
4740 secfile_insert_int(saving->file, plr->score.wonders,
4741 "score%d.wonders", plrno);
4742 secfile_insert_int(saving->file, plr->score.techs,
4743 "score%d.techs", plrno);
4744 secfile_insert_int(saving->file, plr->score.techout,
4745 "score%d.techout", plrno);
4746 secfile_insert_int(saving->file, plr->score.landarea,
4747 "score%d.landarea", plrno);
4748 secfile_insert_int(saving->file, plr->score.settledarea,
4749 "score%d.settledarea", plrno);
4750 secfile_insert_int(saving->file, plr->score.population,
4751 "score%d.population", plrno);
4752 secfile_insert_int(saving->file, plr->score.cities,
4753 "score%d.cities", plrno);
4754 secfile_insert_int(saving->file, plr->score.units,
4755 "score%d.units", plrno);
4756 secfile_insert_int(saving->file, plr->score.pollution,
4757 "score%d.pollution", plrno);
4758 secfile_insert_int(saving->file, plr->score.literacy,
4759 "score%d.literacy", plrno);
4760 secfile_insert_int(saving->file, plr->score.bnp,
4761 "score%d.bnp", plrno);
4762 secfile_insert_int(saving->file, plr->score.mfg,
4763 "score%d.mfg", plrno);
4764 secfile_insert_int(saving->file, plr->score.spaceship,
4765 "score%d.spaceship", plrno);
4766 secfile_insert_int(saving->file, plr->score.units_built,
4767 "score%d.units_built", plrno);
4768 secfile_insert_int(saving->file, plr->score.units_killed,
4769 "score%d.units_killed", plrno);
4770 secfile_insert_int(saving->file, plr->score.units_lost,
4771 "score%d.units_lost", plrno);
4772 secfile_insert_int(saving->file, plr->score.culture,
4773 "score%d.culture", plrno);
4774 secfile_insert_int(saving->file, plr->score.game,
4775 "score%d.total", plrno);
4777 /* Save space ship status. */
4778 secfile_insert_int(saving->file, ship->state, "player%d.spaceship.state",
4779 plrno);
4780 if (ship->state != SSHIP_NONE) {
4781 char buf[32];
4782 char st[NUM_SS_STRUCTURALS+1];
4783 int ssi;
4785 fc_snprintf(buf, sizeof(buf), "player%d.spaceship", plrno);
4787 secfile_insert_int(saving->file, ship->structurals,
4788 "%s.structurals", buf);
4789 secfile_insert_int(saving->file, ship->components,
4790 "%s.components", buf);
4791 secfile_insert_int(saving->file, ship->modules,
4792 "%s.modules", buf);
4793 secfile_insert_int(saving->file, ship->fuel, "%s.fuel", buf);
4794 secfile_insert_int(saving->file, ship->propulsion, "%s.propulsion", buf);
4795 secfile_insert_int(saving->file, ship->habitation, "%s.habitation", buf);
4796 secfile_insert_int(saving->file, ship->life_support,
4797 "%s.life_support", buf);
4798 secfile_insert_int(saving->file, ship->solar_panels,
4799 "%s.solar_panels", buf);
4801 for(ssi = 0; ssi < NUM_SS_STRUCTURALS; ssi++) {
4802 st[ssi] = BV_ISSET(ship->structure, ssi) ? '1' : '0';
4804 st[ssi] = '\0';
4805 secfile_insert_str(saving->file, st, "%s.structure", buf);
4806 if (ship->state >= SSHIP_LAUNCHED) {
4807 secfile_insert_int(saving->file, ship->launch_year,
4808 "%s.launch_year", buf);
4812 /* Save lost wonders info. */
4814 char lost[B_LAST+1];
4816 improvement_iterate(pimprove) {
4817 if (is_wonder(pimprove) && wonder_is_lost(plr, pimprove)) {
4818 lost[improvement_index(pimprove)] = '1';
4819 } else {
4820 lost[improvement_index(pimprove)] = '0';
4822 } improvement_iterate_end;
4823 lost[improvement_count()] = '\0';
4824 secfile_insert_str(saving->file, lost,
4825 "player%d.lost_wonders", plrno);
4828 secfile_insert_int(saving->file, plr->culture,
4829 "player%d.culture", plrno);
4830 secfile_insert_int(saving->file, plr->server.huts,
4831 "player%d.hut_count", plrno);
4834 /****************************************************************************
4835 Load city data
4836 ****************************************************************************/
4837 static void sg_load_player_cities(struct loaddata *loading,
4838 struct player *plr)
4840 int ncities, i, plrno = player_number(plr);
4841 bool tasks_handled;
4843 /* Check status and return if not OK (sg_success != TRUE). */
4844 sg_check_ret();
4846 sg_failure_ret(secfile_lookup_int(loading->file, &ncities,
4847 "player%d.ncities", plrno),
4848 "%s", secfile_error());
4850 if (!plr->is_alive && ncities > 0) {
4851 log_sg("'player%d.ncities' = %d for dead player!", plrno, ncities);
4852 ncities = 0;
4855 if (!plr->server.got_first_city && ncities > 0) {
4856 /* Probably barbarians in an old savegame; fix up */
4857 plr->server.got_first_city = TRUE;
4860 /* Load all cities of the player. */
4861 for (i = 0; i < ncities; i++) {
4862 char buf[32];
4863 struct city *pcity;
4865 fc_snprintf(buf, sizeof(buf), "player%d.c%d", plrno, i);
4867 /* Create a dummy city. */
4868 pcity = create_city_virtual(plr, NULL, buf);
4869 adv_city_alloc(pcity);
4870 if (!sg_load_player_city(loading, plr, pcity, buf)) {
4871 adv_city_free(pcity);
4872 destroy_city_virtual(pcity);
4873 sg_failure_ret(FALSE, "Error loading city %d of player %d.", i, plrno);
4876 identity_number_reserve(pcity->id);
4877 idex_register_city(pcity);
4879 /* Load the information about the nationality of citizens. This is done
4880 * here because the city sanity check called by citizens_update() requires
4881 * that the city is registered. */
4882 sg_load_player_city_citizens(loading, plr, pcity, buf);
4884 /* After everything is loaded, but before vision. */
4885 map_claim_ownership(city_tile(pcity), plr, city_tile(pcity), TRUE);
4887 /* adding the city contribution to fog-of-war */
4888 pcity->server.vision = vision_new(plr, city_tile(pcity));
4889 vision_reveal_tiles(pcity->server.vision, game.server.vision_reveal_tiles);
4890 city_refresh_vision(pcity);
4892 city_list_append(plr->cities, pcity);
4895 tasks_handled = FALSE;
4896 for (i = 0; !tasks_handled; i++) {
4897 int city_id;
4898 struct city *pcity = NULL;
4900 city_id = secfile_lookup_int_default(loading->file, -1, "player%d.task%d.city",
4901 plrno, i);
4903 if (city_id != -1) {
4904 pcity = player_city_by_number(plr, city_id);
4907 if (pcity != NULL) {
4908 const char *str;
4909 int nat_x, nat_y;
4910 struct worker_task *ptask = fc_malloc(sizeof(struct worker_task));
4912 nat_x = secfile_lookup_int_default(loading->file, -1, "player%d.task%d.x", plrno, i);
4913 nat_y = secfile_lookup_int_default(loading->file, -1, "player%d.task%d.y", plrno, i);
4915 ptask->ptile = native_pos_to_tile(nat_x, nat_y);
4917 str = secfile_lookup_str(loading->file, "player%d.task%d.activity", plrno, i);
4918 ptask->act = unit_activity_by_name(str, fc_strcasecmp);
4920 sg_failure_ret(unit_activity_is_valid(ptask->act),
4921 "Unknown workertask activity %s", str);
4923 str = secfile_lookup_str(loading->file, "player%d.task%d.target", plrno, i);
4925 if (strcmp("-", str)) {
4926 ptask->tgt = extra_type_by_rule_name(str);
4928 sg_failure_ret(ptask->tgt != NULL,
4929 "Unknown workertask target %s", str);
4932 ptask->want = secfile_lookup_int_default(loading->file, 1,
4933 "player%d.task%d.want", plrno, i);
4935 worker_task_list_append(pcity->task_reqs, ptask);
4936 } else {
4937 tasks_handled = TRUE;
4942 /****************************************************************************
4943 Load data for one city. sg_save_player_city() is not defined.
4944 ****************************************************************************/
4945 static bool sg_load_player_city(struct loaddata *loading, struct player *plr,
4946 struct city *pcity, const char *citystr)
4948 struct player *past;
4949 const char *kind, *name, *string;
4950 int id, i, repair, sp_count = 0, workers = 0, value;
4951 int nat_x, nat_y;
4952 citizens size;
4953 const char *stylename;
4955 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_x, "%s.x", citystr),
4956 FALSE, "%s", secfile_error());
4957 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_y, "%s.y", citystr),
4958 FALSE, "%s", secfile_error());
4959 pcity->tile = native_pos_to_tile(nat_x, nat_y);
4960 sg_warn_ret_val(NULL != pcity->tile, FALSE,
4961 "%s has invalid center tile (%d, %d)",
4962 citystr, nat_x, nat_y);
4963 sg_warn_ret_val(NULL == tile_city(pcity->tile), FALSE,
4964 "%s duplicates city (%d, %d)", citystr, nat_x, nat_y);
4966 /* Instead of dying, use 'citystr' string for damaged name. */
4967 sz_strlcpy(pcity->name, secfile_lookup_str_default(loading->file, citystr,
4968 "%s.name", citystr));
4970 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->id, "%s.id",
4971 citystr), FALSE, "%s", secfile_error());
4973 id = secfile_lookup_int_default(loading->file, player_number(plr),
4974 "%s.original", citystr);
4975 past = player_by_number(id);
4976 if (NULL != past) {
4977 pcity->original = past;
4980 sg_warn_ret_val(secfile_lookup_int(loading->file, &value, "%s.size",
4981 citystr), FALSE, "%s", secfile_error());
4982 size = (citizens)value; /* set the correct type */
4983 sg_warn_ret_val(value == (int)size, FALSE,
4984 "Invalid city size: %d, set to %d", value, size);
4985 city_size_set(pcity, size);
4987 for (i = 0; i < loading->specialist.size; i++) {
4988 sg_warn_ret_val(secfile_lookup_int(loading->file, &value, "%s.nspe%d",
4989 citystr, i),
4990 FALSE, "%s", secfile_error());
4991 pcity->specialists[specialist_index(loading->specialist.order[i])]
4992 = (citizens)value;
4993 sp_count += value;
4996 for (i = 0; i < MAX_TRADE_ROUTES; i++) {
4997 pcity->trade[i] = secfile_lookup_int_default(loading->file, 0,
4998 "%s.traderoute%d", citystr, i);
5001 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->food_stock,
5002 "%s.food_stock", citystr),
5003 FALSE, "%s", secfile_error());
5004 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->shield_stock,
5005 "%s.shield_stock", citystr),
5006 FALSE, "%s", secfile_error());
5007 pcity->history =
5008 secfile_lookup_int_default(loading->file, 0, "%s.history", citystr);
5010 pcity->airlift =
5011 secfile_lookup_int_default(loading->file, 0, "%s.airlift", citystr);
5012 pcity->was_happy =
5013 secfile_lookup_bool_default(loading->file, FALSE, "%s.was_happy",
5014 citystr);
5016 pcity->turn_plague =
5017 secfile_lookup_int_default(loading->file, 0, "%s.turn_plague", citystr);
5019 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->anarchy,
5020 "%s.anarchy", citystr),
5021 FALSE, "%s", secfile_error());
5022 pcity->rapture =
5023 secfile_lookup_int_default(loading->file, 0, "%s.rapture", citystr);
5024 pcity->server.steal =
5025 secfile_lookup_int_default(loading->file, 0, "%s.steal", citystr);
5027 /* before did_buy for undocumented hack */
5028 pcity->turn_founded =
5029 secfile_lookup_int_default(loading->file, -2, "%s.turn_founded",
5030 citystr);
5031 sg_warn_ret_val(secfile_lookup_int(loading->file, &i, "%s.did_buy",
5032 citystr), FALSE, "%s", secfile_error());
5033 pcity->did_buy = (i != 0);
5034 if (i == -1 && pcity->turn_founded == -2) {
5035 /* undocumented hack */
5036 pcity->turn_founded = game.info.turn;
5039 pcity->did_sell =
5040 secfile_lookup_bool_default(loading->file, FALSE, "%s.did_sell", citystr);
5042 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->turn_last_built,
5043 "%s.turn_last_built", citystr),
5044 FALSE, "%s", secfile_error());
5046 kind = secfile_lookup_str(loading->file, "%s.currently_building_kind",
5047 citystr);
5048 name = secfile_lookup_str(loading->file, "%s.currently_building_name",
5049 citystr);
5050 pcity->production = universal_by_rule_name(kind, name);
5051 sg_warn_ret_val(pcity->production.kind != universals_n_invalid(), FALSE,
5052 "%s.currently_building: unknown \"%s\" \"%s\".",
5053 citystr, kind, name);
5055 kind = secfile_lookup_str(loading->file, "%s.changed_from_kind",
5056 citystr);
5057 name = secfile_lookup_str(loading->file, "%s.changed_from_name",
5058 citystr);
5059 pcity->changed_from = universal_by_rule_name(kind, name);
5060 sg_warn_ret_val(pcity->changed_from.kind != universals_n_invalid(), FALSE,
5061 "%s.changed_from: unknown \"%s\" \"%s\".",
5062 citystr, kind, name);
5064 pcity->before_change_shields =
5065 secfile_lookup_int_default(loading->file, pcity->shield_stock,
5066 "%s.before_change_shields", citystr);
5067 pcity->caravan_shields =
5068 secfile_lookup_int_default(loading->file, 0,
5069 "%s.caravan_shields", citystr);
5070 pcity->disbanded_shields =
5071 secfile_lookup_int_default(loading->file, 0,
5072 "%s.disbanded_shields", citystr);
5073 pcity->last_turns_shield_surplus =
5074 secfile_lookup_int_default(loading->file, 0,
5075 "%s.last_turns_shield_surplus",
5076 citystr);
5078 stylename = secfile_lookup_str_default(loading->file, NULL,
5079 "%s.style", citystr);
5080 if (stylename != NULL) {
5081 pcity->style = city_style_by_rule_name(stylename);
5082 } else {
5083 pcity->style = 0;
5085 if (pcity->style < 0) {
5086 pcity->style = city_style(pcity);
5089 pcity->server.synced = FALSE; /* must re-sync with clients */
5091 /* Initialise list of city improvements. */
5092 for (i = 0; i < ARRAY_SIZE(pcity->built); i++) {
5093 pcity->built[i].turn = I_NEVER;
5096 /* Load city improvements. */
5097 string = secfile_lookup_str(loading->file, "%s.improvements", citystr);
5098 sg_warn_ret_val(string != NULL, FALSE, "%s", secfile_error());
5099 sg_warn_ret_val(strlen(string) == loading->improvement.size, FALSE,
5100 "Invalid length of '%s.improvements' (%lu ~= %lu).",
5101 citystr, (unsigned long) strlen(string),
5102 (unsigned long) loading->improvement.size);
5103 for (i = 0; i < loading->improvement.size; i++) {
5104 sg_warn_ret_val(string[i] == '1' || string[i] == '0', FALSE,
5105 "Undefined value '%c' within '%s.improvements'.",
5106 string[i], citystr)
5108 if (string[i] == '1') {
5109 struct impr_type *pimprove =
5110 improvement_by_rule_name(loading->improvement.order[i]);
5111 if (pimprove) {
5112 city_add_improvement(pcity, pimprove);
5117 sg_failure_ret_val(loading->worked_tiles != NULL, FALSE,
5118 "No worked tiles map defined.");
5120 city_freeze_workers(pcity);
5122 /* load new savegame with variable (squared) city radius and worked
5123 * tiles map */
5125 int radius_sq
5126 = secfile_lookup_int_default(loading->file, -1, "%s.city_radius_sq",
5127 citystr);
5128 city_map_radius_sq_set(pcity, radius_sq);
5130 city_tile_iterate(radius_sq, city_tile(pcity), ptile) {
5131 if (loading->worked_tiles[ptile->index] == pcity->id) {
5132 tile_set_worked(ptile, pcity);
5133 workers++;
5135 #ifdef FREECIV_DEBUG
5136 /* set this tile to unused; a check for not resetted tiles is
5137 * included in game_load_internal() */
5138 loading->worked_tiles[ptile->index] = -1;
5139 #endif /* FREECIV_DEBUG */
5141 } city_tile_iterate_end;
5143 if (tile_worked(city_tile(pcity)) != pcity) {
5144 struct city *pwork = tile_worked(city_tile(pcity));
5146 if (NULL != pwork) {
5147 log_sg("[%s] city center of '%s' (%d,%d) [%d] is worked by '%s' "
5148 "(%d,%d) [%d]; repairing ", citystr, city_name_get(pcity),
5149 TILE_XY(city_tile(pcity)), city_size_get(pcity), city_name_get(pwork),
5150 TILE_XY(city_tile(pwork)), city_size_get(pwork));
5152 tile_set_worked(city_tile(pcity), NULL); /* remove tile from pwork */
5153 pwork->specialists[DEFAULT_SPECIALIST]++;
5154 auto_arrange_workers(pwork);
5155 } else {
5156 log_sg("[%s] city center of '%s' (%d,%d) [%d] is empty; repairing ",
5157 citystr, city_name_get(pcity), TILE_XY(city_tile(pcity)),
5158 city_size_get(pcity));
5161 /* repair pcity */
5162 tile_set_worked(city_tile(pcity), pcity);
5163 city_repair_size(pcity, -1);
5166 repair = city_size_get(pcity) - sp_count - (workers - FREE_WORKED_TILES);
5167 if (0 != repair) {
5168 log_sg("[%s] size mismatch for '%s' (%d,%d): size [%d] != "
5169 "(workers [%d] - free worked tiles [%d]) + specialists [%d]",
5170 citystr, city_name_get(pcity), TILE_XY(city_tile(pcity)), city_size_get(pcity),
5171 workers, FREE_WORKED_TILES, sp_count);
5173 /* repair pcity */
5174 city_repair_size(pcity, repair);
5177 /* worklist_init() done in create_city_virtual() */
5178 worklist_load(loading->file, &pcity->worklist, "%s", citystr);
5180 /* Load city options. */
5181 BV_CLR_ALL(pcity->city_options);
5182 for (i = 0; i < CITYO_LAST; i++) {
5183 if (secfile_lookup_bool_default(loading->file, FALSE, "%s.option%d",
5184 citystr, i)) {
5185 BV_SET(pcity->city_options, i);
5189 CALL_FUNC_EACH_AI(city_load, loading->file, pcity, citystr);
5191 return TRUE;
5194 /****************************************************************************
5195 Load nationality data for one city.
5196 ****************************************************************************/
5197 static void sg_load_player_city_citizens(struct loaddata *loading,
5198 struct player *plr,
5199 struct city *pcity,
5200 const char *citystr)
5202 if (game.info.citizen_nationality) {
5203 citizens size;
5205 citizens_init(pcity);
5206 player_slots_iterate(pslot) {
5207 int nationality;
5209 nationality = secfile_lookup_int_default(loading->file, -1,
5210 "%s.citizen%d", citystr,
5211 player_slot_index(pslot));
5212 if (nationality > 0 && !player_slot_is_used(pslot)) {
5213 log_sg("Citizens of an invalid nation for %s (player slot %d)!",
5214 city_name_get(pcity), player_slot_index(pslot));
5215 continue;
5218 if (nationality != -1 && player_slot_is_used(pslot)) {
5219 sg_warn(nationality >= 0 && nationality <= MAX_CITY_SIZE,
5220 "Invalid value for citizens of player %d in %s: %d.",
5221 player_slot_index(pslot), city_name_get(pcity), nationality);
5222 citizens_nation_set(pcity, pslot, nationality);
5224 } player_slots_iterate_end;
5225 /* Sanity check. */
5226 size = citizens_count(pcity);
5227 if (size != city_size_get(pcity)) {
5228 if (size != 0) {
5229 /* size == 0 can be result from the fact that ruleset had no
5230 * nationality enabled at saving time, so no citizens at all
5231 * were saved. But something more serious must be going on if
5232 * citizens have been saved partially - if some of them are there. */
5233 log_sg("City size and number of citizens does not match in %s "
5234 "(%d != %d)! Repairing ...", city_name_get(pcity),
5235 city_size_get(pcity), size);
5237 citizens_update(pcity, NULL);
5242 /****************************************************************************
5243 Save cities data
5244 ****************************************************************************/
5245 static void sg_save_player_cities(struct savedata *saving,
5246 struct player *plr)
5248 int wlist_max_length = 0;
5249 int i = 0;
5250 int plrno = player_number(plr);
5251 bool nations[MAX_NUM_PLAYER_SLOTS];
5253 /* Check status and return if not OK (sg_success != TRUE). */
5254 sg_check_ret();
5256 secfile_insert_int(saving->file, city_list_size(plr->cities),
5257 "player%d.ncities", plrno);
5259 if (game.info.citizen_nationality) {
5260 /* Initialise the nation list for the citizens information. */
5261 player_slots_iterate(pslot) {
5262 nations[player_slot_index(pslot)] = FALSE;
5263 } player_slots_iterate_end;
5266 /* First determine lenght of longest worklist and the nations we have. */
5267 city_list_iterate(plr->cities, pcity) {
5268 /* Check the sanity of the city. */
5269 city_refresh(pcity);
5270 sanity_check_city(pcity);
5272 if (pcity->worklist.length > wlist_max_length) {
5273 wlist_max_length = pcity->worklist.length;
5276 if (game.info.citizen_nationality) {
5277 /* Find all nations of the citizens,*/
5278 players_iterate(pplayer) {
5279 if (!nations[player_index(pplayer)]
5280 && citizens_nation_get(pcity, pplayer->slot) != 0) {
5281 nations[player_index(pplayer)] = TRUE;
5283 } players_iterate_end;
5285 } city_list_iterate_end;
5287 city_list_iterate(plr->cities, pcity) {
5288 struct tile *pcenter = city_tile(pcity);
5289 char impr_buf[MAX_NUM_ITEMS + 1];
5290 char buf[32];
5291 int j, nat_x, nat_y;
5293 fc_snprintf(buf, sizeof(buf), "player%d.c%d", plrno, i);
5296 index_to_native_pos(&nat_x, &nat_y, tile_index(pcenter));
5297 secfile_insert_int(saving->file, nat_y, "%s.y", buf);
5298 secfile_insert_int(saving->file, nat_x, "%s.x", buf);
5300 secfile_insert_int(saving->file, pcity->id, "%s.id", buf);
5302 secfile_insert_int(saving->file, player_number(pcity->original),
5303 "%s.original", buf);
5304 secfile_insert_int(saving->file, city_size_get(pcity), "%s.size", buf);
5306 j = 0;
5307 specialist_type_iterate(sp) {
5308 secfile_insert_int(saving->file, pcity->specialists[sp], "%s.nspe%d",
5309 buf, j++);
5310 } specialist_type_iterate_end;
5312 for (j = 0; j < MAX_TRADE_ROUTES; j++) {
5313 secfile_insert_int(saving->file, pcity->trade[j], "%s.traderoute%d",
5314 buf, j);
5317 secfile_insert_int(saving->file, pcity->food_stock, "%s.food_stock",
5318 buf);
5319 secfile_insert_int(saving->file, pcity->shield_stock, "%s.shield_stock",
5320 buf);
5321 secfile_insert_int(saving->file, pcity->history, "%s.history",
5322 buf);
5324 secfile_insert_int(saving->file, pcity->airlift, "%s.airlift",
5325 buf);
5326 secfile_insert_bool(saving->file, pcity->was_happy, "%s.was_happy",
5327 buf);
5328 secfile_insert_int(saving->file, pcity->turn_plague, "%s.turn_plague",
5329 buf);
5331 secfile_insert_int(saving->file, pcity->anarchy, "%s.anarchy", buf);
5332 secfile_insert_int(saving->file, pcity->rapture, "%s.rapture", buf);
5333 secfile_insert_int(saving->file, pcity->server.steal, "%s.steal", buf);
5335 secfile_insert_int(saving->file, pcity->turn_founded, "%s.turn_founded",
5336 buf);
5337 if (pcity->turn_founded == game.info.turn) {
5338 j = -1; /* undocumented hack */
5339 } else {
5340 fc_assert(pcity->did_buy == TRUE || pcity->did_buy == FALSE);
5341 j = pcity->did_buy ? 1 : 0;
5343 secfile_insert_int(saving->file, j, "%s.did_buy", buf);
5344 secfile_insert_bool(saving->file, pcity->did_sell, "%s.did_sell", buf);
5345 secfile_insert_int(saving->file, pcity->turn_last_built,
5346 "%s.turn_last_built", buf);
5348 /* for visual debugging, variable length strings together here */
5349 secfile_insert_str(saving->file, city_name_get(pcity), "%s.name", buf);
5351 secfile_insert_str(saving->file, universal_type_rule_name(&pcity->production),
5352 "%s.currently_building_kind", buf);
5353 secfile_insert_str(saving->file, universal_rule_name(&pcity->production),
5354 "%s.currently_building_name", buf);
5356 secfile_insert_str(saving->file, universal_type_rule_name(&pcity->changed_from),
5357 "%s.changed_from_kind", buf);
5358 secfile_insert_str(saving->file, universal_rule_name(&pcity->changed_from),
5359 "%s.changed_from_name", buf);
5361 secfile_insert_int(saving->file, pcity->before_change_shields,
5362 "%s.before_change_shields", buf);
5363 secfile_insert_int(saving->file, pcity->caravan_shields,
5364 "%s.caravan_shields", buf);
5365 secfile_insert_int(saving->file, pcity->disbanded_shields,
5366 "%s.disbanded_shields", buf);
5367 secfile_insert_int(saving->file, pcity->last_turns_shield_surplus,
5368 "%s.last_turns_shield_surplus", buf);
5370 secfile_insert_str(saving->file, city_style_rule_name(pcity->style),
5371 "%s.style", buf);
5373 /* Save the squared city radius and all tiles within the corresponing
5374 * city map. */
5375 secfile_insert_int(saving->file, pcity->city_radius_sq,
5376 "player%d.c%d.city_radius_sq", plrno, i);
5377 /* The tiles worked by the city are saved using the main map.
5378 * See also sg_save_map_worked(). */
5380 /* Save improvement list as bytevector. Note that improvement order
5381 * is saved in savefile.improvement_order. */
5382 improvement_iterate(pimprove) {
5383 impr_buf[improvement_index(pimprove)]
5384 = (pcity->built[improvement_index(pimprove)].turn <= I_NEVER) ? '0'
5385 : '1';
5386 } improvement_iterate_end;
5387 impr_buf[improvement_count()] = '\0';
5388 sg_failure_ret(strlen(impr_buf) < sizeof(impr_buf),
5389 "Invalid size of the improvement vector (%s.improvements: "
5390 "%lu < %lu).", buf, (long unsigned int) strlen(impr_buf),
5391 (long unsigned int) sizeof(impr_buf));
5392 secfile_insert_str(saving->file, impr_buf, "%s.improvements", buf);
5394 worklist_save(saving->file, &pcity->worklist, wlist_max_length, "%s",
5395 buf);
5397 for (j = 0; j < CITYO_LAST; j++) {
5398 secfile_insert_bool(saving->file, BV_ISSET(pcity->city_options, j),
5399 "%s.option%d", buf, j);
5402 CALL_FUNC_EACH_AI(city_save, saving->file, pcity, buf);
5404 if (game.info.citizen_nationality) {
5405 /* Save nationality of the citizens,*/
5406 players_iterate(pplayer) {
5407 if (nations[player_index(pplayer)]) {
5408 secfile_insert_int(saving->file,
5409 citizens_nation_get(pcity, pplayer->slot),
5410 "%s.citizen%d", buf, player_index(pplayer));
5412 } players_iterate_end;
5415 i++;
5416 } city_list_iterate_end;
5418 i = 0;
5419 city_list_iterate(plr->cities, pcity) {
5420 worker_task_list_iterate(pcity->task_reqs, ptask) {
5421 int nat_x, nat_y;
5423 index_to_native_pos(&nat_x, &nat_y, tile_index(ptask->ptile));
5424 secfile_insert_int(saving->file, pcity->id, "player%d.task%d.city",
5425 plrno, i);
5426 secfile_insert_int(saving->file, nat_y, "player%d.task%d.y", plrno, i);
5427 secfile_insert_int(saving->file, nat_x, "player%d.task%d.x", plrno, i);
5428 secfile_insert_str(saving->file, unit_activity_name(ptask->act),
5429 "player%d.task%d.activity",
5430 plrno, i);
5431 if (ptask->tgt != NULL) {
5432 secfile_insert_str(saving->file, extra_rule_name(ptask->tgt),
5433 "player%d.task%d.target",
5434 plrno, i);
5435 } else {
5436 secfile_insert_str(saving->file, "-",
5437 "player%d.task%d.target",
5438 plrno, i);
5440 secfile_insert_int(saving->file, ptask->want, "player%d.task%d.want", plrno, i);
5442 i++;
5443 } worker_task_list_iterate_end;
5444 } city_list_iterate_end;
5447 /****************************************************************************
5448 Load unit data
5449 ****************************************************************************/
5450 static void sg_load_player_units(struct loaddata *loading,
5451 struct player *plr)
5453 int nunits, i, plrno = player_number(plr);
5455 /* Check status and return if not OK (sg_success != TRUE). */
5456 sg_check_ret();
5458 sg_failure_ret(secfile_lookup_int(loading->file, &nunits,
5459 "player%d.nunits", plrno),
5460 "%s", secfile_error());
5461 if (!plr->is_alive && nunits > 0) {
5462 log_sg("'player%d.nunits' = %d for dead player!", plrno, nunits);
5463 nunits = 0; /* Some old savegames may be buggy. */
5466 for (i = 0; i < nunits; i++) {
5467 struct unit *punit;
5468 struct city *pcity;
5469 const char *name;
5470 char buf[32];
5471 struct unit_type *type;
5472 struct tile *ptile;
5474 fc_snprintf(buf, sizeof(buf), "player%d.u%d", plrno, i);
5476 name = secfile_lookup_str(loading->file, "%s.type_by_name", buf);
5477 type = unit_type_by_rule_name(name);
5478 sg_failure_ret(type != NULL, "%s: unknown unit type \"%s\".", buf, name);
5480 /* Create a dummy unit. */
5481 punit = unit_virtual_create(plr, NULL, type, 0);
5482 if (!sg_load_player_unit(loading, plr, punit, buf)) {
5483 unit_virtual_destroy(punit);
5484 sg_failure_ret(FALSE, "Error loading unit %d of player %d.", i, plrno);
5487 identity_number_reserve(punit->id);
5488 idex_register_unit(punit);
5490 if ((pcity = game_city_by_number(punit->homecity))) {
5491 unit_list_prepend(pcity->units_supported, punit);
5492 } else if (punit->homecity > IDENTITY_NUMBER_ZERO) {
5493 log_sg("%s: bad home city %d.", buf, punit->homecity);
5494 punit->homecity = IDENTITY_NUMBER_ZERO;
5497 ptile = unit_tile(punit);
5499 /* allocate the unit's contribution to fog of war */
5500 punit->server.vision = vision_new(unit_owner(punit), ptile);
5501 unit_refresh_vision(punit);
5502 /* NOTE: There used to be some map_set_known calls here. These were
5503 * unneeded since unfogging the tile when the unit sees it will
5504 * automatically reveal that tile. */
5506 unit_list_append(plr->units, punit);
5507 unit_list_prepend(unit_tile(punit)->units, punit);
5509 /* Claim ownership of fortress? */
5510 if ((extra_owner(ptile) == NULL
5511 || pplayers_at_war(extra_owner(ptile), plr))
5512 && tile_has_claimable_base(ptile, unit_type_get(punit))) {
5513 tile_claim_bases(ptile, plr);
5518 /****************************************************************************
5519 Load one unit. sg_save_player_unit() is not defined.
5520 ****************************************************************************/
5521 static bool sg_load_player_unit(struct loaddata *loading,
5522 struct player *plr, struct unit *punit,
5523 const char *unitstr)
5525 int j;
5526 enum unit_activity activity;
5527 int nat_x, nat_y;
5528 enum tile_special_type target;
5529 struct extra_type *pextra = NULL;
5530 struct base_type *pbase = NULL;
5531 struct road_type *proad = NULL;
5532 struct tile *ptile;
5533 int extra_id;
5534 int base_id;
5535 int road_id;
5536 int ei;
5537 const char *facing_str;
5538 enum tile_special_type cfspe;
5539 int natnbr;
5541 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->id, "%s.id",
5542 unitstr), FALSE, "%s", secfile_error());
5543 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_x, "%s.x", unitstr),
5544 FALSE, "%s", secfile_error());
5545 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_y, "%s.y", unitstr),
5546 FALSE, "%s", secfile_error());
5548 ptile = native_pos_to_tile(nat_x, nat_y);
5549 sg_warn_ret_val(NULL != ptile, FALSE, "%s invalid tile (%d, %d)",
5550 unitstr, nat_x, nat_y);
5551 unit_tile_set(punit, ptile);
5553 facing_str
5554 = secfile_lookup_str_default(loading->file, "x",
5555 "%s.facing", unitstr);
5556 if (facing_str[0] != 'x') {
5557 /* We don't touch punit->facing if savegame does not contain that
5558 * information. Initial orientation set by unit_virtual_create()
5559 * is as good as any. */
5560 enum direction8 facing = char2dir(facing_str[0]);
5562 if (direction8_is_valid(facing)) {
5563 punit->facing = facing;
5564 } else {
5565 log_error("Illegal unit orientation '%s'", facing_str);
5569 /* If savegame has unit nationality, it doesn't hurt to
5570 * internally set it even if nationality rules are disabled. */
5571 natnbr = secfile_lookup_int_default(loading->file,
5572 player_number(plr),
5573 "%s.nationality", unitstr);
5575 punit->nationality = player_by_number(natnbr);
5576 if (punit->nationality == NULL) {
5577 punit->nationality = plr;
5580 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->homecity,
5581 "%s.homecity", unitstr), FALSE,
5582 "%s", secfile_error());
5583 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->moves_left,
5584 "%s.moves", unitstr), FALSE,
5585 "%s", secfile_error());
5586 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->fuel,
5587 "%s.fuel", unitstr), FALSE,
5588 "%s", secfile_error());
5589 sg_warn_ret_val(secfile_lookup_int(loading->file, &ei,
5590 "%s.activity", unitstr), FALSE,
5591 "%s", secfile_error());
5592 activity = ei;
5594 punit->server.birth_turn
5595 = secfile_lookup_int_default(loading->file, game.info.turn,
5596 "%s.born", unitstr);
5598 if (activity == ACTIVITY_PATROL_UNUSED) {
5599 /* Previously ACTIVITY_PATROL and ACTIVITY_GOTO were used for
5600 * client-side goto. Now client-side goto is handled by setting
5601 * a special flag, and units with orders generally have ACTIVITY_IDLE.
5602 * Old orders are lost. Old client-side goto units will still have
5603 * ACTIVITY_GOTO and will goto the correct position via server goto.
5604 * Old client-side patrol units lose their patrol routes and are put
5605 * into idle mode. */
5606 activity = ACTIVITY_IDLE;
5609 extra_id = secfile_lookup_int_default(loading->file, -2,
5610 "%s.activity_tgt", unitstr);
5612 if (extra_id != -2) {
5613 if (extra_id >= 0 && extra_id < loading->extra.size) {
5614 pextra = loading->extra.order[extra_id];
5615 set_unit_activity_targeted(punit, activity, pextra);
5616 } else if (activity == ACTIVITY_IRRIGATE) {
5617 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
5618 EC_IRRIGATION,
5619 unit_owner(punit),
5620 punit);
5621 if (tgt != NULL) {
5622 set_unit_activity_targeted(punit, ACTIVITY_IRRIGATE, tgt);
5623 } else {
5624 set_unit_activity_targeted(punit, ACTIVITY_IRRIGATE, NULL);
5626 } else if (activity == ACTIVITY_MINE) {
5627 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
5628 EC_MINE,
5629 unit_owner(punit),
5630 punit);
5631 if (tgt != NULL) {
5632 set_unit_activity_targeted(punit, ACTIVITY_MINE, tgt);
5633 } else {
5634 set_unit_activity_targeted(punit, ACTIVITY_MINE, NULL);
5636 } else {
5637 set_unit_activity(punit, activity);
5639 } else {
5640 /* extra_id == -2 -> activity_tgt not set */
5641 base_id = secfile_lookup_int_default(loading->file, -1,
5642 "%s.activity_base", unitstr);
5643 if (base_id >= 0 && base_id < loading->base.size) {
5644 pbase = loading->base.order[base_id];
5646 road_id = secfile_lookup_int_default(loading->file, -1,
5647 "%s.activity_road", unitstr);
5648 if (road_id >= 0 && road_id < loading->road.size) {
5649 proad = loading->road.order[road_id];
5653 int tgt_no = secfile_lookup_int_default(loading->file,
5654 loading->special.size /* S_LAST */,
5655 "%s.activity_target", unitstr);
5656 if (tgt_no >= 0 && tgt_no < loading->special.size) {
5657 target = loading->special.order[tgt_no];
5658 } else {
5659 target = S_LAST;
5663 if (target == S_OLD_ROAD) {
5664 target = S_LAST;
5665 proad = road_by_compat_special(ROCO_ROAD);
5666 } else if (target == S_OLD_RAILROAD) {
5667 target = S_LAST;
5668 proad = road_by_compat_special(ROCO_RAILROAD);
5671 if (activity == ACTIVITY_OLD_ROAD) {
5672 activity = ACTIVITY_GEN_ROAD;
5673 proad = road_by_compat_special(ROCO_ROAD);
5674 } else if (activity == ACTIVITY_OLD_RAILROAD) {
5675 activity = ACTIVITY_GEN_ROAD;
5676 proad = road_by_compat_special(ROCO_RAILROAD);
5679 /* We need changed_from == ACTIVITY_IDLE by now so that
5680 * set_unit_activity() and friends don't spuriously restore activity
5681 * points -- unit should have been created this way */
5682 fc_assert(punit->changed_from == ACTIVITY_IDLE);
5684 if (activity == ACTIVITY_BASE) {
5685 if (pbase) {
5686 set_unit_activity_base(punit, base_number(pbase));
5687 } else {
5688 log_sg("Cannot find base %d for %s to build",
5689 base_id, unit_rule_name(punit));
5690 set_unit_activity(punit, ACTIVITY_IDLE);
5692 } else if (activity == ACTIVITY_GEN_ROAD) {
5693 if (proad) {
5694 set_unit_activity_road(punit, road_number(proad));
5695 } else {
5696 log_sg("Cannot find road %d for %s to build",
5697 road_id, unit_rule_name(punit));
5698 set_unit_activity(punit, ACTIVITY_IDLE);
5700 } else if (activity == ACTIVITY_PILLAGE) {
5701 struct extra_type *a_target;
5703 if (target != S_LAST) {
5704 a_target = special_extra_get(target);
5705 } else if (pbase != NULL) {
5706 a_target = base_extra_get(pbase);
5707 } else if (proad != NULL) {
5708 a_target = road_extra_get(proad);
5709 } else {
5710 a_target = NULL;
5712 /* An out-of-range base number is seen with old savegames. We take
5713 * it as indicating undirected pillaging. We will assign pillage
5714 * targets before play starts. */
5715 set_unit_activity_targeted(punit, activity, a_target);
5716 } else if (activity == ACTIVITY_IRRIGATE) {
5717 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
5718 EC_IRRIGATION,
5719 unit_owner(punit),
5720 punit);
5721 if (tgt != NULL) {
5722 set_unit_activity_targeted(punit, ACTIVITY_IRRIGATE, tgt);
5723 } else {
5724 set_unit_activity_targeted(punit, ACTIVITY_IRRIGATE, NULL);
5726 } else if (activity == ACTIVITY_MINE) {
5727 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
5728 EC_MINE,
5729 unit_owner(punit),
5730 punit);
5731 if (tgt != NULL) {
5732 set_unit_activity_targeted(punit, ACTIVITY_MINE, tgt);
5733 } else {
5734 set_unit_activity_targeted(punit, ACTIVITY_MINE, NULL);
5736 } else if (activity == ACTIVITY_POLLUTION) {
5737 struct extra_type *tgt = prev_extra_in_tile(unit_tile(punit),
5738 ERM_CLEANPOLLUTION,
5739 unit_owner(punit),
5740 punit);
5741 if (tgt != NULL) {
5742 set_unit_activity_targeted(punit, ACTIVITY_POLLUTION, tgt);
5743 } else {
5744 set_unit_activity_targeted(punit, ACTIVITY_POLLUTION, NULL);
5746 } else if (activity == ACTIVITY_FALLOUT) {
5747 struct extra_type *tgt = prev_extra_in_tile(unit_tile(punit),
5748 ERM_CLEANFALLOUT,
5749 unit_owner(punit),
5750 punit);
5751 if (tgt != NULL) {
5752 set_unit_activity_targeted(punit, ACTIVITY_FALLOUT, tgt);
5753 } else {
5754 set_unit_activity_targeted(punit, ACTIVITY_FALLOUT, NULL);
5756 } else {
5757 set_unit_activity_targeted(punit, activity, NULL);
5759 } /* activity_tgt == NULL */
5761 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->activity_count,
5762 "%s.activity_count", unitstr), FALSE,
5763 "%s", secfile_error());
5765 punit->changed_from =
5766 secfile_lookup_int_default(loading->file, ACTIVITY_IDLE,
5767 "%s.changed_from", unitstr);
5769 extra_id = secfile_lookup_int_default(loading->file, -2,
5770 "%s.changed_from_tgt", unitstr);
5772 if (extra_id != -2) {
5773 if (extra_id >= 0 && extra_id < loading->extra.size) {
5774 punit->changed_from_target = loading->extra.order[extra_id];
5775 } else {
5776 punit->changed_from_target = NULL;
5778 } else {
5779 /* extra_id == -2 -> changed_from_tgt not set */
5781 cfspe =
5782 secfile_lookup_int_default(loading->file, S_LAST,
5783 "%s.changed_from_target", unitstr);
5784 base_id =
5785 secfile_lookup_int_default(loading->file, -1,
5786 "%s.changed_from_base", unitstr);
5787 road_id =
5788 secfile_lookup_int_default(loading->file, -1,
5789 "%s.changed_from_road", unitstr);
5791 if (road_id == -1) {
5792 if (cfspe == S_OLD_ROAD) {
5793 proad = road_by_compat_special(ROCO_ROAD);
5794 if (proad) {
5795 road_id = road_index(proad);
5797 } else if (cfspe == S_OLD_RAILROAD) {
5798 proad = road_by_compat_special(ROCO_RAILROAD);
5799 if (proad) {
5800 road_id = road_index(proad);
5805 if (base_id >= 0 && base_id < loading->base.size) {
5806 punit->changed_from_target = base_extra_get(loading->base.order[base_id]);
5807 } else if (road_id >= 0 && road_id < loading->road.size) {
5808 punit->changed_from_target = road_extra_get(loading->road.order[road_id]);
5809 } else if (cfspe != S_LAST) {
5810 punit->changed_from_target = special_extra_get(cfspe);
5811 } else {
5812 punit->changed_from_target = NULL;
5815 if (punit->changed_from == ACTIVITY_IRRIGATE) {
5816 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
5817 EC_IRRIGATION,
5818 unit_owner(punit),
5819 punit);
5820 if (tgt != NULL) {
5821 punit->changed_from_target = tgt;
5822 } else {
5823 punit->changed_from_target = NULL;
5825 } else if (punit->changed_from == ACTIVITY_MINE) {
5826 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
5827 EC_MINE,
5828 unit_owner(punit),
5829 punit);
5830 if (tgt != NULL) {
5831 punit->changed_from_target = tgt;
5832 } else {
5833 punit->changed_from_target = NULL;
5835 } else if (punit->changed_from == ACTIVITY_POLLUTION) {
5836 struct extra_type *tgt = prev_extra_in_tile(unit_tile(punit),
5837 ERM_CLEANPOLLUTION,
5838 unit_owner(punit),
5839 punit);
5840 if (tgt != NULL) {
5841 punit->changed_from_target = tgt;
5842 } else {
5843 punit->changed_from_target = NULL;
5845 } else if (punit->changed_from == ACTIVITY_FALLOUT) {
5846 struct extra_type *tgt = prev_extra_in_tile(unit_tile(punit),
5847 ERM_CLEANFALLOUT,
5848 unit_owner(punit),
5849 punit);
5850 if (tgt != NULL) {
5851 punit->changed_from_target = tgt;
5852 } else {
5853 punit->changed_from_target = NULL;
5858 punit->changed_from_count =
5859 secfile_lookup_int_default(loading->file, 0,
5860 "%s.changed_from_count", unitstr);
5862 /* Special case: for a long time, we accidentally incremented
5863 * activity_count while a unit was sentried, so it could increase
5864 * without bound (bug #20641) and be saved in old savefiles.
5865 * We zero it to prevent potential trouble overflowing the range
5866 * in network packets, etc. */
5867 if (activity == ACTIVITY_SENTRY) {
5868 punit->activity_count = 0;
5870 if (punit->changed_from == ACTIVITY_SENTRY) {
5871 punit->changed_from_count = 0;
5874 punit->veteran
5875 = secfile_lookup_int_default(loading->file, 0, "%s.veteran", unitstr);
5877 /* Protect against change in veteran system in ruleset */
5878 const int levels = utype_veteran_levels(unit_type_get(punit));
5879 if (punit->veteran >= levels) {
5880 fc_assert(levels >= 1);
5881 punit->veteran = levels - 1;
5884 punit->done_moving
5885 = secfile_lookup_bool_default(loading->file, (punit->moves_left == 0),
5886 "%s.done_moving", unitstr);
5887 punit->battlegroup
5888 = secfile_lookup_int_default(loading->file, BATTLEGROUP_NONE,
5889 "%s.battlegroup", unitstr);
5891 if (secfile_lookup_bool_default(loading->file, FALSE,
5892 "%s.go", unitstr)) {
5893 int gnat_x, gnat_y;
5895 sg_warn_ret_val(secfile_lookup_int(loading->file, &gnat_x,
5896 "%s.goto_x", unitstr), FALSE,
5897 "%s", secfile_error());
5898 sg_warn_ret_val(secfile_lookup_int(loading->file, &gnat_y,
5899 "%s.goto_y", unitstr), FALSE,
5900 "%s", secfile_error());
5902 punit->goto_tile = native_pos_to_tile(gnat_x, gnat_y);
5903 } else {
5904 punit->goto_tile = NULL;
5906 /* These variables are not used but needed for saving the unit table.
5907 * Load them to prevent unused variables errors. */
5908 (void) secfile_entry_lookup(loading->file, "%s.goto_x", unitstr);
5909 (void) secfile_entry_lookup(loading->file, "%s.goto_y", unitstr);
5912 /* Load AI data of the unit. */
5913 CALL_FUNC_EACH_AI(unit_load, loading->file, punit, unitstr);
5915 sg_warn_ret_val(secfile_lookup_bool(loading->file,
5916 &punit->ai_controlled,
5917 "%s.ai", unitstr), FALSE,
5918 "%s", secfile_error());
5919 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->hp,
5920 "%s.hp", unitstr), FALSE,
5921 "%s", secfile_error());
5923 punit->server.ord_map
5924 = secfile_lookup_int_default(loading->file, 0, "%s.ord_map", unitstr);
5925 punit->server.ord_city
5926 = secfile_lookup_int_default(loading->file, 0, "%s.ord_city", unitstr);
5927 punit->moved
5928 = secfile_lookup_bool_default(loading->file, FALSE, "%s.moved", unitstr);
5929 punit->paradropped
5930 = secfile_lookup_bool_default(loading->file, FALSE,
5931 "%s.paradropped", unitstr);
5933 /* The transport status (punit->transported_by) is loaded in
5934 * sg_player_units_transport(). */
5936 /* Initialize upkeep values: these are hopefully initialized
5937 * elsewhere before use (specifically, in city_support(); but
5938 * fixme: check whether always correctly initialized?).
5939 * Below is mainly for units which don't have homecity --
5940 * otherwise these don't get initialized (and AI calculations
5941 * etc may use junk values). */
5942 output_type_iterate(o) {
5943 punit->upkeep[o] = utype_upkeep_cost(unit_type_get(punit), plr, o);
5944 } output_type_iterate_end;
5946 punit->action_decision_want
5947 = secfile_lookup_enum_default(loading->file,
5948 ACT_DEC_NOTHING, action_decision,
5949 "%s.action_decision_want", unitstr);
5951 if (punit->action_decision_want != ACT_DEC_NOTHING) {
5952 /* Load the tile to act against. */
5953 int adwt_x, adwt_y;
5955 if (secfile_lookup_int(loading->file, &adwt_x,
5956 "%s.action_decision_tile_x", unitstr)
5957 && secfile_lookup_int(loading->file, &adwt_y,
5958 "%s.action_decision_tile_y", unitstr)) {
5959 punit->action_decision_tile = native_pos_to_tile(adwt_x, adwt_y);
5960 } else {
5961 punit->action_decision_want = ACT_DEC_NOTHING;
5962 punit->action_decision_tile = NULL;
5963 log_sg("Bad action_decision_tile for unit %d", punit->id);
5965 } else {
5966 punit->action_decision_tile = NULL;
5969 /* load the unit orders */
5971 int len = secfile_lookup_int_default(loading->file, 0,
5972 "%s.orders_length", unitstr);
5973 if (len > 0) {
5974 const char *orders_unitstr, *dir_unitstr, *act_unitstr;
5975 const char *tgt_unitstr;
5976 const char *base_unitstr = NULL;
5977 const char *road_unitstr = NULL;
5978 int road_idx = road_index(road_by_compat_special(ROCO_ROAD));
5979 int rail_idx = road_index(road_by_compat_special(ROCO_RAILROAD));
5981 punit->orders.list = fc_malloc(len * sizeof(*(punit->orders.list)));
5982 punit->orders.length = len;
5983 punit->orders.index
5984 = secfile_lookup_int_default(loading->file, 0,
5985 "%s.orders_index", unitstr);
5986 punit->orders.repeat
5987 = secfile_lookup_bool_default(loading->file, FALSE,
5988 "%s.orders_repeat", unitstr);
5989 punit->orders.vigilant
5990 = secfile_lookup_bool_default(loading->file, FALSE,
5991 "%s.orders_vigilant", unitstr);
5993 orders_unitstr
5994 = secfile_lookup_str_default(loading->file, "",
5995 "%s.orders_list", unitstr);
5996 dir_unitstr
5997 = secfile_lookup_str_default(loading->file, "",
5998 "%s.dir_list", unitstr);
5999 act_unitstr
6000 = secfile_lookup_str_default(loading->file, "",
6001 "%s.activity_list", unitstr);
6002 tgt_unitstr
6003 = secfile_lookup_str_default(loading->file, NULL, "%s.tgt_list", unitstr);
6005 if (tgt_unitstr == NULL) {
6006 base_unitstr
6007 = secfile_lookup_str(loading->file, "%s.base_list", unitstr);
6008 road_unitstr
6009 = secfile_lookup_str_default(loading->file, NULL, "%s.road_list", unitstr);
6012 punit->has_orders = TRUE;
6013 for (j = 0; j < len; j++) {
6014 struct unit_order *order = &punit->orders.list[j];
6016 if (orders_unitstr[j] == '\0' || dir_unitstr[j] == '\0'
6017 || act_unitstr[j] == '\0') {
6018 log_sg("Invalid unit orders.");
6019 free_unit_orders(punit);
6020 break;
6022 order->order = char2order(orders_unitstr[j]);
6023 order->dir = char2dir(dir_unitstr[j]);
6024 order->activity = char2activity(act_unitstr[j]);
6025 if (order->order == ORDER_LAST
6026 || (order->order == ORDER_MOVE && !direction8_is_valid(order->dir))
6027 || (order->order == ORDER_ACTION_MOVE
6028 && !direction8_is_valid(order->dir))
6029 || (order->order == ORDER_ACTIVITY
6030 && order->activity == ACTIVITY_LAST)) {
6031 /* An invalid order. Just drop the orders for this unit. */
6032 free(punit->orders.list);
6033 punit->orders.list = NULL;
6034 punit->has_orders = FALSE;
6035 break;
6038 if (tgt_unitstr) {
6039 if (tgt_unitstr[j] != '?') {
6040 extra_id = char2num(tgt_unitstr[j]);
6042 if (extra_id < 0 || extra_id >= loading->extra.size) {
6043 log_sg("Cannot find extra %d for %s to build",
6044 extra_id, unit_rule_name(punit));
6045 order->target = EXTRA_NONE;
6046 } else {
6047 order->target = extra_id;
6049 } else {
6050 order->target = EXTRA_NONE;
6052 } else {
6053 /* In pre-2.6 savegames, base_list and road_list were only saved
6054 * for those activities (and not e.g. pillaging) */
6055 if (base_unitstr && base_unitstr[j] != '?'
6056 && order->activity == ACTIVITY_BASE) {
6057 base_id = char2num(base_unitstr[j]);
6059 if (base_id < 0 || base_id >= loading->base.size) {
6060 log_sg("Cannot find base %d for %s to build",
6061 base_id, unit_rule_name(punit));
6062 base_id = base_number(get_base_by_gui_type(BASE_GUI_FORTRESS,
6063 NULL, NULL));
6066 order->target
6067 = extra_number(base_extra_get(base_by_number(base_id)));
6068 } else if (road_unitstr && road_unitstr[j] != '?'
6069 && order->activity == ACTIVITY_GEN_ROAD) {
6070 road_id = char2num(road_unitstr[j]);
6072 if (road_id < 0 || road_id >= loading->road.size) {
6073 log_sg("Cannot find road %d for %s to build",
6074 road_id, unit_rule_name(punit));
6075 road_id = 0;
6078 order->target
6079 = extra_number(road_extra_get(road_by_number(road_id)));
6080 } else {
6081 order->target = EXTRA_NONE;
6084 if (order->activity == ACTIVITY_OLD_ROAD) {
6085 order->activity = ACTIVITY_GEN_ROAD;
6086 order->target
6087 = extra_number(road_extra_get(road_by_number(road_idx)));
6088 } else if (order->activity == ACTIVITY_OLD_RAILROAD) {
6089 order->activity = ACTIVITY_GEN_ROAD;
6090 order->target
6091 = extra_number(road_extra_get(road_by_number(rail_idx)));
6095 } else {
6096 punit->has_orders = FALSE;
6097 punit->orders.list = NULL;
6101 return TRUE;
6104 /*****************************************************************************
6105 Load the transport status of all units. This is seperated from the other
6106 code as all units must be known.
6107 *****************************************************************************/
6108 static void sg_load_player_units_transport(struct loaddata *loading,
6109 struct player *plr)
6111 int nunits, i, plrno = player_number(plr);
6113 /* Check status and return if not OK (sg_success != TRUE). */
6114 sg_check_ret();
6116 /* Recheck the number of units for the player. This is a copied from
6117 * sg_load_player_units(). */
6118 sg_failure_ret(secfile_lookup_int(loading->file, &nunits,
6119 "player%d.nunits", plrno),
6120 "%s", secfile_error());
6121 if (!plr->is_alive && nunits > 0) {
6122 log_sg("'player%d.nunits' = %d for dead player!", plrno, nunits);
6123 nunits = 0; /* Some old savegames may be buggy. */
6126 for (i = 0; i < nunits; i++) {
6127 int id_unit, id_trans;
6128 struct unit *punit, *ptrans;
6130 id_unit = secfile_lookup_int_default(loading->file, -1,
6131 "player%d.u%d.id",
6132 plrno, i);
6133 punit = player_unit_by_number(plr, id_unit);
6134 fc_assert_action(punit != NULL, continue);
6136 id_trans = secfile_lookup_int_default(loading->file, -1,
6137 "player%d.u%d.transported_by",
6138 plrno, i);
6139 if (id_trans == -1) {
6140 /* Not transported. */
6141 continue;
6144 ptrans = game_unit_by_number(id_trans);
6145 fc_assert_action(id_trans == -1 || ptrans != NULL, continue);
6147 if (ptrans) {
6148 bool load_success = unit_transport_load(punit, ptrans, TRUE);
6150 fc_assert_action(load_success == TRUE, continue);
6155 /****************************************************************************
6156 Save unit data
6157 ****************************************************************************/
6158 static void sg_save_player_units(struct savedata *saving,
6159 struct player *plr)
6161 int i = 0;
6163 /* Check status and return if not OK (sg_success != TRUE). */
6164 sg_check_ret();
6166 secfile_insert_int(saving->file, unit_list_size(plr->units),
6167 "player%d.nunits", player_number(plr));
6169 unit_list_iterate(plr->units, punit) {
6170 char buf[32];
6171 char dirbuf[2] = " ";
6172 int nat_x, nat_y;
6174 fc_snprintf(buf, sizeof(buf), "player%d.u%d", player_number(plr), i);
6175 dirbuf[0] = dir2char(punit->facing);
6176 secfile_insert_int(saving->file, punit->id, "%s.id", buf);
6178 index_to_native_pos(&nat_x, &nat_y, tile_index(unit_tile(punit)));
6179 secfile_insert_int(saving->file, nat_x, "%s.x", buf);
6180 secfile_insert_int(saving->file, nat_y, "%s.y", buf);
6182 secfile_insert_str(saving->file, dirbuf, "%s.facing", buf);
6183 if (game.info.citizen_nationality) {
6184 secfile_insert_int(saving->file, player_number(unit_nationality(punit)),
6185 "%s.nationality", buf);
6187 secfile_insert_int(saving->file, punit->veteran, "%s.veteran", buf);
6188 secfile_insert_int(saving->file, punit->hp, "%s.hp", buf);
6189 secfile_insert_int(saving->file, punit->homecity, "%s.homecity", buf);
6190 secfile_insert_str(saving->file, unit_rule_name(punit),
6191 "%s.type_by_name", buf);
6193 secfile_insert_int(saving->file, punit->activity, "%s.activity", buf);
6194 secfile_insert_int(saving->file, punit->activity_count,
6195 "%s.activity_count", buf);
6196 if (punit->activity_target == NULL) {
6197 secfile_insert_int(saving->file, -1, "%s.activity_tgt", buf);
6198 } else {
6199 secfile_insert_int(saving->file, extra_index(punit->activity_target),
6200 "%s.activity_tgt", buf);
6203 secfile_insert_int(saving->file, punit->changed_from,
6204 "%s.changed_from", buf);
6205 secfile_insert_int(saving->file, punit->changed_from_count,
6206 "%s.changed_from_count", buf);
6207 if (punit->changed_from_target == NULL) {
6208 secfile_insert_int(saving->file, -1, "%s.changed_from_tgt", buf);
6209 } else {
6210 secfile_insert_int(saving->file, extra_index(punit->changed_from_target),
6211 "%s.changed_from_tgt", buf);
6214 secfile_insert_bool(saving->file, punit->done_moving,
6215 "%s.done_moving", buf);
6216 secfile_insert_int(saving->file, punit->moves_left, "%s.moves", buf);
6217 secfile_insert_int(saving->file, punit->fuel, "%s.fuel", buf);
6218 secfile_insert_int(saving->file, punit->server.birth_turn,
6219 "%s.born", buf);
6220 secfile_insert_int(saving->file, punit->battlegroup,
6221 "%s.battlegroup", buf);
6223 if (punit->goto_tile) {
6224 index_to_native_pos(&nat_x, &nat_y, tile_index(punit->goto_tile));
6225 secfile_insert_bool(saving->file, TRUE, "%s.go", buf);
6226 secfile_insert_int(saving->file, nat_x, "%s.goto_x", buf);
6227 secfile_insert_int(saving->file, nat_y, "%s.goto_y", buf);
6228 } else {
6229 secfile_insert_bool(saving->file, FALSE, "%s.go", buf);
6230 /* Set this values to allow saving it as table. */
6231 secfile_insert_int(saving->file, 0, "%s.goto_x", buf);
6232 secfile_insert_int(saving->file, 0, "%s.goto_y", buf);
6235 secfile_insert_bool(saving->file, punit->ai_controlled,
6236 "%s.ai", buf);
6238 /* Save AI data of the unit. */
6239 CALL_FUNC_EACH_AI(unit_save, saving->file, punit, buf);
6241 secfile_insert_int(saving->file, punit->server.ord_map,
6242 "%s.ord_map", buf);
6243 secfile_insert_int(saving->file, punit->server.ord_city,
6244 "%s.ord_city", buf);
6245 secfile_insert_bool(saving->file, punit->moved, "%s.moved", buf);
6246 secfile_insert_bool(saving->file, punit->paradropped,
6247 "%s.paradropped", buf);
6248 secfile_insert_int(saving->file, unit_transport_get(punit)
6249 ? unit_transport_get(punit)->id : -1,
6250 "%s.transported_by", buf);
6252 secfile_insert_enum(saving->file, punit->action_decision_want,
6253 action_decision, "%s.action_decision_want", buf);
6255 /* Stored as tile rather than direction to make sure the target tile is
6256 * sane. */
6257 if (punit->action_decision_tile) {
6258 index_to_native_pos(&nat_x, &nat_y,
6259 tile_index(punit->action_decision_tile));
6260 secfile_insert_int(saving->file, nat_x,
6261 "%s.action_decision_tile_x", buf);
6262 secfile_insert_int(saving->file, nat_y,
6263 "%s.action_decision_tile_y", buf);
6264 } else {
6265 /* Dummy values to get tabular format. */
6266 secfile_insert_int(saving->file, -1,
6267 "%s.action_decision_tile_x", buf);
6268 secfile_insert_int(saving->file, -1,
6269 "%s.action_decision_tile_y", buf);
6272 if (punit->has_orders) {
6273 int len = punit->orders.length, j;
6274 char orders_buf[len + 1], dir_buf[len + 1];
6275 char act_buf[len + 1], tgt_buf[len + 1];
6277 secfile_insert_int(saving->file, len, "%s.orders_length", buf);
6278 secfile_insert_int(saving->file, punit->orders.index,
6279 "%s.orders_index", buf);
6280 secfile_insert_bool(saving->file, punit->orders.repeat,
6281 "%s.orders_repeat", buf);
6282 secfile_insert_bool(saving->file, punit->orders.vigilant,
6283 "%s.orders_vigilant", buf);
6285 for (j = 0; j < len; j++) {
6286 orders_buf[j] = order2char(punit->orders.list[j].order);
6287 dir_buf[j] = '?';
6288 act_buf[j] = '?';
6289 tgt_buf[j] = '?';
6290 switch (punit->orders.list[j].order) {
6291 case ORDER_MOVE:
6292 case ORDER_ACTION_MOVE:
6293 dir_buf[j] = dir2char(punit->orders.list[j].dir);
6294 break;
6295 case ORDER_ACTIVITY:
6296 tgt_buf[j] = num2char(punit->orders.list[j].target);
6297 act_buf[j] = activity2char(punit->orders.list[j].activity);
6298 break;
6299 case ORDER_FULL_MP:
6300 case ORDER_BUILD_CITY:
6301 case ORDER_DISBAND:
6302 case ORDER_BUILD_WONDER:
6303 case ORDER_TRADE_ROUTE:
6304 case ORDER_HOMECITY:
6305 case ORDER_LAST:
6306 break;
6309 orders_buf[len] = dir_buf[len] = act_buf[len] = tgt_buf[len] = '\0';
6311 secfile_insert_str(saving->file, orders_buf, "%s.orders_list", buf);
6312 secfile_insert_str(saving->file, dir_buf, "%s.dir_list", buf);
6313 secfile_insert_str(saving->file, act_buf, "%s.activity_list", buf);
6314 secfile_insert_str(saving->file, tgt_buf, "%s.tgt_list", buf);
6315 } else {
6316 /* Put all the same fields into the savegame - otherwise the
6317 * registry code can't correctly use a tabular format and the
6318 * savegame will be bigger. */
6319 secfile_insert_int(saving->file, 0, "%s.orders_length", buf);
6320 secfile_insert_int(saving->file, 0, "%s.orders_index", buf);
6321 secfile_insert_bool(saving->file, FALSE, "%s.orders_repeat", buf);
6322 secfile_insert_bool(saving->file, FALSE, "%s.orders_vigilant", buf);
6323 secfile_insert_str(saving->file, "-", "%s.orders_list", buf);
6324 secfile_insert_str(saving->file, "-", "%s.dir_list", buf);
6325 secfile_insert_str(saving->file, "-", "%s.activity_list", buf);
6326 secfile_insert_str(saving->file, "-", "%s.tgt_list", buf);
6329 i++;
6330 } unit_list_iterate_end;
6333 /****************************************************************************
6334 Load player (client) attributes data
6335 ****************************************************************************/
6336 static void sg_load_player_attributes(struct loaddata *loading,
6337 struct player *plr)
6339 int plrno = player_number(plr);
6341 /* Check status and return if not OK (sg_success != TRUE). */
6342 sg_check_ret();
6344 /* Toss any existing attribute_block (should not exist) */
6345 if (plr->attribute_block.data) {
6346 free(plr->attribute_block.data);
6347 plr->attribute_block.data = NULL;
6350 /* This is a big heap of opaque data for the client, check everything! */
6351 plr->attribute_block.length = secfile_lookup_int_default(
6352 loading->file, 0, "player%d.attribute_v2_block_length", plrno);
6354 if (0 > plr->attribute_block.length) {
6355 log_sg("player%d.attribute_v2_block_length=%d too small", plrno,
6356 plr->attribute_block.length);
6357 plr->attribute_block.length = 0;
6358 } else if (MAX_ATTRIBUTE_BLOCK < plr->attribute_block.length) {
6359 log_sg("player%d.attribute_v2_block_length=%d too big (max %d)",
6360 plrno, plr->attribute_block.length, MAX_ATTRIBUTE_BLOCK);
6361 plr->attribute_block.length = 0;
6362 } else if (0 < plr->attribute_block.length) {
6363 int part_nr, parts;
6364 size_t actual_length;
6365 int quoted_length;
6366 char *quoted;
6368 sg_failure_ret(
6369 secfile_lookup_int(loading->file, &quoted_length,
6370 "player%d.attribute_v2_block_length_quoted",
6371 plrno), "%s", secfile_error());
6372 sg_failure_ret(
6373 secfile_lookup_int(loading->file, &parts,
6374 "player%d.attribute_v2_block_parts", plrno),
6375 "%s", secfile_error());
6377 quoted = fc_malloc(quoted_length + 1);
6378 quoted[0] = '\0';
6379 plr->attribute_block.data = fc_malloc(plr->attribute_block.length);
6380 for (part_nr = 0; part_nr < parts; part_nr++) {
6381 const char *current =
6382 secfile_lookup_str(loading->file,
6383 "player%d.attribute_v2_block_data.part%d",
6384 plrno, part_nr);
6385 if (!current) {
6386 log_sg("attribute_v2_block_parts=%d actual=%d", parts, part_nr);
6387 break;
6389 log_debug("attribute_v2_block_length_quoted=%lu have=%lu part=%lu",
6390 (unsigned long) quoted_length,
6391 (unsigned long) strlen(quoted),
6392 (unsigned long) strlen(current));
6393 fc_assert(strlen(quoted) + strlen(current) <= quoted_length);
6394 strcat(quoted, current);
6396 fc_assert_msg(quoted_length == strlen(quoted),
6397 "attribute_v2_block_length_quoted=%lu actual=%lu",
6398 (unsigned long) quoted_length,
6399 (unsigned long) strlen(quoted));
6401 actual_length =
6402 unquote_block(quoted,
6403 plr->attribute_block.data,
6404 plr->attribute_block.length);
6405 fc_assert(actual_length == plr->attribute_block.length);
6406 free(quoted);
6410 /****************************************************************************
6411 Save player (client) attributes data.
6412 ****************************************************************************/
6413 static void sg_save_player_attributes(struct savedata *saving,
6414 struct player *plr)
6416 int plrno = player_number(plr);
6418 /* Check status and return if not OK (sg_success != TRUE). */
6419 sg_check_ret();
6421 /* This is a big heap of opaque data from the client. Although the binary
6422 * format is not user editable, keep the lines short enough for debugging,
6423 * and hope that data compression will keep the file a reasonable size.
6424 * Note that the "quoted" format is a multiple of 3.
6426 #define PART_SIZE (3*256)
6427 #define PART_ADJUST (3)
6428 if (plr->attribute_block.data) {
6429 char part[PART_SIZE + PART_ADJUST];
6430 int parts;
6431 int current_part_nr;
6432 char *quoted = quote_block(plr->attribute_block.data,
6433 plr->attribute_block.length);
6434 char *quoted_at = strchr(quoted, ':');
6435 size_t bytes_left = strlen(quoted);
6436 size_t bytes_at_colon = 1 + (quoted_at - quoted);
6437 size_t bytes_adjust = bytes_at_colon % PART_ADJUST;
6439 secfile_insert_int(saving->file, plr->attribute_block.length,
6440 "player%d.attribute_v2_block_length", plrno);
6441 secfile_insert_int(saving->file, bytes_left,
6442 "player%d.attribute_v2_block_length_quoted", plrno);
6444 /* Try to wring some compression efficiencies out of the "quoted" format.
6445 * The first line has a variable length decimal, mis-aligning triples.
6447 if ((bytes_left - bytes_adjust) > PART_SIZE) {
6448 /* first line can be longer */
6449 parts = 1 + (bytes_left - bytes_adjust - 1) / PART_SIZE;
6450 } else {
6451 parts = 1;
6454 secfile_insert_int(saving->file, parts,
6455 "player%d.attribute_v2_block_parts", plrno);
6457 if (parts > 1) {
6458 size_t size_of_current_part = PART_SIZE + bytes_adjust;
6460 /* first line can be longer */
6461 memcpy(part, quoted, size_of_current_part);
6462 part[size_of_current_part] = '\0';
6463 secfile_insert_str(saving->file, part,
6464 "player%d.attribute_v2_block_data.part%d",
6465 plrno, 0);
6466 bytes_left -= size_of_current_part;
6467 quoted_at = &quoted[size_of_current_part];
6468 current_part_nr = 1;
6469 } else {
6470 quoted_at = quoted;
6471 current_part_nr = 0;
6474 for (; current_part_nr < parts; current_part_nr++) {
6475 size_t size_of_current_part = MIN(bytes_left, PART_SIZE);
6477 memcpy(part, quoted_at, size_of_current_part);
6478 part[size_of_current_part] = '\0';
6479 secfile_insert_str(saving->file, part,
6480 "player%d.attribute_v2_block_data.part%d",
6481 plrno,
6482 current_part_nr);
6483 bytes_left -= size_of_current_part;
6484 quoted_at = &quoted_at[size_of_current_part];
6486 fc_assert(bytes_left == 0);
6487 free(quoted);
6489 #undef PART_ADJUST
6490 #undef PART_SIZE
6493 /****************************************************************************
6494 Load vision data
6495 ****************************************************************************/
6496 static void sg_load_player_vision(struct loaddata *loading,
6497 struct player *plr)
6499 int plrno = player_number(plr);
6500 int total_ncities =
6501 secfile_lookup_int_default(loading->file, -1,
6502 "player%d.dc_total", plrno);
6503 int i;
6505 /* Check status and return if not OK (sg_success != TRUE). */
6506 sg_check_ret();
6508 if (!plr->is_alive) {
6509 if (game.server.revealmap & REVEAL_MAP_DEAD
6510 && player_list_size(team_members(plr->team)) == 1) {
6511 /* Reveal all for dead players. */
6512 map_know_and_see_all(plr);
6516 if (!plr->is_alive
6517 || -1 == total_ncities
6518 || FALSE == game.info.fogofwar
6519 || !secfile_lookup_bool_default(loading->file, TRUE,
6520 "game.save_private_map")) {
6521 /* We have:
6522 * - a dead player;
6523 * - fogged cities are not saved for any reason;
6524 * - a savegame with fog of war turned off;
6525 * - or game.save_private_map is not set to FALSE in the scenario /
6526 * savegame. The players private knowledge is set to be what he could
6527 * see without fog of war. */
6528 whole_map_iterate(ptile) {
6529 if (map_is_known(ptile, plr)) {
6530 struct city *pcity = tile_city(ptile);
6532 update_player_tile_last_seen(plr, ptile);
6533 update_player_tile_knowledge(plr, ptile);
6535 if (NULL != pcity) {
6536 update_dumb_city(plr, pcity);
6539 } whole_map_iterate_end;
6541 /* Nothing more to do; */
6542 return;
6545 /* Load player map (terrain). */
6546 LOAD_MAP_CHAR(ch, ptile,
6547 map_get_player_tile(ptile, plr)->terrain
6548 = char2terrain(ch), loading->file,
6549 "player%d.map_t%04d", plrno);
6551 /* Load player map (resources). */
6552 LOAD_MAP_CHAR(ch, ptile,
6553 map_get_player_tile(ptile, plr)->resource
6554 = char2resource(ch), loading->file,
6555 "player%d.map_res%04d", plrno);
6557 if (loading->version >= 30) {
6558 /* 2.6.0 or newer */
6560 /* Load player map (extras). */
6561 halfbyte_iterate_extras(j, loading->extra.size) {
6562 LOAD_MAP_CHAR(ch, ptile,
6563 sg_extras_set(&map_get_player_tile(ptile, plr)->extras,
6564 ch, loading->extra.order + 4 * j),
6565 loading->file, "player%d.map_e%02d_%04d", plrno, j);
6566 } halfbyte_iterate_extras_end;
6567 } else {
6568 /* Load player map (specials). */
6569 halfbyte_iterate_special(j, loading->special.size) {
6570 LOAD_MAP_CHAR(ch, ptile,
6571 sg_special_set(ptile, &map_get_player_tile(ptile, plr)->extras,
6572 ch, loading->special.order + 4 * j, FALSE),
6573 loading->file, "player%d.map_spe%02d_%04d", plrno, j);
6574 } halfbyte_iterate_special_end;
6576 /* Load player map (bases). */
6577 halfbyte_iterate_bases(j, loading->base.size) {
6578 LOAD_MAP_CHAR(ch, ptile,
6579 sg_bases_set(&map_get_player_tile(ptile, plr)->extras,
6580 ch, loading->base.order + 4 * j),
6581 loading->file, "player%d.map_b%02d_%04d", plrno, j);
6582 } halfbyte_iterate_bases_end;
6584 /* Load player map (roads). */
6585 if (loading->version >= 20) {
6586 /* 2.5.0 or newer */
6587 halfbyte_iterate_roads(j, loading->road.size) {
6588 LOAD_MAP_CHAR(ch, ptile,
6589 sg_roads_set(&map_get_player_tile(ptile, plr)->extras,
6590 ch, loading->road.order + 4 * j),
6591 loading->file, "player%d.map_r%02d_%04d", plrno, j);
6592 } halfbyte_iterate_roads_end;
6596 if (game.server.foggedborders) {
6597 /* Load player map (border). */
6598 int x, y;
6600 for (y = 0; y < game.map.ysize; y++) {
6601 const char *buffer
6602 = secfile_lookup_str(loading->file, "player%d.map_owner%04d",
6603 plrno, y);
6604 const char *buffer2
6605 = secfile_lookup_str(loading->file, "player%d.extras_owner%04d",
6606 plrno, y);
6607 const char *ptr = buffer;
6608 const char *ptr2 = buffer2;
6610 sg_failure_ret(NULL != buffer,
6611 "Savegame corrupt - map line %d not found.", y);
6612 for (x = 0; x < game.map.xsize; x++) {
6613 char token[TOKEN_SIZE];
6614 char token2[TOKEN_SIZE];
6615 int number;
6616 struct tile *ptile = native_pos_to_tile(x, y);
6618 scanin(&ptr, ",", token, sizeof(token));
6619 sg_failure_ret('\0' != token[0],
6620 "Savegame corrupt - map size not correct.");
6621 if (strcmp(token, "-") == 0) {
6622 map_get_player_tile(ptile, plr)->owner = NULL;
6623 } else {
6624 sg_failure_ret(str_to_int(token, &number),
6625 "Savegame corrupt - got tile owner=%s in (%d, %d).",
6626 token, x, y);
6627 map_get_player_tile(ptile, plr)->owner = player_by_number(number);
6630 if (loading->version >= 30) {
6631 scanin(&ptr2, ",", token2, sizeof(token2));
6632 sg_failure_ret('\0' != token2[0],
6633 "Savegame corrupt - map size not correct.");
6634 if (strcmp(token2, "-") == 0) {
6635 map_get_player_tile(ptile, plr)->extras_owner = NULL;
6636 } else {
6637 sg_failure_ret(str_to_int(token2, &number),
6638 "Savegame corrupt - got extras owner=%s in (%d, %d).",
6639 token, x, y);
6640 map_get_player_tile(ptile, plr)->extras_owner = player_by_number(number);
6642 } else {
6643 map_get_player_tile(ptile, plr)->extras_owner
6644 = map_get_player_tile(ptile, plr)->owner;
6650 /* Load player map (update time). */
6651 for (i = 0; i < 4; i++) {
6652 /* put 4-bit segments of 16-bit "updated" field */
6653 if (i == 0) {
6654 LOAD_MAP_CHAR(ch, ptile,
6655 map_get_player_tile(ptile, plr)->last_updated
6656 = ascii_hex2bin(ch, i),
6657 loading->file, "player%d.map_u%02d_%04d", plrno, i);
6658 } else {
6659 LOAD_MAP_CHAR(ch, ptile,
6660 map_get_player_tile(ptile, plr)->last_updated
6661 |= ascii_hex2bin(ch, i),
6662 loading->file, "player%d.map_u%02d_%04d", plrno, i);
6666 /* Load player map known cities. */
6667 for (i = 0; i < total_ncities; i++) {
6668 struct vision_site *pdcity;
6669 char buf[32];
6670 fc_snprintf(buf, sizeof(buf), "player%d.dc%d", plrno, i);
6672 pdcity = vision_site_new(0, NULL, NULL);
6673 if (sg_load_player_vision_city(loading, plr, pdcity, buf)) {
6674 change_playertile_site(map_get_player_tile(pdcity->location, plr),
6675 pdcity);
6676 identity_number_reserve(pdcity->identity);
6677 } else {
6678 /* Error loading the data. */
6679 log_sg("Skipping seen city %d for player %d.", i, plrno);
6680 if (pdcity != NULL) {
6681 vision_site_destroy(pdcity);
6686 /* Repair inconsistent player maps. */
6687 whole_map_iterate(ptile) {
6688 if (map_is_known_and_seen(ptile, plr, V_MAIN)) {
6689 struct city *pcity = tile_city(ptile);
6691 update_player_tile_knowledge(plr, ptile);
6692 reality_check_city(plr, ptile);
6694 if (NULL != pcity) {
6695 update_dumb_city(plr, pcity);
6698 } whole_map_iterate_end;
6701 /****************************************************************************
6702 Load data for one seen city. sg_save_player_vision_city() is not defined.
6703 ****************************************************************************/
6704 static bool sg_load_player_vision_city(struct loaddata *loading,
6705 struct player *plr,
6706 struct vision_site *pdcity,
6707 const char *citystr)
6709 const char *string;
6710 int i, id, size;
6711 citizens city_size;
6712 int nat_x, nat_y;
6713 const char *stylename;
6715 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_x, "%s.x",
6716 citystr),
6717 FALSE, "%s", secfile_error());
6718 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_y, "%s.y",
6719 citystr),
6720 FALSE, "%s", secfile_error());
6721 pdcity->location = native_pos_to_tile(nat_x, nat_y);
6722 sg_warn_ret_val(NULL != pdcity->location, FALSE,
6723 "%s invalid tile (%d,%d)", citystr, nat_x, nat_y);
6725 sg_warn_ret_val(secfile_lookup_int(loading->file, &id, "%s.owner",
6726 citystr),
6727 FALSE, "%s", secfile_error());
6728 pdcity->owner = player_by_number(id);
6729 sg_warn_ret_val(NULL != pdcity->owner, FALSE,
6730 "%s has invalid owner (%d); skipping.", citystr, id);
6732 sg_warn_ret_val(secfile_lookup_int(loading->file, &pdcity->identity,
6733 "%s.id", citystr),
6734 FALSE, "%s", secfile_error());
6735 sg_warn_ret_val(IDENTITY_NUMBER_ZERO < pdcity->identity, FALSE,
6736 "%s has invalid id (%d); skipping.", citystr, id);
6738 sg_warn_ret_val(secfile_lookup_int(loading->file, &size,
6739 "%s.size", citystr),
6740 FALSE, "%s", secfile_error());
6741 city_size = (citizens)size; /* set the correct type */
6742 sg_warn_ret_val(size == (int)city_size, FALSE,
6743 "Invalid city size: %d; set to %d.", size, city_size);
6744 vision_site_size_set(pdcity, city_size);
6746 /* Initialise list of improvements */
6747 BV_CLR_ALL(pdcity->improvements);
6748 string = secfile_lookup_str(loading->file, "%s.improvements", citystr);
6749 sg_warn_ret_val(string != NULL, FALSE, "%s", secfile_error());
6750 sg_warn_ret_val(strlen(string) == loading->improvement.size, FALSE,
6751 "Invalid length of '%s.improvements' (%lu ~= %lu).",
6752 citystr, (unsigned long) strlen(string),
6753 (unsigned long) loading->improvement.size);
6754 for (i = 0; i < loading->improvement.size; i++) {
6755 sg_warn_ret_val(string[i] == '1' || string[i] == '0', FALSE,
6756 "Undefined value '%c' within '%s.improvements'.",
6757 string[i], citystr)
6759 if (string[i] == '1') {
6760 struct impr_type *pimprove =
6761 improvement_by_rule_name(loading->improvement.order[i]);
6762 if (pimprove) {
6763 BV_SET(pdcity->improvements, improvement_index(pimprove));
6768 /* Use the section as backup name. */
6769 sz_strlcpy(pdcity->name, secfile_lookup_str_default(loading->file, citystr,
6770 "%s.name", citystr));
6772 pdcity->occupied = secfile_lookup_bool_default(loading->file, FALSE,
6773 "%s.occupied", citystr);
6774 pdcity->walls = secfile_lookup_bool_default(loading->file, FALSE,
6775 "%s.walls", citystr);
6776 pdcity->happy = secfile_lookup_bool_default(loading->file, FALSE,
6777 "%s.happy", citystr);
6778 pdcity->unhappy = secfile_lookup_bool_default(loading->file, FALSE,
6779 "%s.unhappy", citystr);
6780 stylename = secfile_lookup_str_default(loading->file, NULL,
6781 "%s.style", citystr);
6782 if (stylename != NULL) {
6783 pdcity->style = city_style_by_rule_name(stylename);
6784 } else {
6785 pdcity->style = 0;
6787 if (pdcity->style < 0) {
6788 pdcity->style = 0;
6791 pdcity->city_image = secfile_lookup_int_default(loading->file, -100,
6792 "%s.city_image", citystr);
6794 return TRUE;
6797 /****************************************************************************
6798 Save vision data
6799 ****************************************************************************/
6800 static void sg_save_player_vision(struct savedata *saving,
6801 struct player *plr)
6803 int i, plrno = player_number(plr);
6805 /* Check status and return if not OK (sg_success != TRUE). */
6806 sg_check_ret();
6808 if (!game.info.fogofwar || !game.server.save_options.save_private_map) {
6809 /* The player can see all, there's no reason to save the private map. */
6810 return;
6813 if (!plr->is_alive) {
6814 /* Nothing to save. */
6815 return;
6818 /* Save the map (terrain). */
6819 SAVE_MAP_CHAR(ptile,
6820 terrain2char(map_get_player_tile(ptile, plr)->terrain),
6821 saving->file, "player%d.map_t%04d", plrno);
6823 /* Save the map (resources). */
6824 SAVE_MAP_CHAR(ptile,
6825 resource2char(map_get_player_tile(ptile, plr)->resource),
6826 saving->file, "player%d.map_res%04d", plrno);
6828 if (game.server.foggedborders) {
6829 /* Save the map (borders). */
6830 int x, y;
6832 for (y = 0; y < game.map.ysize; y++) {
6833 char line[game.map.xsize * TOKEN_SIZE];
6835 line[0] = '\0';
6836 for (x = 0; x < game.map.xsize; x++) {
6837 char token[TOKEN_SIZE];
6838 struct tile *ptile = native_pos_to_tile(x, y);
6839 struct player_tile *plrtile = map_get_player_tile(ptile, plr);
6841 if (plrtile == NULL || plrtile->owner == NULL) {
6842 strcpy(token, "-");
6843 } else {
6844 fc_snprintf(token, sizeof(token), "%d",
6845 player_number(plrtile->owner));
6847 strcat(line, token);
6848 if (x < game.map.xsize) {
6849 strcat(line, ",");
6852 secfile_insert_str(saving->file, line, "player%d.map_owner%04d",
6853 plrno, y);
6856 for (y = 0; y < game.map.ysize; y++) {
6857 char line[game.map.xsize * TOKEN_SIZE];
6859 line[0] = '\0';
6860 for (x = 0; x < game.map.xsize; x++) {
6861 char token[TOKEN_SIZE];
6862 struct tile *ptile = native_pos_to_tile(x, y);
6863 struct player_tile *plrtile = map_get_player_tile(ptile, plr);
6865 if (plrtile == NULL || plrtile->extras_owner == NULL) {
6866 strcpy(token, "-");
6867 } else {
6868 fc_snprintf(token, sizeof(token), "%d",
6869 player_number(plrtile->extras_owner));
6871 strcat(line, token);
6872 if (x < game.map.xsize) {
6873 strcat(line, ",");
6876 secfile_insert_str(saving->file, line, "player%d.extras_owner%04d",
6877 plrno, y);
6881 /* Save the map (extras). */
6882 halfbyte_iterate_extras(j, game.control.num_extra_types) {
6883 int mod[4];
6884 int l;
6886 for (l = 0; l < 4; l++) {
6887 if (4 * j + 1 > game.control.num_extra_types) {
6888 mod[l] = -1;
6889 } else {
6890 mod[l] = 4 * j + l;
6894 SAVE_MAP_CHAR(ptile,
6895 sg_extras_get(map_get_player_tile(ptile, plr)->extras, mod),
6896 saving->file, "player%d.map_e%02d_%04d", plrno, j);
6897 } halfbyte_iterate_extras_end;
6899 /* Save the map (update time). */
6900 for (i = 0; i < 4; i++) {
6901 /* put 4-bit segments of 16-bit "updated" field */
6902 SAVE_MAP_CHAR(ptile,
6903 bin2ascii_hex(
6904 map_get_player_tile(ptile, plr)->last_updated, i),
6905 saving->file, "player%d.map_u%02d_%04d", plrno, i);
6908 /* Save known cities. */
6909 i = 0;
6910 whole_map_iterate(ptile) {
6911 struct vision_site *pdcity = map_get_player_city(ptile, plr);
6912 char impr_buf[MAX_NUM_ITEMS + 1];
6913 char buf[32];
6915 fc_snprintf(buf, sizeof(buf), "player%d.dc%d", plrno, i);
6917 if (NULL != pdcity && plr != vision_site_owner(pdcity)) {
6918 int nat_x, nat_y;
6920 index_to_native_pos(&nat_x, &nat_y, tile_index(ptile));
6921 secfile_insert_int(saving->file, nat_y, "%s.y", buf);
6922 secfile_insert_int(saving->file, nat_x, "%s.x", buf);
6924 secfile_insert_int(saving->file, pdcity->identity, "%s.id", buf);
6925 secfile_insert_int(saving->file, player_number(vision_site_owner(pdcity)),
6926 "%s.owner", buf);
6928 secfile_insert_int(saving->file, vision_site_size_get(pdcity),
6929 "%s.size", buf);
6930 secfile_insert_bool(saving->file, pdcity->occupied,
6931 "%s.occupied", buf);
6932 secfile_insert_bool(saving->file, pdcity->walls, "%s.walls", buf);
6933 secfile_insert_bool(saving->file, pdcity->happy, "%s.happy", buf);
6934 secfile_insert_bool(saving->file, pdcity->unhappy, "%s.unhappy", buf);
6935 secfile_insert_str(saving->file, city_style_rule_name(pdcity->style),
6936 "%s.style", buf);
6937 secfile_insert_int(saving->file, pdcity->city_image, "%s.city_image", buf);
6939 /* Save improvement list as bitvector. Note that improvement order
6940 * is saved in savefile.improvement.order. */
6941 improvement_iterate(pimprove) {
6942 impr_buf[improvement_index(pimprove)]
6943 = BV_ISSET(pdcity->improvements, improvement_index(pimprove))
6944 ? '1' : '0';
6945 } improvement_iterate_end;
6946 impr_buf[improvement_count()] = '\0';
6947 sg_failure_ret(strlen(impr_buf) < sizeof(impr_buf),
6948 "Invalid size of the improvement vector (%s.improvements: "
6949 "%lu < %lu).", buf, (long unsigned int) strlen(impr_buf),
6950 (long unsigned int) sizeof(impr_buf));
6951 secfile_insert_str(saving->file, impr_buf, "%s.improvements", buf);
6952 secfile_insert_str(saving->file, pdcity->name, "%s.name", buf);
6954 i++;
6956 } whole_map_iterate_end;
6958 secfile_insert_int(saving->file, i, "player%d.dc_total", plrno);
6961 /* =======================================================================
6962 * Load / save the researches.
6963 * ======================================================================= */
6965 /****************************************************************************
6966 Load '[research]'.
6967 ****************************************************************************/
6968 static void sg_load_researches(struct loaddata *loading)
6970 struct research *presearch;
6971 int count;
6972 int number;
6973 const char *string;
6974 int i, j;
6976 /* Check status and return if not OK (sg_success != TRUE). */
6977 sg_check_ret();
6979 /* Initialize all researches. */
6980 researches_iterate(pinitres) {
6981 init_tech(pinitres, FALSE);
6982 } researches_iterate_end;
6984 /* May be unsaved (e.g. scenario case). */
6985 count = secfile_lookup_int_default(loading->file, 0, "research.count");
6986 for (i = 0; i < count; i++) {
6987 sg_failure_ret(secfile_lookup_int(loading->file, &number,
6988 "research.r%d.number", i),
6989 "%s", secfile_error());
6990 presearch = research_by_number(number);
6991 sg_failure_ret(presearch != NULL,
6992 "Invalid research number %d in 'research.r%d.number'",
6993 number, i);
6995 presearch->tech_goal = technology_load(loading->file,
6996 "research.r%d.goal", i);
6997 sg_failure_ret(secfile_lookup_int(loading->file,
6998 &presearch->techs_researched,
6999 "research.r%d.techs", i),
7000 "%s", secfile_error());
7001 sg_failure_ret(secfile_lookup_int(loading->file,
7002 &presearch->future_tech,
7003 "research.r%d.futuretech", i),
7004 "%s", secfile_error());
7005 sg_failure_ret(secfile_lookup_int(loading->file,
7006 &presearch->bulbs_researched,
7007 "research.r%d.bulbs", i),
7008 "%s", secfile_error());
7009 sg_failure_ret(secfile_lookup_int(loading->file,
7010 &presearch->bulbs_researching_saved,
7011 "research.r%d.bulbs_before", i),
7012 "%s", secfile_error());
7013 presearch->researching_saved = technology_load(loading->file,
7014 "research.r%d.saved", i);
7015 presearch->researching = technology_load(loading->file,
7016 "research.r%d.now", i);
7017 sg_failure_ret(secfile_lookup_bool(loading->file,
7018 &presearch->got_tech,
7019 "research.r%d.got_tech", i),
7020 "%s", secfile_error());
7022 string = secfile_lookup_str(loading->file, "research.r%d.done",
7024 sg_failure_ret(string != NULL, "%s", secfile_error());
7025 sg_failure_ret(strlen(string) == loading->technology.size,
7026 "Invalid length of 'research.r%d.done' (%lu ~= %lu).",
7027 i, (unsigned long) strlen(string),
7028 (unsigned long) loading->technology.size);
7029 for (j = 0; j < loading->technology.size; j++) {
7030 sg_failure_ret(string[j] == '1' || string[j] == '0',
7031 "Undefined value '%c' within 'research.r%d.done'.",
7032 string[j], i);
7034 if (string[j] == '1') {
7035 struct advance *padvance =
7036 advance_by_rule_name(loading->technology.order[j]);
7038 if (padvance) {
7039 research_invention_set(presearch, advance_number(padvance),
7040 TECH_KNOWN);
7046 /* In case of tech_leakage, we can update research only after all the
7047 * researches have been loaded */
7048 researches_iterate(pupres) {
7049 research_update(pupres);
7050 } researches_iterate_end;
7053 /****************************************************************************
7054 Save '[research]'.
7055 ****************************************************************************/
7056 static void sg_save_researches(struct savedata *saving)
7058 char invs[A_LAST];
7059 int i = 0;
7061 /* Check status and return if not OK (sg_success != TRUE). */
7062 sg_check_ret();
7064 if (saving->save_players) {
7065 researches_iterate(presearch) {
7066 secfile_insert_int(saving->file, research_number(presearch),
7067 "research.r%d.number", i);
7068 technology_save(saving->file, "research.r%d.goal",
7069 i, presearch->tech_goal);
7070 secfile_insert_int(saving->file, presearch->techs_researched,
7071 "research.r%d.techs", i);
7072 secfile_insert_int(saving->file, presearch->future_tech,
7073 "research.r%d.futuretech", i);
7074 secfile_insert_int(saving->file, presearch->bulbs_researching_saved,
7075 "research.r%d.bulbs_before", i);
7076 technology_save(saving->file, "research.r%d.saved",
7077 i, presearch->researching_saved);
7078 secfile_insert_int(saving->file, presearch->bulbs_researched,
7079 "research.r%d.bulbs", i);
7080 technology_save(saving->file, "research.r%d.now",
7081 i, presearch->researching);
7082 secfile_insert_bool(saving->file, presearch->got_tech,
7083 "research.r%d.got_tech", i);
7084 /* Save technology lists as bytevector. Note that technology order is
7085 * saved in savefile.technology.order */
7086 advance_index_iterate(A_NONE, tech_id) {
7087 invs[tech_id] = (research_invention_state(presearch, tech_id)
7088 == TECH_KNOWN ? '1' : '0');
7089 } advance_index_iterate_end;
7090 invs[game.control.num_tech_types] = '\0';
7091 secfile_insert_str(saving->file, invs, "research.r%d.done", i);
7092 i++;
7093 } researches_iterate_end;
7094 secfile_insert_int(saving->file, i, "research.count");
7098 /* =======================================================================
7099 * Load / save the event cache. Should be the last thing to do.
7100 * ======================================================================= */
7102 /****************************************************************************
7103 Load '[event_cache]'.
7104 ****************************************************************************/
7105 static void sg_load_event_cache(struct loaddata *loading)
7107 /* Check status and return if not OK (sg_success != TRUE). */
7108 sg_check_ret();
7110 event_cache_load(loading->file, "event_cache");
7113 /****************************************************************************
7114 Save '[event_cache]'.
7115 ****************************************************************************/
7116 static void sg_save_event_cache(struct savedata *saving)
7118 /* Check status and return if not OK (sg_success != TRUE). */
7119 sg_check_ret();
7121 if (saving->scenario) {
7122 /* Do _not_ save events in a scenario. */
7123 return;
7126 event_cache_save(saving->file, "event_cache");
7129 /* =======================================================================
7130 * Load / save the open treaties
7131 * ======================================================================= */
7133 /****************************************************************************
7134 Load '[treaty_xxx]'.
7135 ****************************************************************************/
7136 static void sg_load_treaties(struct loaddata *loading)
7138 int tidx;
7139 const char *plr0;
7140 struct treaty_list *treaties = get_all_treaties();
7142 for (tidx = 0; (plr0 = secfile_lookup_str_default(loading->file, NULL,
7143 "treaty%d.plr0", tidx)) != NULL ;
7144 tidx++) {
7145 const char *plr1;
7146 const char *ct;
7147 int cidx;
7148 struct player *p0, *p1;
7150 plr1 = secfile_lookup_str(loading->file, "treaty%d.plr1", tidx);
7152 p0 = player_by_name(plr0);
7153 p1 = player_by_name(plr1);
7155 if (p0 == NULL || p1 == NULL) {
7156 log_error("Treaty between unknown players %s and %s", plr0, plr1);
7157 } else {
7158 struct Treaty *ptreaty = fc_malloc(sizeof(*ptreaty));
7160 init_treaty(ptreaty, p0, p1);
7161 treaty_list_prepend(treaties, ptreaty);
7163 for (cidx = 0; (ct = secfile_lookup_str_default(loading->file, NULL,
7164 "treaty%d.clause%d.type",
7165 tidx, cidx)) != NULL ;
7166 cidx++ ) {
7167 enum clause_type type = clause_type_by_name(ct, fc_strcasecmp);
7168 const char *plrx;
7170 if (!clause_type_is_valid(type)) {
7171 log_error("Invalid clause type \"%s\"", ct);
7172 } else {
7173 struct player *pgiver = NULL;
7175 plrx = secfile_lookup_str(loading->file, "treaty%d.clause%d.from",
7176 tidx, cidx);
7178 if (!fc_strcasecmp(plrx, plr0)) {
7179 pgiver = p0;
7180 } else if (!fc_strcasecmp(plrx, plr1)) {
7181 pgiver = p1;
7182 } else {
7183 log_error("Clause giver %s is not participant of the treaty"
7184 "between %s and %s", plrx, plr0, plr1);
7187 if (pgiver != NULL) {
7188 int value;
7190 value = secfile_lookup_int_default(loading->file, 0,
7191 "treaty%d.clause%d.value",
7192 tidx, cidx);
7194 add_clause(ptreaty, pgiver, type, value);
7198 /* These must be after clauses have been added so that acceptance
7199 * does not get cleared by what seems like changes to the treaty. */
7200 ptreaty->accept0 = secfile_lookup_bool_default(loading->file, FALSE,
7201 "treaty%d.accept0", tidx);
7202 ptreaty->accept1 = secfile_lookup_bool_default(loading->file, FALSE,
7203 "treaty%d.accept1", tidx);
7209 /****************************************************************************
7210 Save '[treaty_xxx]'.
7211 ****************************************************************************/
7212 static void sg_save_treaties(struct savedata *saving)
7214 struct treaty_list *treaties = get_all_treaties();
7215 int tidx = 0;
7217 treaty_list_iterate(treaties, ptr) {
7218 char tpath[512];
7219 int cidx = 0;
7221 fc_snprintf(tpath, sizeof(tpath), "treaty%d", tidx++);
7223 secfile_insert_str(saving->file, player_name(ptr->plr0), "%s.plr0", tpath);
7224 secfile_insert_str(saving->file, player_name(ptr->plr1), "%s.plr1", tpath);
7225 secfile_insert_bool(saving->file, ptr->accept0, "%s.accept0", tpath);
7226 secfile_insert_bool(saving->file, ptr->accept1, "%s.accept1", tpath);
7228 clause_list_iterate(ptr->clauses, pclaus) {
7229 char cpath[512];
7231 fc_snprintf(cpath, sizeof(cpath), "%s.clause%d", tpath, cidx++);
7233 secfile_insert_str(saving->file, clause_type_name(pclaus->type), "%s.type", cpath);
7234 secfile_insert_str(saving->file, player_name(pclaus->from), "%s.from", cpath);
7235 secfile_insert_int(saving->file, pclaus->value, "%s.value", cpath);
7236 } clause_list_iterate_end;
7237 } treaty_list_iterate_end;
7240 /* =======================================================================
7241 * Load / save the history report
7242 * ======================================================================= */
7244 /****************************************************************************
7245 Load '[history]'.
7246 ****************************************************************************/
7247 static void sg_load_history(struct loaddata *loading)
7249 struct history_report *hist = history_report_get();
7250 int turn;
7252 turn = secfile_lookup_int_default(loading->file, -2, "history.turn");
7254 if (turn + 1 >= game.info.turn) {
7255 const char *str;
7257 hist->turn = turn;
7258 str = secfile_lookup_str(loading->file, "history.title");
7259 sg_failure_ret(str != NULL, "%s", secfile_error());
7260 strncpy(hist->title, str, REPORT_TITLESIZE);
7261 str = secfile_lookup_str(loading->file, "history.body");
7262 sg_failure_ret(str != NULL, "%s", secfile_error());
7263 strncpy(hist->body, str, REPORT_BODYSIZE);
7267 /****************************************************************************
7268 Save '[history]'.
7269 ****************************************************************************/
7270 static void sg_save_history(struct savedata *saving)
7272 struct history_report *hist = history_report_get();
7274 secfile_insert_int(saving->file, hist->turn, "history.turn");
7276 if (hist->turn + 1 >= game.info.turn) {
7277 secfile_insert_str(saving->file, hist->title, "history.title");
7278 secfile_insert_str(saving->file, hist->body, "history.body");
7282 /* =======================================================================
7283 * Load / save the mapimg definitions.
7284 * ======================================================================= */
7286 /****************************************************************************
7287 Load '[mapimg]'.
7288 ****************************************************************************/
7289 static void sg_load_mapimg(struct loaddata *loading)
7291 int mapdef_count, i;
7293 /* Check status and return if not OK (sg_success != TRUE). */
7294 sg_check_ret();
7296 /* Clear all defined map images. */
7297 while (mapimg_count() > 0) {
7298 mapimg_delete(0);
7301 mapdef_count = secfile_lookup_int_default(loading->file, 0,
7302 "mapimg.count");
7303 log_verbose("Saved map image definitions: %d.", mapdef_count);
7305 if (0 >= mapdef_count) {
7306 return;
7309 for (i = 0; i < mapdef_count; i++) {
7310 const char *p;
7312 p = secfile_lookup_str(loading->file, "mapimg.mapdef%d", i);
7313 if (NULL == p) {
7314 log_verbose("[Mapimg %4d] Missing definition.", i);
7315 continue;
7318 if (!mapimg_define(p, FALSE)) {
7319 log_error("Invalid map image definition %4d: %s.", i, p);
7322 log_verbose("Mapimg %4d loaded.", i);
7326 /****************************************************************************
7327 Save '[mapimg]'.
7328 ****************************************************************************/
7329 static void sg_save_mapimg(struct savedata *saving)
7331 /* Check status and return if not OK (sg_success != TRUE). */
7332 sg_check_ret();
7334 secfile_insert_int(saving->file, mapimg_count(), "mapimg.count");
7335 if (mapimg_count() > 0) {
7336 int i;
7338 for (i = 0; i < mapimg_count(); i++) {
7339 char buf[MAX_LEN_MAPDEF];
7341 mapimg_id2str(i, buf, sizeof(buf));
7342 secfile_insert_str(saving->file, buf, "mapimg.mapdef%d", i);
7347 /* =======================================================================
7348 * Sanity checks for loading / saving a game.
7349 * ======================================================================= */
7351 /****************************************************************************
7352 Sanity check for loaded game.
7353 ****************************************************************************/
7354 static void sg_load_sanitycheck(struct loaddata *loading)
7356 int players;
7358 /* Check status and return if not OK (sg_success != TRUE). */
7359 sg_check_ret();
7361 if (game.info.is_new_game) {
7362 /* Nothing to do for new games (or not started scenarios). */
7363 return;
7366 /* Old savegames may have maxplayers lower than current player count,
7367 * fix. */
7368 players = normal_player_count();
7369 if (game.server.max_players < players) {
7370 log_verbose("Max players lower than current players, fixing");
7371 game.server.max_players = players;
7374 /* Fix ferrying sanity */
7375 players_iterate(pplayer) {
7376 unit_list_iterate_safe(pplayer->units, punit) {
7377 if (!unit_transport_get(punit)
7378 && !can_unit_exist_at_tile(punit, unit_tile(punit))) {
7379 log_sg("Removing %s unferried %s in %s at (%d, %d)",
7380 nation_rule_name(nation_of_player(pplayer)),
7381 unit_rule_name(punit),
7382 terrain_rule_name(unit_tile(punit)->terrain),
7383 TILE_XY(unit_tile(punit)));
7384 bounce_unit(punit, TRUE);
7386 } unit_list_iterate_safe_end;
7387 } players_iterate_end;
7389 /* Fix stacking issues. We don't rely on the savegame preserving
7390 * alliance invariants (old savegames often did not) so if there are any
7391 * unallied units on the same tile we just bounce them. */
7392 players_iterate(pplayer) {
7393 players_iterate(aplayer) {
7394 resolve_unit_stacks(pplayer, aplayer, TRUE);
7395 } players_iterate_end;
7397 /* Backward compatibility: if we had any open-ended orders (pillage)
7398 * in the savegame, assign specific targets now */
7399 unit_list_iterate(pplayer->units, punit) {
7400 unit_assign_specific_activity_target(punit,
7401 &punit->activity,
7402 &punit->activity_target);
7403 } unit_list_iterate_end;
7404 } players_iterate_end;
7406 /* Recalculate the potential buildings for each city. Has caused some
7407 * problems with game random state.
7408 * This also changes the game state if you save the game directly after
7409 * loading it and compare the results. */
7410 players_iterate(pplayer) {
7411 bool saved_ai_control = pplayer->ai_controlled;
7413 /* Recalculate for all players. */
7414 pplayer->ai_controlled = FALSE;
7416 /* Building advisor needs data phase open in order to work */
7417 adv_data_phase_init(pplayer, FALSE);
7418 building_advisor(pplayer);
7419 /* Close data phase again so it can be opened again when game starts. */
7420 adv_data_phase_done(pplayer);
7422 pplayer->ai_controlled = saved_ai_control;
7423 } players_iterate_end;
7425 /* Check worked tiles map */
7426 #ifdef DEBUG
7427 if (loading->worked_tiles != NULL) {
7428 /* check the entire map for unused worked tiles */
7429 whole_map_iterate(ptile) {
7430 if (loading->worked_tiles[ptile->index] != -1) {
7431 log_error("[city id: %d] Unused worked tile at (%d, %d).",
7432 loading->worked_tiles[ptile->index], TILE_XY(ptile));
7434 } whole_map_iterate_end;
7436 #endif /* DEBUG */
7438 /* Check researching technologies and goals. */
7439 researches_iterate(presearch) {
7440 if (presearch->researching != A_UNSET
7441 && !is_future_tech(presearch->researching)
7442 && (valid_advance_by_number(presearch->researching) == NULL
7443 || (research_invention_state(presearch, presearch->researching)
7444 != TECH_PREREQS_KNOWN))) {
7445 log_sg(_("%s had invalid researching technology."),
7446 research_name_translation(presearch));
7447 presearch->researching = A_UNSET;
7449 if (presearch->tech_goal != A_UNSET
7450 && !is_future_tech(presearch->tech_goal)
7451 && (valid_advance_by_number(presearch->researching) == NULL
7452 || !research_invention_reachable(presearch, presearch->tech_goal)
7453 || (research_invention_state(presearch, presearch->tech_goal)
7454 == TECH_KNOWN))) {
7455 log_sg(_("%s had invalid technology goal."),
7456 research_name_translation(presearch));
7457 presearch->tech_goal = A_UNSET;
7459 } researches_iterate_end;
7461 if (0 == strlen(server.game_identifier)
7462 || !is_base64url(server.game_identifier)) {
7463 /* This uses fc_rand(), so random state has to be initialized before. */
7464 randomize_base64url_string(server.game_identifier,
7465 sizeof(server.game_identifier));
7468 /* Check if some player has more than one of some UTYF_UNIQUE unit type */
7469 players_iterate(pplayer) {
7470 int unique_count[U_LAST];
7472 memset(unique_count, 0, sizeof(unique_count));
7474 unit_list_iterate(pplayer->units, punit) {
7475 unique_count[utype_index(unit_type_get(punit))]++;
7476 } unit_list_iterate_end;
7478 unit_type_iterate(ut) {
7479 if (unique_count[utype_index(ut)] > 1 && utype_has_flag(ut, UTYF_UNIQUE)) {
7480 log_sg(_("%s has multiple units of type %s though it should be possible "
7481 "to have only one."),
7482 player_name(pplayer), utype_name_translation(ut));
7484 } unit_type_iterate_end;
7485 } players_iterate_end;
7487 /* Restore game random state, just in case various initialization code
7488 * inexplicably altered the previously existing state. */
7489 if (!game.info.is_new_game) {
7490 fc_rand_set_state(loading->rstate);
7492 if (loading->version < 30) {
7493 /* For older savegames we have to recalculate the score with current data,
7494 * instead of using beginning-of-turn saved scores. */
7495 players_iterate(pplayer) {
7496 calc_civ_score(pplayer);
7497 } players_iterate_end;
7501 /* At the end do the default sanity checks. */
7502 sanity_check();
7505 /****************************************************************************
7506 Sanity check for saved game.
7507 ****************************************************************************/
7508 static void sg_save_sanitycheck(struct savedata *saving)
7510 /* Check status and return if not OK (sg_success != TRUE). */
7511 sg_check_ret();