webperimental: killstack decides stack protects.
[freeciv.git] / server / savegame3.c
blob11da6e8a353e528353268fe6d987afb0696ac9d6
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 3.0. It is defined by the mandatory option '+version3'. The main load
17 function checks if this option is present. If not, the old (pre-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 function for saving is savegame3_save().
27 - The real work is done by savegame3_load() and savegame3_save_real().
28 This function call all submodules (settings, players, etc.)
30 - The remaining part of this file is split into several sections:
31 * helper functions
32 * save / load functions for all submodules (and their subsubmodules)
34 - If possible, all functions for load / save submodules should exit in
35 pairs named sg_load_<submodule> and sg_save_<submodule>. If one is not
36 needed please add a comment why.
38 - The submodules can be further divided as:
39 sg_load_<submodule>_<subsubmodule>
41 - If needed (due to static variables in the *.c files) these functions
42 can be located in the corresponding source files (as done for the settings
43 and the event_cache).
45 Creating a savegame:
47 (nothing at the moment)
49 Loading a savegame:
51 - The status of the process is saved within the static variable
52 'sg_success'. This variable is set to TRUE within savegame3_load().
53 If you encounter an error use sg_failure_*() to set it to FALSE and
54 return an error message. Furthermore, sg_check_* should be used at the
55 start of each (submodule) function to return if previous functions failed.
57 - While the loading process dependencies between different modules exits.
58 They can be handled within the struct loaddata *loading which is used as
59 first argument for all sg_load_*() function. Please indicate the
60 dependencies within the definition of this struct.
64 #ifdef HAVE_CONFIG_H
65 #include <fc_config.h>
66 #endif
68 #include <ctype.h>
69 #include <stdarg.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
74 /* utility */
75 #include "bitvector.h"
76 #include "fcintl.h"
77 #include "idex.h"
78 #include "log.h"
79 #include "mem.h"
80 #include "rand.h"
81 #include "registry.h"
82 #include "shared.h"
83 #include "support.h" /* bool type */
84 #include "timing.h"
86 /* common */
87 #include "achievements.h"
88 #include "ai.h"
89 #include "bitvector.h"
90 #include "capability.h"
91 #include "citizens.h"
92 #include "city.h"
93 #include "game.h"
94 #include "government.h"
95 #include "map.h"
96 #include "mapimg.h"
97 #include "movement.h"
98 #include "multipliers.h"
99 #include "packets.h"
100 #include "research.h"
101 #include "rgbcolor.h"
102 #include "specialist.h"
103 #include "unit.h"
104 #include "unitlist.h"
105 #include "version.h"
107 /* server */
108 #include "barbarian.h"
109 #include "citizenshand.h"
110 #include "citytools.h"
111 #include "cityturn.h"
112 #include "diplhand.h"
113 #include "maphand.h"
114 #include "meta.h"
115 #include "notify.h"
116 #include "plrhand.h"
117 #include "report.h"
118 #include "ruleset.h"
119 #include "sanitycheck.h"
120 #include "savecompat.h"
121 #include "score.h"
122 #include "settings.h"
123 #include "spacerace.h"
124 #include "srv_main.h"
125 #include "stdinhand.h"
126 #include "techtools.h"
127 #include "unittools.h"
129 /* server/advisors */
130 #include "advdata.h"
131 #include "advbuilding.h"
132 #include "infracache.h"
134 /* server/generator */
135 #include "mapgen.h"
136 #include "mapgen_utils.h"
138 /* server/scripting */
139 #include "script_server.h"
141 /* ai */
142 #include "aitraits.h"
143 #include "difficulty.h"
145 #include "savegame3.h"
147 extern bool sg_success;
149 #ifdef FREECIV_TESTMATIC
150 #define SAVE_DUMMY_TURN_CHANGE_TIME 1
151 #endif
154 * This loops over the entire map to save data. It collects all the data of
155 * a line using GET_XY_CHAR and then executes the macro SECFILE_INSERT_LINE.
157 * Parameters:
158 * ptile: current tile within the line (used by GET_XY_CHAR)
159 * GET_XY_CHAR: macro returning the map character for each position
160 * secfile: a secfile struct
161 * secpath, ...: path as used for sprintf() with arguments; the last item
162 * will be the the y coordinate
163 * Example:
164 * SAVE_MAP_CHAR(ptile, terrain2char(ptile->terrain), file, "map.t%04d");
166 #define SAVE_MAP_CHAR(ptile, GET_XY_CHAR, secfile, secpath, ...) \
168 char _line[wld.map.xsize + 1]; \
169 int _nat_x, _nat_y; \
171 for (_nat_y = 0; _nat_y < wld.map.ysize; _nat_y++) { \
172 for (_nat_x = 0; _nat_x < wld.map.xsize; _nat_x++) { \
173 struct tile *ptile = native_pos_to_tile(&(wld.map), _nat_x, _nat_y); \
174 fc_assert_action(ptile != NULL, continue); \
175 _line[_nat_x] = (GET_XY_CHAR); \
176 sg_failure_ret(fc_isprint(_line[_nat_x] & 0x7f), \
177 "Trying to write invalid map data at position " \
178 "(%d, %d) for path %s: '%c' (%d)", _nat_x, _nat_y, \
179 secpath, _line[_nat_x], _line[_nat_x]); \
181 _line[wld.map.xsize] = '\0'; \
182 secfile_insert_str(secfile, _line, secpath, ## __VA_ARGS__, _nat_y); \
187 * This loops over the entire map to load data. It inputs a line of data
188 * using the macro SECFILE_LOOKUP_LINE and then loops using the macro
189 * SET_XY_CHAR to load each char into the map at (map_x, map_y). Internal
190 * variables ch, map_x, map_y, nat_x, and nat_y are allocated within the
191 * macro but definable by the caller.
193 * Parameters:
194 * ch: a variable to hold a char (data for a single position,
195 * used by SET_XY_CHAR)
196 * ptile: current tile within the line (used by SET_XY_CHAR)
197 * SET_XY_CHAR: macro to load the map character at each (map_x, map_y)
198 * secfile: a secfile struct
199 * secpath, ...: path as used for sprintf() with arguments; the last item
200 * will be the the y coordinate
201 * Example:
202 * LOAD_MAP_CHAR(ch, ptile,
203 * map_get_player_tile(ptile, plr)->terrain
204 * = char2terrain(ch), file, "player%d.map_t%04d", plrno);
206 * Note: some (but not all) of the code this is replacing used to skip over
207 * lines that did not exist. This allowed for backward-compatibility.
208 * We could add another parameter that specified whether it was OK to
209 * skip the data, but there's not really much advantage to exiting
210 * early in this case. Instead, we let any map data type to be empty,
211 * and just print an informative warning message about it.
213 #define LOAD_MAP_CHAR(ch, ptile, SET_XY_CHAR, secfile, secpath, ...) \
215 int _nat_x, _nat_y; \
216 bool _printed_warning = FALSE; \
217 for (_nat_y = 0; _nat_y < wld.map.ysize; _nat_y++) { \
218 const char *_line = secfile_lookup_str(secfile, secpath, \
219 ## __VA_ARGS__, _nat_y); \
220 if (NULL == _line) { \
221 char buf[64]; \
222 fc_snprintf(buf, sizeof(buf), secpath, ## __VA_ARGS__, _nat_y); \
223 log_verbose("Line not found='%s'", buf); \
224 _printed_warning = TRUE; \
225 continue; \
226 } else if (strlen(_line) != wld.map.xsize) { \
227 char buf[64]; \
228 fc_snprintf(buf, sizeof(buf), secpath, ## __VA_ARGS__, _nat_y); \
229 log_verbose("Line too short (expected %d got %lu)='%s'", \
230 wld.map.xsize, (unsigned long) strlen(_line), buf); \
231 _printed_warning = TRUE; \
232 continue; \
234 for (_nat_x = 0; _nat_x < wld.map.xsize; _nat_x++) { \
235 const char ch = _line[_nat_x]; \
236 struct tile *ptile = native_pos_to_tile(&(wld.map), _nat_x, _nat_y); \
237 (SET_XY_CHAR); \
240 if (_printed_warning) { \
241 /* TRANS: Minor error message. */ \
242 log_sg(_("Saved game contains incomplete map data. This can" \
243 " happen with old saved games, or it may indicate an" \
244 " invalid saved game file. Proceed at your own risk.")); \
248 /* Iterate on the extras half-bytes */
249 #define halfbyte_iterate_extras(e, num_extras_types) \
251 int e; \
252 for (e = 0; 4 * e < (num_extras_types); e++) {
254 #define halfbyte_iterate_extras_end \
258 struct savedata {
259 struct section_file *file;
260 char secfile_options[512];
262 /* set by the caller */
263 const char *save_reason;
264 bool scenario;
266 /* Set in sg_save_game(); needed in sg_save_map_*(); ... */
267 bool save_players;
270 #define TOKEN_SIZE 10
272 static const char savefile_options_default[] =
273 " +version3";
274 /* The following savefile option are added if needed:
275 * - nothing at current version
276 * See also calls to sg_save_savefile_options(). */
278 static const char num_chars[] =
279 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-+";
281 static void savegame3_save_real(struct section_file *file,
282 const char *save_reason,
283 bool scenario);
284 static struct loaddata *loaddata_new(struct section_file *file);
285 static void loaddata_destroy(struct loaddata *loading);
287 static struct savedata *savedata_new(struct section_file *file,
288 const char *save_reason,
289 bool scenario);
290 static void savedata_destroy(struct savedata *saving);
292 static enum unit_orders char2order(char order);
293 static char order2char(enum unit_orders order);
294 static enum direction8 char2dir(char dir);
295 static char dir2char(enum direction8 dir);
296 static char activity2char(enum unit_activity activity);
297 static enum unit_activity char2activity(char activity);
298 static char *quote_block(const void *const data, int length);
299 static int unquote_block(const char *const quoted_, void *dest,
300 int dest_length);
301 static void worklist_load(struct section_file *file, struct worklist *pwl,
302 const char *path, ...);
303 static void worklist_save(struct section_file *file,
304 const struct worklist *pwl,
305 int max_length, const char *path, ...);
306 static void unit_ordering_calc(void);
307 static void unit_ordering_apply(void);
308 static void sg_extras_set(bv_extras *extras, char ch, struct extra_type **idx);
309 static char sg_extras_get(bv_extras extras, struct extra_type *presource,
310 const int *idx);
311 static char num2char(unsigned int num);
312 static int char2num(char ch);
313 static struct terrain *char2terrain(char ch);
314 static char terrain2char(const struct terrain *pterrain);
315 static Tech_type_id technology_load(struct section_file *file,
316 const char* path, int plrno);
317 static void technology_save(struct section_file *file,
318 const char* path, int plrno, Tech_type_id tech);
320 static void sg_load_savefile(struct loaddata *loading);
321 static void sg_save_savefile(struct savedata *saving);
322 static void sg_save_savefile_options(struct savedata *saving,
323 const char *option);
325 static void sg_load_game(struct loaddata *loading);
326 static void sg_save_game(struct savedata *saving);
328 static void sg_load_ruledata(struct loaddata *loading);
329 static void sg_save_ruledata(struct savedata *saving);
331 static void sg_load_random(struct loaddata *loading);
332 static void sg_save_random(struct savedata *saving);
334 static void sg_load_script(struct loaddata *loading);
335 static void sg_save_script(struct savedata *saving);
337 static void sg_load_scenario(struct loaddata *loading);
338 static void sg_save_scenario(struct savedata *saving);
340 static void sg_load_settings(struct loaddata *loading);
341 static void sg_save_settings(struct savedata *saving);
343 static void sg_load_map(struct loaddata *loading);
344 static void sg_save_map(struct savedata *saving);
345 static void sg_load_map_tiles(struct loaddata *loading);
346 static void sg_save_map_tiles(struct savedata *saving);
347 static void sg_load_map_tiles_extras(struct loaddata *loading);
348 static void sg_save_map_tiles_extras(struct savedata *saving);
350 static void sg_load_map_startpos(struct loaddata *loading);
351 static void sg_save_map_startpos(struct savedata *saving);
352 static void sg_load_map_owner(struct loaddata *loading);
353 static void sg_save_map_owner(struct savedata *saving);
354 static void sg_load_map_worked(struct loaddata *loading);
355 static void sg_save_map_worked(struct savedata *saving);
356 static void sg_load_map_known(struct loaddata *loading);
357 static void sg_save_map_known(struct savedata *saving);
359 static void sg_load_players_basic(struct loaddata *loading);
360 static void sg_load_players(struct loaddata *loading);
361 static void sg_load_player_main(struct loaddata *loading,
362 struct player *plr);
363 static void sg_load_player_cities(struct loaddata *loading,
364 struct player *plr);
365 static bool sg_load_player_city(struct loaddata *loading, struct player *plr,
366 struct city *pcity, const char *citystr);
367 static void sg_load_player_city_citizens(struct loaddata *loading,
368 struct player *plr,
369 struct city *pcity,
370 const char *citystr);
371 static void sg_load_player_units(struct loaddata *loading,
372 struct player *plr);
373 static bool sg_load_player_unit(struct loaddata *loading,
374 struct player *plr, struct unit *punit,
375 const char *unitstr);
376 static void sg_load_player_units_transport(struct loaddata *loading,
377 struct player *plr);
378 static void sg_load_player_attributes(struct loaddata *loading,
379 struct player *plr);
380 static void sg_load_player_vision(struct loaddata *loading,
381 struct player *plr);
382 static bool sg_load_player_vision_city(struct loaddata *loading,
383 struct player *plr,
384 struct vision_site *pdcity,
385 const char *citystr);
386 static void sg_save_players(struct savedata *saving);
387 static void sg_save_player_main(struct savedata *saving,
388 struct player *plr);
389 static void sg_save_player_cities(struct savedata *saving,
390 struct player *plr);
391 static void sg_save_player_units(struct savedata *saving,
392 struct player *plr);
393 static void sg_save_player_attributes(struct savedata *saving,
394 struct player *plr);
395 static void sg_save_player_vision(struct savedata *saving,
396 struct player *plr);
398 static void sg_load_researches(struct loaddata *loading);
399 static void sg_save_researches(struct savedata *saving);
401 static void sg_load_event_cache(struct loaddata *loading);
402 static void sg_save_event_cache(struct savedata *saving);
404 static void sg_load_treaties(struct loaddata *loading);
405 static void sg_save_treaties(struct savedata *saving);
407 static void sg_load_history(struct loaddata *loading);
408 static void sg_save_history(struct savedata *saving);
410 static void sg_load_mapimg(struct loaddata *loading);
411 static void sg_save_mapimg(struct savedata *saving);
413 static void sg_load_sanitycheck(struct loaddata *loading);
414 static void sg_save_sanitycheck(struct savedata *saving);
417 /****************************************************************************
418 Main entry point for saving a game in savegame3 format.
419 ****************************************************************************/
420 void savegame3_save(struct section_file *sfile, const char *save_reason,
421 bool scenario)
423 fc_assert_ret(sfile != NULL);
425 #ifdef DEBUG_TIMERS
426 struct timer *savetimer = timer_new(TIMER_CPU, TIMER_DEBUG);
427 timer_start(savetimer);
428 #endif
430 log_verbose("saving game in new format ...");
431 savegame3_save_real(sfile, save_reason, scenario);
433 #ifdef DEBUG_TIMERS
434 timer_stop(savetimer);
435 log_debug("Creating secfile in %.3f seconds.", timer_read_seconds(savetimer));
436 timer_destroy(savetimer);
437 #endif /* DEBUG_TIMERS */
440 /* =======================================================================
441 * Basic load / save functions.
442 * ======================================================================= */
444 /****************************************************************************
445 Really loading the savegame.
446 ****************************************************************************/
447 void savegame3_load(struct section_file *file)
449 struct loaddata *loading;
450 bool was_send_city_suppressed, was_send_tile_suppressed;
452 /* initialise loading */
453 was_send_city_suppressed = send_city_suppression(TRUE);
454 was_send_tile_suppressed = send_tile_suppression(TRUE);
455 loading = loaddata_new(file);
456 sg_success = TRUE;
458 /* Load the savegame data. */
459 /* [compat] */
460 sg_load_compat(loading, SAVEGAME_3);
461 /* [scenario] */
462 sg_load_scenario(loading);
463 /* [savefile] */
464 sg_load_savefile(loading);
465 /* [game] */
466 sg_load_game(loading);
467 /* [random] */
468 sg_load_random(loading);
469 /* [script] */
470 sg_load_script(loading);
471 /* [settings] */
472 sg_load_settings(loading);
473 /* [ruldata] */
474 sg_load_ruledata(loading);
475 /* [players] (basic data) */
476 sg_load_players_basic(loading);
477 /* [map]; needs width and height loaded by [settings] */
478 sg_load_map(loading);
479 /* [research] */
480 sg_load_researches(loading);
481 /* [player<i>] */
482 sg_load_players(loading);
483 /* [event_cache] */
484 sg_load_event_cache(loading);
485 /* [treaties] */
486 sg_load_treaties(loading);
487 /* [history] */
488 sg_load_history(loading);
489 /* [mapimg] */
490 sg_load_mapimg(loading);
492 /* Sanity checks for the loaded game. */
493 sg_load_sanitycheck(loading);
495 /* deinitialise loading */
496 loaddata_destroy(loading);
497 send_tile_suppression(was_send_tile_suppressed);
498 send_city_suppression(was_send_city_suppressed);
500 if (!sg_success) {
501 log_error("Failure loading savegame!");
502 game_reset();
506 /****************************************************************************
507 Really save the game to a file.
508 ****************************************************************************/
509 static void savegame3_save_real(struct section_file *file,
510 const char *save_reason,
511 bool scenario)
513 struct savedata *saving;
515 /* initialise loading */
516 saving = savedata_new(file, save_reason, scenario);
517 sg_success = TRUE;
519 /* [scenario] */
520 /* This should be first section so scanning through all scenarios just for
521 * names and descriptions would go faster. */
522 sg_save_scenario(saving);
523 /* [savefile] */
524 sg_save_savefile(saving);
525 /* [game] */
526 sg_save_game(saving);
527 /* [random] */
528 sg_save_random(saving);
529 /* [script] */
530 sg_save_script(saving);
531 /* [settings] */
532 sg_save_settings(saving);
533 /* [ruledata] */
534 sg_save_ruledata(saving);
535 /* [map] */
536 sg_save_map(saving);
537 /* [player<i>] */
538 sg_save_players(saving);
539 /* [research] */
540 sg_save_researches(saving);
541 /* [event_cache] */
542 sg_save_event_cache(saving);
543 /* [treaty<i>] */
544 sg_save_treaties(saving);
545 /* [history] */
546 sg_save_history(saving);
547 /* [mapimg] */
548 sg_save_mapimg(saving);
550 /* Sanity checks for the saved game. */
551 sg_save_sanitycheck(saving);
553 /* deinitialise saving */
554 savedata_destroy(saving);
556 if (!sg_success) {
557 log_error("Failure saving savegame!");
561 /****************************************************************************
562 Create new loaddata item for given section file.
563 ****************************************************************************/
564 static struct loaddata *loaddata_new(struct section_file *file)
566 struct loaddata *loading = calloc(1, sizeof(*loading));
567 loading->file = file;
568 loading->secfile_options = NULL;
570 loading->improvement.order = NULL;
571 loading->improvement.size = -1;
572 loading->technology.order = NULL;
573 loading->technology.size = -1;
574 loading->activities.order = NULL;
575 loading->activities.size = -1;
576 loading->trait.order = NULL;
577 loading->trait.size = -1;
578 loading->extra.order = NULL;
579 loading->extra.size = -1;
580 loading->multiplier.order = NULL;
581 loading->multiplier.size = -1;
582 loading->specialist.order = NULL;
583 loading->specialist.size = -1;
584 loading->action.order = NULL;
585 loading->action.size = -1;
586 loading->act_dec.order = NULL;
587 loading->act_dec.size = -1;
589 loading->server_state = S_S_INITIAL;
590 loading->rstate = fc_rand_state();
591 loading->worked_tiles = NULL;
593 return loading;
596 /****************************************************************************
597 Free resources allocated for loaddata item.
598 ****************************************************************************/
599 static void loaddata_destroy(struct loaddata *loading)
601 if (loading->improvement.order != NULL) {
602 free(loading->improvement.order);
605 if (loading->technology.order != NULL) {
606 free(loading->technology.order);
609 if (loading->activities.order != NULL) {
610 free(loading->activities.order);
613 if (loading->trait.order != NULL) {
614 free(loading->trait.order);
617 if (loading->extra.order != NULL) {
618 free(loading->extra.order);
621 if (loading->multiplier.order != NULL) {
622 free(loading->multiplier.order);
625 if (loading->specialist.order != NULL) {
626 free(loading->specialist.order);
629 if (loading->action.order != NULL) {
630 free(loading->action.order);
633 if (loading->act_dec.order != NULL) {
634 free(loading->act_dec.order);
637 if (loading->worked_tiles != NULL) {
638 free(loading->worked_tiles);
641 free(loading);
644 /****************************************************************************
645 Create new savedata item for given file.
646 ****************************************************************************/
647 static struct savedata *savedata_new(struct section_file *file,
648 const char *save_reason,
649 bool scenario)
651 struct savedata *saving = calloc(1, sizeof(*saving));
652 saving->file = file;
653 saving->secfile_options[0] = '\0';
655 saving->save_reason = save_reason;
656 saving->scenario = scenario;
658 saving->save_players = FALSE;
660 return saving;
663 /****************************************************************************
664 Free resources allocated for savedata item
665 ****************************************************************************/
666 static void savedata_destroy(struct savedata *saving)
668 free(saving);
671 /* =======================================================================
672 * Helper functions.
673 * ======================================================================= */
675 /****************************************************************************
676 Returns an order for a character identifier. See also order2char.
677 ****************************************************************************/
678 static enum unit_orders char2order(char order)
680 switch (order) {
681 case 'm':
682 case 'M':
683 return ORDER_MOVE;
684 case 'w':
685 case 'W':
686 return ORDER_FULL_MP;
687 case 'b':
688 case 'B':
689 #ifdef FREECIV_DEV_SAVE_COMPAT_3_0
690 /* Will be upgraded with sg_order_to_action(). */
691 return ORDER_OLD_BUILD_CITY;
692 #else /* FREECIV_DEV_SAVE_COMPAT_3_0 */
693 /* This order isn't supposed to show up in version 3 save games. */
694 log_error("Corrupt save game: build city ordered the old way.");
696 return ORDER_LAST;
697 #endif /* FREECIV_DEV_SAVE_COMPAT_3_0 */
698 case 'a':
699 case 'A':
700 return ORDER_ACTIVITY;
701 case 'd':
702 case 'D':
703 #ifdef FREECIV_DEV_SAVE_COMPAT_3_0
704 /* Will be upgraded with sg_order_to_action(). */
705 return ORDER_OLD_DISBAND;
706 #else /* FREECIV_DEV_SAVE_COMPAT_3_0 */
707 /* This order isn't supposed to show up in version 3 save games. */
708 log_error("Corrupt save game: disband unit ordered the old way.");
710 return ORDER_LAST;
711 #endif /* FREECIV_DEV_SAVE_COMPAT_3_0 */
712 case 'u':
713 case 'U':
714 #ifdef FREECIV_DEV_SAVE_COMPAT_3_0
715 /* Will be upgraded with sg_order_to_action(). */
716 return ORDER_OLD_BUILD_WONDER;
717 #else /* FREECIV_DEV_SAVE_COMPAT_3_0 */
718 /* This order isn't supposed to show up in version 3 save games. */
719 log_error("Corrupt save game: help build wonder ordered the old way.");
721 return ORDER_LAST;
722 #endif /* FREECIV_DEV_SAVE_COMPAT_3_0 */
723 case 't':
724 case 'T':
725 #ifdef FREECIV_DEV_SAVE_COMPAT_3_0
726 /* Will be upgraded with sg_order_to_action(). */
727 return ORDER_OLD_TRADE_ROUTE;
728 #else /* FREECIV_DEV_SAVE_COMPAT_3_0 */
729 /* This order isn't supposed to show up in version 3 save games. */
730 log_error("Corrupt save game: trade route ordered the old way.");
732 return ORDER_LAST;
733 #endif /* FREECIV_DEV_SAVE_COMPAT_3_0 */
734 case 'h':
735 case 'H':
736 #ifdef FREECIV_DEV_SAVE_COMPAT_3_0
737 /* Will be upgraded with sg_order_to_action(). */
738 return ORDER_OLD_HOMECITY;
739 #else /* FREECIV_DEV_SAVE_COMPAT_3_0 */
740 /* This order isn't supposed to show up in version 3 save games. */
741 log_error("Corrupt save game: change home city ordered the old way.");
743 return ORDER_LAST;
744 #endif /* FREECIV_DEV_SAVE_COMPAT_3_0 */
745 case 'x':
746 case 'X':
747 return ORDER_ACTION_MOVE;
748 case 'p':
749 case 'P':
750 return ORDER_PERFORM_ACTION;
753 /* This can happen if the savegame is invalid. */
754 return ORDER_LAST;
757 /****************************************************************************
758 Returns a character identifier for an order. See also char2order.
759 ****************************************************************************/
760 static char order2char(enum unit_orders order)
762 switch (order) {
763 case ORDER_MOVE:
764 return 'm';
765 case ORDER_FULL_MP:
766 return 'w';
767 case ORDER_ACTIVITY:
768 return 'a';
769 case ORDER_ACTION_MOVE:
770 return 'x';
771 case ORDER_PERFORM_ACTION:
772 return 'p';
773 case ORDER_LAST:
774 break;
777 fc_assert(FALSE);
778 return '?';
781 /****************************************************************************
782 Returns a direction for a character identifier. See also dir2char.
783 ****************************************************************************/
784 static enum direction8 char2dir(char dir)
786 /* Numberpad values for the directions. */
787 switch (dir) {
788 case '1':
789 return DIR8_SOUTHWEST;
790 case '2':
791 return DIR8_SOUTH;
792 case '3':
793 return DIR8_SOUTHEAST;
794 case '4':
795 return DIR8_WEST;
796 case '6':
797 return DIR8_EAST;
798 case '7':
799 return DIR8_NORTHWEST;
800 case '8':
801 return DIR8_NORTH;
802 case '9':
803 return DIR8_NORTHEAST;
806 /* This can happen if the savegame is invalid. */
807 return direction8_invalid();
810 /****************************************************************************
811 Returns a character identifier for a direction. See also char2dir.
812 ****************************************************************************/
813 static char dir2char(enum direction8 dir)
815 /* Numberpad values for the directions. */
816 switch (dir) {
817 case DIR8_NORTH:
818 return '8';
819 case DIR8_SOUTH:
820 return '2';
821 case DIR8_EAST:
822 return '6';
823 case DIR8_WEST:
824 return '4';
825 case DIR8_NORTHEAST:
826 return '9';
827 case DIR8_NORTHWEST:
828 return '7';
829 case DIR8_SOUTHEAST:
830 return '3';
831 case DIR8_SOUTHWEST:
832 return '1';
835 fc_assert(FALSE);
836 return '?';
839 /****************************************************************************
840 Returns a character identifier for an activity. See also char2activity.
841 ****************************************************************************/
842 static char activity2char(enum unit_activity activity)
844 switch (activity) {
845 case ACTIVITY_IDLE:
846 return 'w';
847 case ACTIVITY_POLLUTION:
848 return 'p';
849 case ACTIVITY_OLD_ROAD:
850 return 'r';
851 case ACTIVITY_MINE:
852 return 'm';
853 case ACTIVITY_IRRIGATE:
854 return 'i';
855 case ACTIVITY_FORTIFIED:
856 return 'f';
857 case ACTIVITY_FORTRESS:
858 return 't';
859 case ACTIVITY_SENTRY:
860 return 's';
861 case ACTIVITY_OLD_RAILROAD:
862 return 'l';
863 case ACTIVITY_PILLAGE:
864 return 'e';
865 case ACTIVITY_GOTO:
866 return 'g';
867 case ACTIVITY_EXPLORE:
868 return 'x';
869 case ACTIVITY_TRANSFORM:
870 return 'o';
871 case ACTIVITY_AIRBASE:
872 return 'a';
873 case ACTIVITY_FORTIFYING:
874 return 'y';
875 case ACTIVITY_FALLOUT:
876 return 'u';
877 case ACTIVITY_BASE:
878 return 'b';
879 case ACTIVITY_GEN_ROAD:
880 return 'R';
881 case ACTIVITY_CONVERT:
882 return 'c';
883 case ACTIVITY_UNKNOWN:
884 case ACTIVITY_PATROL_UNUSED:
885 return '?';
886 case ACTIVITY_LAST:
887 break;
890 fc_assert(FALSE);
891 return '?';
894 /****************************************************************************
895 Returns an activity for a character identifier. See also activity2char.
896 ****************************************************************************/
897 static enum unit_activity char2activity(char activity)
899 enum unit_activity a;
901 for (a = 0; a < ACTIVITY_LAST; a++) {
902 char achar = activity2char(a);
904 if (activity == achar) {
905 return a;
909 /* This can happen if the savegame is invalid. */
910 return ACTIVITY_LAST;
913 /****************************************************************************
914 Quote the memory block denoted by data and length so it consists only of
915 " a-f0-9:". The returned string has to be freed by the caller using free().
916 ****************************************************************************/
917 static char *quote_block(const void *const data, int length)
919 char *buffer = fc_malloc(length * 3 + 10);
920 size_t offset;
921 int i;
923 sprintf(buffer, "%d:", length);
924 offset = strlen(buffer);
926 for (i = 0; i < length; i++) {
927 sprintf(buffer + offset, "%02x ", ((unsigned char *) data)[i]);
928 offset += 3;
930 return buffer;
933 /****************************************************************************
934 Unquote a string. The unquoted data is written into dest. If the unquoted
935 data will be larger than dest_length the function aborts. It returns the
936 actual length of the unquoted block.
937 ****************************************************************************/
938 static int unquote_block(const char *const quoted_, void *dest,
939 int dest_length)
941 int i, length, parsed, tmp;
942 char *endptr;
943 const char *quoted = quoted_;
945 parsed = sscanf(quoted, "%d", &length);
946 fc_assert_ret_val(1 == parsed, 0);
948 if (length > dest_length) {
949 return 0;
951 quoted = strchr(quoted, ':');
952 fc_assert_ret_val(quoted != NULL, 0);
953 quoted++;
955 for (i = 0; i < length; i++) {
956 tmp = strtol(quoted, &endptr, 16);
957 fc_assert_ret_val((endptr - quoted) == 2, 0);
958 fc_assert_ret_val(*endptr == ' ', 0);
959 fc_assert_ret_val((tmp & 0xff) == tmp, 0);
960 ((unsigned char *) dest)[i] = tmp;
961 quoted += 3;
963 return length;
966 /****************************************************************************
967 Load the worklist elements specified by path to the worklist pointed to
968 by 'pwl'. 'pwl' should be a pointer to an existing worklist.
969 ****************************************************************************/
970 static void worklist_load(struct section_file *file, struct worklist *pwl,
971 const char *path, ...)
973 int i;
974 const char *kind;
975 const char *name;
976 char path_str[1024];
977 va_list ap;
979 /* The first part of the registry path is taken from the varargs to the
980 * function. */
981 va_start(ap, path);
982 fc_vsnprintf(path_str, sizeof(path_str), path, ap);
983 va_end(ap);
985 worklist_init(pwl);
986 pwl->length = secfile_lookup_int_default(file, 0,
987 "%s.wl_length", path_str);
989 for (i = 0; i < pwl->length; i++) {
990 kind = secfile_lookup_str(file, "%s.wl_kind%d", path_str, i);
992 /* We lookup the production value by name. An invalid entry isn't a
993 * fatal error; we just truncate the worklist. */
994 name = secfile_lookup_str_default(file, "-", "%s.wl_value%d",
995 path_str, i);
996 pwl->entries[i] = universal_by_rule_name(kind, name);
997 if (pwl->entries[i].kind == universals_n_invalid()) {
998 log_sg("%s.wl_value%d: unknown \"%s\" \"%s\".", path_str, i, kind,
999 name);
1000 pwl->length = i;
1001 break;
1006 /****************************************************************************
1007 Save the worklist elements specified by path from the worklist pointed to
1008 by 'pwl'. 'pwl' should be a pointer to an existing worklist.
1009 ****************************************************************************/
1010 static void worklist_save(struct section_file *file,
1011 const struct worklist *pwl,
1012 int max_length, const char *path, ...)
1014 char path_str[1024];
1015 int i;
1016 va_list ap;
1018 /* The first part of the registry path is taken from the varargs to the
1019 * function. */
1020 va_start(ap, path);
1021 fc_vsnprintf(path_str, sizeof(path_str), path, ap);
1022 va_end(ap);
1024 secfile_insert_int(file, pwl->length, "%s.wl_length", path_str);
1026 for (i = 0; i < pwl->length; i++) {
1027 const struct universal *entry = pwl->entries + i;
1028 secfile_insert_str(file, universal_type_rule_name(entry),
1029 "%s.wl_kind%d", path_str, i);
1030 secfile_insert_str(file, universal_rule_name(entry),
1031 "%s.wl_value%d", path_str, i);
1034 fc_assert_ret(max_length <= MAX_LEN_WORKLIST);
1036 /* We want to keep savegame in tabular format, so each line has to be
1037 * of equal length. Fill table up to maximum worklist size. */
1038 for (i = pwl->length ; i < max_length; i++) {
1039 secfile_insert_str(file, "", "%s.wl_kind%d", path_str, i);
1040 secfile_insert_str(file, "", "%s.wl_value%d", path_str, i);
1044 /****************************************************************************
1045 Assign values to ord_city and ord_map for each unit, so the values can be
1046 saved.
1047 ****************************************************************************/
1048 static void unit_ordering_calc(void)
1050 int j;
1052 players_iterate(pplayer) {
1053 /* to avoid junk values for unsupported units: */
1054 unit_list_iterate(pplayer->units, punit) {
1055 punit->server.ord_city = 0;
1056 } unit_list_iterate_end;
1057 city_list_iterate(pplayer->cities, pcity) {
1058 j = 0;
1059 unit_list_iterate(pcity->units_supported, punit) {
1060 punit->server.ord_city = j++;
1061 } unit_list_iterate_end;
1062 } city_list_iterate_end;
1063 } players_iterate_end;
1065 whole_map_iterate(&(wld.map), ptile) {
1066 j = 0;
1067 unit_list_iterate(ptile->units, punit) {
1068 punit->server.ord_map = j++;
1069 } unit_list_iterate_end;
1070 } whole_map_iterate_end;
1073 /****************************************************************************
1074 For each city and tile, sort unit lists according to ord_city and ord_map
1075 values.
1076 ****************************************************************************/
1077 static void unit_ordering_apply(void)
1079 players_iterate(pplayer) {
1080 city_list_iterate(pplayer->cities, pcity) {
1081 unit_list_sort_ord_city(pcity->units_supported);
1083 city_list_iterate_end;
1084 } players_iterate_end;
1086 whole_map_iterate(&(wld.map), ptile) {
1087 unit_list_sort_ord_map(ptile->units);
1088 } whole_map_iterate_end;
1091 /****************************************************************************
1092 Helper function for loading extras from a savegame.
1094 'ch' gives the character loaded from the savegame. Extras are packed
1095 in four to a character in hex notation. 'index' is a mapping of
1096 savegame bit -> base bit.
1097 ****************************************************************************/
1098 static void sg_extras_set(bv_extras *extras, char ch, struct extra_type **idx)
1100 int i, bin;
1101 const char *pch = strchr(hex_chars, ch);
1103 if (!pch || ch == '\0') {
1104 log_sg("Unknown hex value: '%c' (%d)", ch, ch);
1105 bin = 0;
1106 } else {
1107 bin = pch - hex_chars;
1110 for (i = 0; i < 4; i++) {
1111 struct extra_type *pextra = idx[i];
1113 if (pextra == NULL) {
1114 continue;
1116 if ((bin & (1 << i))
1117 && (wld.map.server.have_huts || !is_extra_caused_by(pextra, EC_HUT))) {
1118 BV_SET(*extras, extra_index(pextra));
1123 /****************************************************************************
1124 Helper function for saving extras into a savegame.
1126 Extras are packed in four to a character in hex notation. 'index'
1127 specifies which set of extras are included in this character.
1128 ****************************************************************************/
1129 static char sg_extras_get(bv_extras extras, struct extra_type *presource,
1130 const int *idx)
1132 int i, bin = 0;
1134 for (i = 0; i < 4; i++) {
1135 int extra = idx[i];
1137 if (extra < 0) {
1138 break;
1141 if (BV_ISSET(extras, extra)
1142 /* An invalid resource, a resource that can't exist at the tile's
1143 * current terrain, isn't in the bit extra vector. Save it so it
1144 * can return if the tile's terrain changes to something it can
1145 * exist on. */
1146 || extra_by_number(extra) == presource) {
1147 bin |= (1 << i);
1151 return hex_chars[bin];
1154 /****************************************************************************
1155 Converts number in to single character. This works to values up to ~70.
1156 ****************************************************************************/
1157 static char num2char(unsigned int num)
1159 if (num >= strlen(num_chars)) {
1160 return '?';
1163 return num_chars[num];
1166 /****************************************************************************
1167 Converts single character into numerical value. This is not hex conversion.
1168 ****************************************************************************/
1169 static int char2num(char ch)
1171 const char *pch;
1173 pch = strchr(num_chars, ch);
1175 sg_failure_ret_val(NULL != pch, 0,
1176 "Unknown ascii value for num: '%c' %d", ch, ch);
1178 return pch - num_chars;
1181 /****************************************************************************
1182 Dereferences the terrain character. See terrains[].identifier
1183 example: char2terrain('a') => T_ARCTIC
1184 ****************************************************************************/
1185 static struct terrain *char2terrain(char ch)
1187 /* terrain_by_identifier plus fatal error */
1188 if (ch == TERRAIN_UNKNOWN_IDENTIFIER) {
1189 return T_UNKNOWN;
1191 terrain_type_iterate(pterrain) {
1192 if (pterrain->identifier_load == ch) {
1193 return pterrain;
1195 } terrain_type_iterate_end;
1197 log_fatal("Unknown terrain identifier '%c' in savegame.", ch);
1198 exit(EXIT_FAILURE);
1201 /****************************************************************************
1202 References the terrain character. See terrains[].identifier
1203 example: terrain2char(T_ARCTIC) => 'a'
1204 ****************************************************************************/
1205 static char terrain2char(const struct terrain *pterrain)
1207 if (pterrain == T_UNKNOWN) {
1208 return TERRAIN_UNKNOWN_IDENTIFIER;
1209 } else {
1210 return pterrain->identifier;
1214 /*****************************************************************************
1215 Load technology from path_name and if doesn't exist (because savegame
1216 is too old) load from path.
1217 *****************************************************************************/
1218 static Tech_type_id technology_load(struct section_file *file,
1219 const char* path, int plrno)
1221 char path_with_name[128];
1222 const char* name;
1223 struct advance *padvance;
1225 fc_snprintf(path_with_name, sizeof(path_with_name),
1226 "%s_name", path);
1228 name = secfile_lookup_str(file, path_with_name, plrno);
1230 if (!name || name[0] == '\0') {
1231 /* used by researching_saved */
1232 return A_UNKNOWN;
1234 if (fc_strcasecmp(name, "A_FUTURE") == 0) {
1235 return A_FUTURE;
1237 if (fc_strcasecmp(name, "A_NONE") == 0) {
1238 return A_NONE;
1240 if (fc_strcasecmp(name, "A_UNSET") == 0) {
1241 return A_UNSET;
1244 padvance = advance_by_rule_name(name);
1245 sg_failure_ret_val(NULL != padvance, A_NONE,
1246 "%s: unknown technology \"%s\".", path_with_name, name);
1248 return advance_number(padvance);
1251 /*****************************************************************************
1252 Save technology in secfile entry called path_name.
1253 *****************************************************************************/
1254 static void technology_save(struct section_file *file,
1255 const char* path, int plrno, Tech_type_id tech)
1257 char path_with_name[128];
1258 const char* name;
1260 fc_snprintf(path_with_name, sizeof(path_with_name),
1261 "%s_name", path);
1263 switch (tech) {
1264 case A_UNKNOWN: /* used by researching_saved */
1265 name = "";
1266 break;
1267 case A_NONE:
1268 name = "A_NONE";
1269 break;
1270 case A_UNSET:
1271 name = "A_UNSET";
1272 break;
1273 case A_FUTURE:
1274 name = "A_FUTURE";
1275 break;
1276 default:
1277 name = advance_rule_name(advance_by_number(tech));
1278 break;
1281 secfile_insert_str(file, name, path_with_name, plrno);
1284 /* =======================================================================
1285 * Load / save savefile data.
1286 * ======================================================================= */
1288 /****************************************************************************
1289 Load '[savefile]'.
1290 ****************************************************************************/
1291 static void sg_load_savefile(struct loaddata *loading)
1293 int i;
1294 const char *terr_name;
1296 /* Check status and return if not OK (sg_success != TRUE). */
1297 sg_check_ret();
1299 /* Load savefile options. */
1300 loading->secfile_options
1301 = secfile_lookup_str(loading->file, "savefile.options");
1303 /* We don't need these entries, but read them anyway to avoid
1304 * warnings about unread secfile entries. */
1305 (void) secfile_entry_by_path(loading->file, "savefile.reason");
1306 (void) secfile_entry_by_path(loading->file, "savefile.revision");
1308 if (!game.scenario.is_scenario || game.scenario.ruleset_locked) {
1309 /* Load ruleset. */
1310 sz_strlcpy(game.server.rulesetdir,
1311 secfile_lookup_str_default(loading->file, GAME_DEFAULT_RULESETDIR,
1312 "savefile.rulesetdir"));
1313 if (!strcmp("default", game.server.rulesetdir)) {
1314 /* Here 'default' really means current default.
1315 * Saving happens with real ruleset name, so savegames containing this
1316 * are special scenarios. */
1317 sz_strlcpy(game.server.rulesetdir, GAME_DEFAULT_RULESETDIR);
1321 if (!load_rulesets(NULL, FALSE, TRUE, FALSE)) {
1322 /* Failed to load correct ruleset */
1323 sg_failure_ret(FALSE, "Failed to load ruleset");
1326 if (game.scenario.is_scenario && !game.scenario.ruleset_locked) {
1327 const char *req_caps;
1328 req_caps = secfile_lookup_str_default(loading->file, "",
1329 "scenario.ruleset_caps");
1331 if (!has_capabilities(req_caps, game.ruleset_capabilities)) {
1332 /* Current ruleset lacks required capabilities. */
1333 log_normal(_("Scenario requires ruleset capabilities: %s"), req_caps);
1334 log_normal(_("Ruleset has capabilities: %s"), game.ruleset_capabilities);
1335 log_error(_("Current ruleset not compatible with the scenario."));
1336 sg_success = FALSE;
1337 return;
1341 /* This is in the savegame only if the game has been started before savegame3.c time,
1342 * and in that case it's TRUE. If it's missing, it's to be considered FALSE. */
1343 game.server.last_updated_year = secfile_lookup_bool_default(loading->file, FALSE,
1344 "savefile.last_updated_as_year");
1346 /* Load improvements. */
1347 loading->improvement.size
1348 = secfile_lookup_int_default(loading->file, 0,
1349 "savefile.improvement_size");
1350 if (loading->improvement.size) {
1351 loading->improvement.order
1352 = secfile_lookup_str_vec(loading->file, &loading->improvement.size,
1353 "savefile.improvement_vector");
1354 sg_failure_ret(loading->improvement.size != 0,
1355 "Failed to load improvement order: %s",
1356 secfile_error());
1359 /* Load technologies. */
1360 loading->technology.size
1361 = secfile_lookup_int_default(loading->file, 0,
1362 "savefile.technology_size");
1363 if (loading->technology.size) {
1364 loading->technology.order
1365 = secfile_lookup_str_vec(loading->file, &loading->technology.size,
1366 "savefile.technology_vector");
1367 sg_failure_ret(loading->technology.size != 0,
1368 "Failed to load technology order: %s",
1369 secfile_error());
1372 /* Load Activities. */
1373 loading->activities.size
1374 = secfile_lookup_int_default(loading->file, 0,
1375 "savefile.activities_size");
1376 if (loading->activities.size) {
1377 loading->activities.order
1378 = secfile_lookup_str_vec(loading->file, &loading->activities.size,
1379 "savefile.activities_vector");
1380 sg_failure_ret(loading->activities.size != 0,
1381 "Failed to load activity order: %s",
1382 secfile_error());
1385 /* Load traits. */
1386 loading->trait.size
1387 = secfile_lookup_int_default(loading->file, 0,
1388 "savefile.trait_size");
1389 if (loading->trait.size) {
1390 loading->trait.order
1391 = secfile_lookup_str_vec(loading->file, &loading->trait.size,
1392 "savefile.trait_vector");
1393 sg_failure_ret(loading->trait.size != 0,
1394 "Failed to load trait order: %s",
1395 secfile_error());
1398 /* Load extras. */
1399 loading->extra.size
1400 = secfile_lookup_int_default(loading->file, 0,
1401 "savefile.extras_size");
1402 if (loading->extra.size) {
1403 const char **modname;
1404 size_t nmod;
1405 int j;
1407 modname = secfile_lookup_str_vec(loading->file, &loading->extra.size,
1408 "savefile.extras_vector");
1409 sg_failure_ret(loading->extra.size != 0,
1410 "Failed to load extras order: %s",
1411 secfile_error());
1412 sg_failure_ret(!(game.control.num_extra_types < loading->extra.size),
1413 "Number of extras defined by the ruleset (= %d) are "
1414 "lower than the number in the savefile (= %d).",
1415 game.control.num_extra_types, (int)loading->extra.size);
1416 /* make sure that the size of the array is divisible by 4 */
1417 nmod = 4 * ((loading->extra.size + 3) / 4);
1418 loading->extra.order = fc_calloc(nmod, sizeof(*loading->extra.order));
1419 for (j = 0; j < loading->extra.size; j++) {
1420 loading->extra.order[j] = extra_type_by_rule_name(modname[j]);
1422 free(modname);
1423 for (; j < nmod; j++) {
1424 loading->extra.order[j] = NULL;
1428 /* Load multipliers. */
1429 loading->multiplier.size
1430 = secfile_lookup_int_default(loading->file, 0,
1431 "savefile.multipliers_size");
1432 if (loading->multiplier.size) {
1433 const char **modname;
1434 int j;
1436 modname = secfile_lookup_str_vec(loading->file, &loading->multiplier.size,
1437 "savefile.multipliers_vector");
1438 sg_failure_ret(loading->multiplier.size != 0,
1439 "Failed to load multipliers order: %s",
1440 secfile_error());
1441 /* It's OK for the set of multipliers in the savefile to differ
1442 * from those in the ruleset. */
1443 loading->multiplier.order = fc_calloc(loading->multiplier.size,
1444 sizeof(*loading->multiplier.order));
1445 for (j = 0; j < loading->multiplier.size; j++) {
1446 loading->multiplier.order[j] = multiplier_by_rule_name(modname[j]);
1447 if (!loading->multiplier.order[j]) {
1448 log_verbose("Multiplier \"%s\" in savegame but not in ruleset, "
1449 "discarding", modname[j]);
1452 free(modname);
1455 /* Load specialists. */
1456 loading->specialist.size
1457 = secfile_lookup_int_default(loading->file, 0,
1458 "savefile.specialists_size");
1459 if (loading->specialist.size) {
1460 const char **modname;
1461 size_t nmod;
1462 int j;
1464 modname = secfile_lookup_str_vec(loading->file, &loading->specialist.size,
1465 "savefile.specialists_vector");
1466 sg_failure_ret(loading->specialist.size != 0,
1467 "Failed to load specialists order: %s",
1468 secfile_error());
1469 sg_failure_ret(!(game.control.num_specialist_types < loading->specialist.size),
1470 "Number of specialists defined by the ruleset (= %d) are "
1471 "lower than the number in the savefile (= %d).",
1472 game.control.num_specialist_types, (int)loading->specialist.size);
1473 /* make sure that the size of the array is divisible by 4 */
1474 /* That's not really needed with specialists at the moment, but done this way
1475 * for consistency with other types, and to be prepared for the time it needs
1476 * to be this way. */
1477 nmod = 4 * ((loading->specialist.size + 3) / 4);
1478 loading->specialist.order = fc_calloc(nmod, sizeof(*loading->specialist.order));
1479 for (j = 0; j < loading->specialist.size; j++) {
1480 loading->specialist.order[j] = specialist_by_rule_name(modname[j]);
1482 free(modname);
1483 for (; j < nmod; j++) {
1484 loading->specialist.order[j] = NULL;
1488 /* Load action order. */
1489 loading->action.size = secfile_lookup_int_default(loading->file, 0,
1490 "savefile.action_size");
1492 sg_failure_ret(loading->action.size > 0,
1493 "Failed to load action order: %s",
1494 secfile_error());
1496 if (loading->action.size) {
1497 const char **modname;
1498 int j;
1500 modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
1501 "savefile.action_vector");
1503 loading->action.order = fc_calloc(loading->action.size,
1504 sizeof(*loading->action.order));
1506 for (j = 0; j < loading->action.size; j++) {
1507 struct action *real_action = action_by_rule_name(modname[j]);
1509 if (real_action) {
1510 loading->action.order[j] = real_action->id;
1511 } else {
1512 log_sg("Unknown action \'%s\'", modname[j]);
1513 loading->action.order[j] = ACTION_NONE;
1517 free(modname);
1520 /* Load action decision order. */
1521 loading->act_dec.size
1522 = secfile_lookup_int_default(loading->file, 0,
1523 "savefile.action_decision_size");
1525 sg_failure_ret(loading->act_dec.size > 0,
1526 "Failed to load action decision order: %s",
1527 secfile_error());
1529 if (loading->act_dec.size) {
1530 const char **modname;
1531 int j;
1533 modname = secfile_lookup_str_vec(loading->file, &loading->act_dec.size,
1534 "savefile.action_decision_vector");
1536 loading->act_dec.order = fc_calloc(loading->act_dec.size,
1537 sizeof(*loading->act_dec.order));
1539 for (j = 0; j < loading->act_dec.size; j++) {
1540 loading->act_dec.order[j] = action_decision_by_name(modname[j],
1541 fc_strcasecmp);
1544 free(modname);
1547 terrain_type_iterate(pterr) {
1548 pterr->identifier_load = '\0';
1549 } terrain_type_iterate_end;
1551 i = 0;
1552 while ((terr_name = secfile_lookup_str_default(loading->file, NULL,
1553 "savefile.terrident%d.name", i)) != NULL) {
1554 struct terrain *pterr = terrain_by_rule_name(terr_name);
1556 if (pterr != NULL) {
1557 const char *iptr = secfile_lookup_str_default(loading->file, NULL,
1558 "savefile.terrident%d.identifier", i);
1560 pterr->identifier_load = *iptr;
1561 } else {
1562 log_error("Identifier for unknown terrain type %s.", terr_name);
1564 i++;
1567 terrain_type_iterate(pterr) {
1568 terrain_type_iterate(pterr2) {
1569 if (pterr != pterr2 && pterr->identifier_load != '\0') {
1570 sg_failure_ret((pterr->identifier_load != pterr2->identifier_load),
1571 "%s and %s share a saved identifier",
1572 terrain_rule_name(pterr), terrain_rule_name(pterr2));
1574 } terrain_type_iterate_end;
1575 } terrain_type_iterate_end;
1578 /****************************************************************************
1579 Save '[savefile]'.
1580 ****************************************************************************/
1581 static void sg_save_savefile(struct savedata *saving)
1583 int i;
1585 /* Check status and return if not OK (sg_success != TRUE). */
1586 sg_check_ret();
1588 /* Save savefile options. */
1589 sg_save_savefile_options(saving, savefile_options_default);
1591 secfile_insert_int(saving->file, current_compat_ver(), "savefile.version");
1593 /* Save reason of the savefile generation. */
1594 secfile_insert_str(saving->file, saving->save_reason, "savefile.reason");
1596 /* Save as accurate freeciv revision information as possible */
1597 secfile_insert_str(saving->file, freeciv_datafile_version(), "savefile.revision");
1599 /* Save rulesetdir at this point as this ruleset is required by this
1600 * savefile. */
1601 secfile_insert_str(saving->file, game.server.rulesetdir, "savefile.rulesetdir");
1603 if (game.control.version[0] != '\0') {
1604 /* Current ruleset has version information, save it.
1605 * This is never loaded, but exist in savegame file only for debugging purposes. */
1606 secfile_insert_str(saving->file, game.control.version, "savefile.rulesetversion");
1609 if (game.server.last_updated_year) {
1610 secfile_insert_bool(saving->file, TRUE, "savefile.last_updated_as_year");
1613 /* Save improvement order in savegame, so we are not dependent on ruleset
1614 * order. If the game isn't started improvements aren't loaded so we can
1615 * not save the order. */
1616 secfile_insert_int(saving->file, improvement_count(),
1617 "savefile.improvement_size");
1618 if (improvement_count() > 0) {
1619 const char* buf[improvement_count()];
1621 improvement_iterate(pimprove) {
1622 buf[improvement_index(pimprove)] = improvement_rule_name(pimprove);
1623 } improvement_iterate_end;
1625 secfile_insert_str_vec(saving->file, buf, improvement_count(),
1626 "savefile.improvement_vector");
1629 /* Save technology order in savegame, so we are not dependent on ruleset
1630 * order. If the game isn't started advances aren't loaded so we can not
1631 * save the order. */
1632 secfile_insert_int(saving->file, game.control.num_tech_types,
1633 "savefile.technology_size");
1634 if (game.control.num_tech_types > 0) {
1635 const char* buf[game.control.num_tech_types];
1637 buf[A_NONE] = "A_NONE";
1638 advance_iterate(A_FIRST, a) {
1639 buf[advance_index(a)] = advance_rule_name(a);
1640 } advance_iterate_end;
1641 secfile_insert_str_vec(saving->file, buf, game.control.num_tech_types,
1642 "savefile.technology_vector");
1645 /* Save activities order in the savegame. */
1646 secfile_insert_int(saving->file, ACTIVITY_LAST,
1647 "savefile.activities_size");
1648 if (ACTIVITY_LAST > 0) {
1649 const char **modname;
1650 int j;
1652 i = 0;
1654 modname = fc_calloc(ACTIVITY_LAST, sizeof(*modname));
1656 for (j = 0; j < ACTIVITY_LAST; j++) {
1657 modname[i++] = unit_activity_name(j);
1660 secfile_insert_str_vec(saving->file, modname,
1661 ACTIVITY_LAST,
1662 "savefile.activities_vector");
1663 free(modname);
1666 /* Save specialists order in the savegame. */
1667 secfile_insert_int(saving->file, specialist_count(),
1668 "savefile.specialists_size");
1670 const char **modname;
1672 i = 0;
1673 modname = fc_calloc(specialist_count(), sizeof(*modname));
1675 specialist_type_iterate(sp) {
1676 modname[i++] = specialist_rule_name(specialist_by_number(sp));
1677 } specialist_type_iterate_end;
1679 secfile_insert_str_vec(saving->file, modname, specialist_count(),
1680 "savefile.specialists_vector");
1682 free(modname);
1685 /* Save trait order in savegame. */
1686 secfile_insert_int(saving->file, TRAIT_COUNT,
1687 "savefile.trait_size");
1689 const char **modname;
1690 enum trait tr;
1691 int j;
1693 modname = fc_calloc(TRAIT_COUNT, sizeof(*modname));
1695 for (tr = trait_begin(), j = 0; tr != trait_end(); tr = trait_next(tr), j++) {
1696 modname[j] = trait_name(tr);
1699 secfile_insert_str_vec(saving->file, modname, TRAIT_COUNT,
1700 "savefile.trait_vector");
1701 free(modname);
1704 /* Save extras order in the savegame. */
1705 secfile_insert_int(saving->file, game.control.num_extra_types,
1706 "savefile.extras_size");
1707 if (game.control.num_extra_types > 0) {
1708 const char **modname;
1710 i = 0;
1711 modname = fc_calloc(game.control.num_extra_types, sizeof(*modname));
1713 extra_type_iterate(pextra) {
1714 modname[i++] = extra_rule_name(pextra);
1715 } extra_type_iterate_end;
1717 secfile_insert_str_vec(saving->file, modname,
1718 game.control.num_extra_types,
1719 "savefile.extras_vector");
1720 free(modname);
1723 /* Save multipliers order in the savegame. */
1724 secfile_insert_int(saving->file, multiplier_count(),
1725 "savefile.multipliers_size");
1726 if (multiplier_count() > 0) {
1727 const char **modname;
1729 i = 0;
1730 modname = fc_calloc(multiplier_count(), sizeof(*modname));
1732 multipliers_iterate(pmul) {
1733 modname[multiplier_index(pmul)] = multiplier_rule_name(pmul);
1734 } multipliers_iterate_end;
1736 secfile_insert_str_vec(saving->file, modname,
1737 multiplier_count(),
1738 "savefile.multipliers_vector");
1739 free(modname);
1742 /* Save diplstate type order in the savegame. */
1743 secfile_insert_int(saving->file, DS_LAST,
1744 "savefile.diplstate_type_size");
1745 if (DS_LAST > 0) {
1746 const char **modname;
1747 int j;
1749 i = 0;
1750 modname = fc_calloc(DS_LAST, sizeof(*modname));
1752 for (j = 0; j < DS_LAST; j++) {
1753 modname[i++] = diplstate_type_name(j);
1756 secfile_insert_str_vec(saving->file, modname,
1757 DS_LAST,
1758 "savefile.diplstate_type_vector");
1759 free(modname);
1762 /* Save city_option order in the savegame. */
1763 secfile_insert_int(saving->file, CITYO_LAST,
1764 "savefile.city_options_size");
1765 if (CITYO_LAST > 0) {
1766 const char **modname;
1767 int j;
1769 i = 0;
1770 modname = fc_calloc(CITYO_LAST, sizeof(*modname));
1772 for (j = 0; j < CITYO_LAST; j++) {
1773 modname[i++] = city_options_name(j);
1776 secfile_insert_str_vec(saving->file, modname,
1777 CITYO_LAST,
1778 "savefile.city_options_vector");
1779 free(modname);
1782 /* Save action order in the savegame. */
1783 secfile_insert_int(saving->file, NUM_ACTIONS,
1784 "savefile.action_size");
1785 if (NUM_ACTIONS > 0) {
1786 const char **modname;
1787 int j;
1789 i = 0;
1790 modname = fc_calloc(NUM_ACTIONS, sizeof(*modname));
1792 for (j = 0; j < NUM_ACTIONS; j++) {
1793 modname[i++] = action_id_rule_name(j);
1796 secfile_insert_str_vec(saving->file, modname,
1797 NUM_ACTIONS,
1798 "savefile.action_vector");
1799 free(modname);
1802 /* Save action decision order in the savegame. */
1803 secfile_insert_int(saving->file, ACT_DEC_COUNT,
1804 "savefile.action_decision_size");
1805 if (ACT_DEC_COUNT > 0) {
1806 const char **modname;
1807 int j;
1809 i = 0;
1810 modname = fc_calloc(ACT_DEC_COUNT, sizeof(*modname));
1812 for (j = 0; j < ACT_DEC_COUNT; j++) {
1813 modname[i++] = action_decision_name(j);
1816 secfile_insert_str_vec(saving->file, modname,
1817 ACT_DEC_COUNT,
1818 "savefile.action_decision_vector");
1819 free(modname);
1822 /* Save terrain character mapping in the savegame. */
1823 i = 0;
1824 terrain_type_iterate(pterr) {
1825 char buf[2];
1827 secfile_insert_str(saving->file, terrain_rule_name(pterr), "savefile.terrident%d.name", i);
1828 buf[0] = terrain_identifier(pterr);
1829 buf[1] = '\0';
1830 secfile_insert_str(saving->file, buf, "savefile.terrident%d.identifier", i++);
1831 } terrain_type_iterate_end;
1834 /****************************************************************************
1835 Save options for this savegame. sg_load_savefile_options() is not defined.
1836 ****************************************************************************/
1837 static void sg_save_savefile_options(struct savedata *saving,
1838 const char *option)
1840 /* Check status and return if not OK (sg_success != TRUE). */
1841 sg_check_ret();
1843 if (option == NULL) {
1844 /* no additional option */
1845 return;
1848 sz_strlcat(saving->secfile_options, option);
1849 secfile_replace_str(saving->file, saving->secfile_options,
1850 "savefile.options");
1853 /* =======================================================================
1854 * Load / save game status.
1855 * ======================================================================= */
1857 /****************************************************************************
1858 Load '[ruledata]'.
1859 ****************************************************************************/
1860 static void sg_load_ruledata(struct loaddata *loading)
1862 int i;
1863 const char *name;
1865 for (i = 0;
1866 (name = secfile_lookup_str_default(loading->file, NULL,
1867 "ruledata.government%d.name", i));
1868 i++) {
1869 struct government *gov = government_by_rule_name(name);
1871 if (gov != NULL) {
1872 gov->changed_to_times = secfile_lookup_int_default(loading->file, 0,
1873 "ruledata.government%d.changes", i);
1878 /****************************************************************************
1879 Load '[game]'.
1880 ****************************************************************************/
1881 static void sg_load_game(struct loaddata *loading)
1883 const char *str;
1884 const char *level;
1885 int i;
1887 /* Check status and return if not OK (sg_success != TRUE). */
1888 sg_check_ret();
1890 /* Load server state. */
1891 str = secfile_lookup_str_default(loading->file, "S_S_INITIAL",
1892 "game.server_state");
1893 loading->server_state = server_states_by_name(str, strcmp);
1894 if (!server_states_is_valid(loading->server_state)) {
1895 /* Don't take any risk! */
1896 loading->server_state = S_S_INITIAL;
1899 str = secfile_lookup_str_default(loading->file,
1900 default_meta_patches_string(),
1901 "game.meta_patches");
1902 set_meta_patches_string(str);
1904 if (0 == strcmp(DEFAULT_META_SERVER_ADDR, srvarg.metaserver_addr)) {
1905 /* Do not overwrite this if the user requested a specific metaserver
1906 * from the command line (option --Metaserver). */
1907 sz_strlcpy(srvarg.metaserver_addr,
1908 secfile_lookup_str_default(loading->file,
1909 DEFAULT_META_SERVER_ADDR,
1910 "game.meta_server"));
1913 if ('\0' == srvarg.serverid[0]) {
1914 /* Do not overwrite this if the user requested a specific metaserver
1915 * from the command line (option --serverid). */
1916 sz_strlcpy(srvarg.serverid,
1917 secfile_lookup_str_default(loading->file, "",
1918 "game.serverid"));
1920 sz_strlcpy(server.game_identifier,
1921 secfile_lookup_str_default(loading->file, "", "game.id"));
1922 /* We are not checking game_identifier legality just yet.
1923 * That's done when we are sure that rand seed has been initialized,
1924 * so that we can generate new game_identifier, if needed.
1925 * See sq_load_sanitycheck(). */
1927 level = secfile_lookup_str_default(loading->file, NULL,
1928 "game.level");
1929 if (level != NULL) {
1930 game.info.skill_level = ai_level_by_name(level, fc_strcasecmp);
1931 } else {
1932 game.info.skill_level = ai_level_invalid();
1935 if (!ai_level_is_valid(game.info.skill_level)) {
1936 game.info.skill_level
1937 = ai_level_convert(GAME_HARDCODED_DEFAULT_SKILL_LEVEL);
1939 str = secfile_lookup_str_default(loading->file, NULL,
1940 "game.phase_mode");
1941 if (str != NULL) {
1942 game.info.phase_mode = phase_mode_type_by_name(str, fc_strcasecmp);
1943 if (!phase_mode_type_is_valid(game.info.phase_mode)) {
1944 log_error("Illegal phase mode \"%s\"", str);
1945 game.info.phase_mode = GAME_DEFAULT_PHASE_MODE;
1947 } else {
1948 log_error("Phase mode missing");
1951 str = secfile_lookup_str_default(loading->file, NULL,
1952 "game.phase_mode_stored");
1953 if (str != NULL) {
1954 game.server.phase_mode_stored = phase_mode_type_by_name(str, fc_strcasecmp);
1955 if (!phase_mode_type_is_valid(game.server.phase_mode_stored)) {
1956 log_error("Illegal stored phase mode \"%s\"", str);
1957 game.server.phase_mode_stored = GAME_DEFAULT_PHASE_MODE;
1959 } else {
1960 log_error("Stored phase mode missing");
1962 game.info.phase
1963 = secfile_lookup_int_default(loading->file, 0,
1964 "game.phase");
1965 game.server.scoreturn
1966 = secfile_lookup_int_default(loading->file,
1967 game.info.turn + GAME_DEFAULT_SCORETURN,
1968 "game.scoreturn");
1970 game.server.timeoutint
1971 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_TIMEOUTINT,
1972 "game.timeoutint");
1973 game.server.timeoutintinc
1974 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_TIMEOUTINTINC,
1975 "game.timeoutintinc");
1976 game.server.timeoutinc
1977 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_TIMEOUTINC,
1978 "game.timeoutinc");
1979 game.server.timeoutincmult
1980 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_TIMEOUTINCMULT,
1981 "game.timeoutincmult");
1982 game.server.timeoutcounter
1983 = secfile_lookup_int_default(loading->file, GAME_DEFAULT_TIMEOUTCOUNTER,
1984 "game.timeoutcounter");
1986 game.info.turn
1987 = secfile_lookup_int_default(loading->file, 0, "game.turn");
1988 sg_failure_ret(secfile_lookup_int(loading->file, &game.info.year,
1989 "game.year"), "%s", secfile_error());
1990 game.info.year_0_hack
1991 = secfile_lookup_bool_default(loading->file, FALSE, "game.year_0_hack");
1993 game.info.globalwarming
1994 = secfile_lookup_int_default(loading->file, 0, "game.globalwarming");
1995 game.info.heating
1996 = secfile_lookup_int_default(loading->file, 0, "game.heating");
1997 game.info.warminglevel
1998 = secfile_lookup_int_default(loading->file, 0, "game.warminglevel");
2000 game.info.nuclearwinter
2001 = secfile_lookup_int_default(loading->file, 0, "game.nuclearwinter");
2002 game.info.cooling
2003 = secfile_lookup_int_default(loading->file, 0, "game.cooling");
2004 game.info.coolinglevel
2005 = secfile_lookup_int_default(loading->file, 0, "game.coolinglevel");
2007 /* Global advances. */
2008 str = secfile_lookup_str_default(loading->file, NULL,
2009 "game.global_advances");
2010 if (str != NULL) {
2011 sg_failure_ret(strlen(str) == loading->technology.size,
2012 "Invalid length of 'game.global_advances' (%lu ~= %lu).",
2013 (unsigned long) strlen(str),
2014 (unsigned long) loading->technology.size);
2015 for (i = 0; i < loading->technology.size; i++) {
2016 sg_failure_ret(str[i] == '1' || str[i] == '0',
2017 "Undefined value '%c' within 'game.global_advances'.",
2018 str[i]);
2019 if (str[i] == '1') {
2020 struct advance *padvance =
2021 advance_by_rule_name(loading->technology.order[i]);
2023 if (padvance != NULL) {
2024 game.info.global_advances[advance_number(padvance)] = TRUE;
2030 game.info.is_new_game
2031 = !secfile_lookup_bool_default(loading->file, TRUE, "game.save_players");
2033 game.server.turn_change_time
2034 = secfile_lookup_int_default(loading->file, 0, "game.last_turn_change_time") / 100;
2037 /****************************************************************************
2038 Save '[ruledata]'.
2039 ****************************************************************************/
2040 static void sg_save_ruledata(struct savedata *saving)
2042 int set_count = 0;
2044 governments_iterate(pgov) {
2045 char path[256];
2047 fc_snprintf(path, sizeof(path),
2048 "ruledata.government%d", set_count++);
2050 secfile_insert_str(saving->file, government_rule_name(pgov),
2051 "%s.name", path);
2052 secfile_insert_int(saving->file, pgov->changed_to_times,
2053 "%s.changes", path);
2054 } governments_iterate_end;
2057 /****************************************************************************
2058 Save '[game]'.
2059 ****************************************************************************/
2060 static void sg_save_game(struct savedata *saving)
2062 enum server_states srv_state;
2063 char global_advances[game.control.num_tech_types + 1];
2064 int i;
2066 /* Check status and return if not OK (sg_success != TRUE). */
2067 sg_check_ret();
2069 /* Game state: once the game is no longer a new game (ie, has been
2070 * started the first time), it should always be considered a running
2071 * game for savegame purposes. */
2072 if (saving->scenario && !game.scenario.players) {
2073 srv_state = S_S_INITIAL;
2074 } else {
2075 srv_state = game.info.is_new_game ? server_state() : S_S_RUNNING;
2077 secfile_insert_str(saving->file, server_states_name(srv_state),
2078 "game.server_state");
2080 secfile_insert_str(saving->file, get_meta_patches_string(),
2081 "game.meta_patches");
2082 secfile_insert_str(saving->file, meta_addr_port(), "game.meta_server");
2084 secfile_insert_str(saving->file, server.game_identifier, "game.id");
2085 secfile_insert_str(saving->file, srvarg.serverid, "game.serverid");
2087 secfile_insert_str(saving->file, ai_level_name(game.info.skill_level),
2088 "game.level");
2089 secfile_insert_str(saving->file,
2090 phase_mode_type_name(game.info.phase_mode),
2091 "game.phase_mode");
2092 secfile_insert_str(saving->file,
2093 phase_mode_type_name(game.server.phase_mode_stored),
2094 "game.phase_mode_stored");
2095 secfile_insert_int(saving->file, game.info.phase,
2096 "game.phase");
2097 secfile_insert_int(saving->file, game.server.scoreturn,
2098 "game.scoreturn");
2100 secfile_insert_int(saving->file, game.server.timeoutint,
2101 "game.timeoutint");
2102 secfile_insert_int(saving->file, game.server.timeoutintinc,
2103 "game.timeoutintinc");
2104 secfile_insert_int(saving->file, game.server.timeoutinc,
2105 "game.timeoutinc");
2106 secfile_insert_int(saving->file, game.server.timeoutincmult,
2107 "game.timeoutincmult");
2108 secfile_insert_int(saving->file, game.server.timeoutcounter,
2109 "game.timeoutcounter");
2111 secfile_insert_int(saving->file, game.info.turn, "game.turn");
2112 secfile_insert_int(saving->file, game.info.year, "game.year");
2113 secfile_insert_bool(saving->file, game.info.year_0_hack,
2114 "game.year_0_hack");
2116 secfile_insert_int(saving->file, game.info.globalwarming,
2117 "game.globalwarming");
2118 secfile_insert_int(saving->file, game.info.heating,
2119 "game.heating");
2120 secfile_insert_int(saving->file, game.info.warminglevel,
2121 "game.warminglevel");
2123 secfile_insert_int(saving->file, game.info.nuclearwinter,
2124 "game.nuclearwinter");
2125 secfile_insert_int(saving->file, game.info.cooling,
2126 "game.cooling");
2127 secfile_insert_int(saving->file, game.info.coolinglevel,
2128 "game.coolinglevel");
2129 /* For debugging purposes only.
2130 * Do not save it if it's 0 (not known);
2131 * this confuses people reading this 'document' less than
2132 * saving 0. */
2133 if (game.server.seed != 0) {
2134 secfile_insert_int(saving->file, game.server.seed,
2135 "game.random_seed");
2138 /* Global advances. */
2139 for (i = 0; i < game.control.num_tech_types; i++) {
2140 global_advances[i] = game.info.global_advances[i] ? '1' : '0';
2142 global_advances[i] = '\0';
2143 secfile_insert_str(saving->file, global_advances, "game.global_advances");
2145 if (!game_was_started()) {
2146 saving->save_players = FALSE;
2147 } else {
2148 if (saving->scenario) {
2149 saving->save_players = game.scenario.players;
2150 } else {
2151 saving->save_players = TRUE;
2153 #ifndef SAVE_DUMMY_TURN_CHANGE_TIME
2154 secfile_insert_int(saving->file, game.server.turn_change_time * 100,
2155 "game.last_turn_change_time");
2156 #else /* SAVE_DUMMY_TURN_CHANGE_TIME */
2157 secfile_insert_int(saving->file, game.info.turn * 10,
2158 "game.last_turn_change_time");
2159 #endif /* SAVE_DUMMY_TURN_CHANGE_TIME */
2161 secfile_insert_bool(saving->file, saving->save_players,
2162 "game.save_players");
2165 /* =======================================================================
2166 * Load / save random status.
2167 * ======================================================================= */
2169 /****************************************************************************
2170 Load '[random]'.
2171 ****************************************************************************/
2172 static void sg_load_random(struct loaddata *loading)
2174 /* Check status and return if not OK (sg_success != TRUE). */
2175 sg_check_ret();
2177 if (secfile_lookup_bool_default(loading->file, FALSE, "random.saved")) {
2178 const char *str;
2179 int i;
2181 sg_failure_ret(secfile_lookup_int(loading->file, &loading->rstate.j,
2182 "random.index_J"), "%s", secfile_error());
2183 sg_failure_ret(secfile_lookup_int(loading->file, &loading->rstate.k,
2184 "random.index_K"), "%s", secfile_error());
2185 sg_failure_ret(secfile_lookup_int(loading->file, &loading->rstate.x,
2186 "random.index_X"), "%s", secfile_error());
2188 for (i = 0; i < 8; i++) {
2189 str = secfile_lookup_str(loading->file, "random.table%d",i);
2190 sg_failure_ret(NULL != str, "%s", secfile_error());
2191 sscanf(str, "%8x %8x %8x %8x %8x %8x %8x", &loading->rstate.v[7*i],
2192 &loading->rstate.v[7*i+1], &loading->rstate.v[7*i+2],
2193 &loading->rstate.v[7*i+3], &loading->rstate.v[7*i+4],
2194 &loading->rstate.v[7*i+5], &loading->rstate.v[7*i+6]);
2196 loading->rstate.is_init = TRUE;
2197 fc_rand_set_state(loading->rstate);
2198 } else {
2199 /* No random values - mark the setting. */
2200 (void) secfile_entry_by_path(loading->file, "random.saved");
2202 /* We're loading a game without a seed (which is okay, if it's a scenario).
2203 * We need to generate the game seed now because it will be needed later
2204 * during the load. */
2205 init_game_seed();
2206 loading->rstate = fc_rand_state();
2210 /****************************************************************************
2211 Save '[random]'.
2212 ****************************************************************************/
2213 static void sg_save_random(struct savedata *saving)
2215 /* Check status and return if not OK (sg_success != TRUE). */
2216 sg_check_ret();
2218 if (fc_rand_is_init() && (!saving->scenario || game.scenario.save_random)) {
2219 int i;
2220 RANDOM_STATE rstate = fc_rand_state();
2222 secfile_insert_bool(saving->file, TRUE, "random.saved");
2223 fc_assert(rstate.is_init);
2225 secfile_insert_int(saving->file, rstate.j, "random.index_J");
2226 secfile_insert_int(saving->file, rstate.k, "random.index_K");
2227 secfile_insert_int(saving->file, rstate.x, "random.index_X");
2229 for (i = 0; i < 8; i++) {
2230 char vec[100];
2232 fc_snprintf(vec, sizeof(vec),
2233 "%8x %8x %8x %8x %8x %8x %8x", rstate.v[7 * i],
2234 rstate.v[7 * i + 1], rstate.v[7 * i + 2],
2235 rstate.v[7 * i + 3], rstate.v[7 * i + 4],
2236 rstate.v[7 * i + 5], rstate.v[7 * i + 6]);
2237 secfile_insert_str(saving->file, vec, "random.table%d", i);
2239 } else {
2240 secfile_insert_bool(saving->file, FALSE, "random.saved");
2244 /* =======================================================================
2245 * Load / save lua script data.
2246 * ======================================================================= */
2248 /****************************************************************************
2249 Load '[script]'.
2250 ****************************************************************************/
2251 static void sg_load_script(struct loaddata *loading)
2253 /* Check status and return if not OK (sg_success != TRUE). */
2254 sg_check_ret();
2256 script_server_state_load(loading->file);
2259 /****************************************************************************
2260 Save '[script]'.
2261 ****************************************************************************/
2262 static void sg_save_script(struct savedata *saving)
2264 /* Check status and return if not OK (sg_success != TRUE). */
2265 sg_check_ret();
2267 script_server_state_save(saving->file);
2270 /* =======================================================================
2271 * Load / save scenario data.
2272 * ======================================================================= */
2274 /****************************************************************************
2275 Load '[scenario]'.
2276 ****************************************************************************/
2277 static void sg_load_scenario(struct loaddata *loading)
2279 const char *buf;
2280 int game_version;
2282 /* Check status and return if not OK (sg_success != TRUE). */
2283 sg_check_ret();
2285 /* Load version. */
2286 game_version
2287 = secfile_lookup_int_default(loading->file, 0, "scenario.game_version");
2288 /* We require at least version 2.90.99 - and at that time we saved version
2289 * numbers as 10000*MAJOR+100*MINOR+PATCH */
2290 sg_failure_ret(29099 <= game_version, "Saved game is too old, at least "
2291 "version 2.90.99 required.");
2293 sg_failure_ret(secfile_lookup_bool(loading->file, &game.scenario.is_scenario,
2294 "scenario.is_scenario"), "%s", secfile_error());
2295 if (!game.scenario.is_scenario) {
2296 return;
2299 buf = secfile_lookup_str_default(loading->file, "", "scenario.name");
2300 if (buf[0] != '\0') {
2301 sz_strlcpy(game.scenario.name, buf);
2304 buf = secfile_lookup_str_default(loading->file, "",
2305 "scenario.authors");
2306 if (buf[0] != '\0') {
2307 sz_strlcpy(game.scenario.authors, buf);
2308 } else {
2309 game.scenario.authors[0] = '\0';
2312 buf = secfile_lookup_str_default(loading->file, "",
2313 "scenario.description");
2314 if (buf[0] != '\0') {
2315 sz_strlcpy(game.scenario_desc.description, buf);
2316 } else {
2317 game.scenario_desc.description[0] = '\0';
2319 game.scenario.save_random
2320 = secfile_lookup_bool_default(loading->file, FALSE, "scenario.save_random");
2321 game.scenario.players
2322 = secfile_lookup_bool_default(loading->file, TRUE, "scenario.players");
2323 game.scenario.startpos_nations
2324 = secfile_lookup_bool_default(loading->file, FALSE,
2325 "scenario.startpos_nations");
2326 game.scenario.prevent_new_cities
2327 = secfile_lookup_bool_default(loading->file, FALSE,
2328 "scenario.prevent_new_cities");
2329 game.scenario.lake_flooding
2330 = secfile_lookup_bool_default(loading->file, TRUE,
2331 "scenario.lake_flooding");
2332 game.scenario.handmade
2333 = secfile_lookup_bool_default(loading->file, FALSE,
2334 "scenario.handmade");
2335 game.scenario.allow_ai_type_fallback
2336 = secfile_lookup_bool_default(loading->file, FALSE,
2337 "scenario.allow_ai_type_fallback");
2339 game.scenario.ruleset_locked
2340 = secfile_lookup_bool_default(loading->file, TRUE,
2341 "scenario.ruleset_locked");
2343 sg_failure_ret(loading->server_state == S_S_INITIAL
2344 || (loading->server_state == S_S_RUNNING
2345 && game.scenario.players == TRUE),
2346 "Invalid scenario definition (server state '%s' and "
2347 "players are %s).",
2348 server_states_name(loading->server_state),
2349 game.scenario.players ? "saved" : "not saved");
2351 /* Remove all defined players. They are recreated with the skill level
2352 * defined by the scenario. */
2353 (void) aifill(0);
2356 /****************************************************************************
2357 Save '[scenario]'.
2358 ****************************************************************************/
2359 static void sg_save_scenario(struct savedata *saving)
2361 struct entry *mod_entry;
2362 int game_version;
2364 /* Check status and return if not OK (sg_success != TRUE). */
2365 sg_check_ret();
2367 game_version = MAJOR_VERSION * 1000000 + MINOR_VERSION * 10000 + PATCH_VERSION * 100;
2368 #ifdef EMERGENCY_VERSION
2369 game_version += EMERGENCY_VERSION;
2370 #endif /* EMERGENCY_VERSION */
2371 secfile_insert_int(saving->file, game_version, "scenario.game_version");
2373 if (!saving->scenario || !game.scenario.is_scenario) {
2374 secfile_insert_bool(saving->file, FALSE, "scenario.is_scenario");
2375 return;
2378 secfile_insert_bool(saving->file, TRUE, "scenario.is_scenario");
2380 /* Name is mandatory to the level that is saved even if empty. */
2381 mod_entry = secfile_insert_str(saving->file, game.scenario.name, "scenario.name");
2382 entry_str_set_gt_marking(mod_entry, TRUE);
2384 /* Authors list is saved only if it exist */
2385 if (game.scenario.authors[0] != '\0') {
2386 mod_entry = secfile_insert_str(saving->file, game.scenario.authors,
2387 "scenario.authors");
2388 entry_str_set_gt_marking(mod_entry, TRUE);
2391 /* Description is saved only if it exist */
2392 if (game.scenario_desc.description[0] != '\0') {
2393 mod_entry = secfile_insert_str(saving->file, game.scenario_desc.description,
2394 "scenario.description");
2395 entry_str_set_gt_marking(mod_entry, TRUE);
2398 secfile_insert_bool(saving->file, game.scenario.save_random, "scenario.save_random");
2399 secfile_insert_bool(saving->file, game.scenario.players, "scenario.players");
2400 secfile_insert_bool(saving->file, game.scenario.startpos_nations,
2401 "scenario.startpos_nations");
2402 if (game.scenario.prevent_new_cities) {
2403 secfile_insert_bool(saving->file, game.scenario.prevent_new_cities,
2404 "scenario.prevent_new_cities");
2406 secfile_insert_bool(saving->file, game.scenario.lake_flooding,
2407 "scenario.lake_flooding");
2408 if (game.scenario.handmade) {
2409 secfile_insert_bool(saving->file, game.scenario.handmade,
2410 "scenario.handmade");
2412 if (game.scenario.allow_ai_type_fallback) {
2413 secfile_insert_bool(saving->file, game.scenario.allow_ai_type_fallback,
2414 "scenario.allow_ai_type_fallback");
2418 /* =======================================================================
2419 * Load / save game settings.
2420 * ======================================================================= */
2422 /****************************************************************************
2423 Load '[settings]'.
2424 ****************************************************************************/
2425 static void sg_load_settings(struct loaddata *loading)
2427 /* Check status and return if not OK (sg_success != TRUE). */
2428 sg_check_ret();
2430 settings_game_load(loading->file, "settings");
2432 /* Save current status of fogofwar. */
2433 game.server.fogofwar_old = game.info.fogofwar;
2435 /* Add all compatibility settings here. */
2438 /****************************************************************************
2439 Save [settings].
2440 ****************************************************************************/
2441 static void sg_save_settings(struct savedata *saving)
2443 enum map_generator real_generator = wld.map.server.generator;
2445 /* Check status and return if not OK (sg_success != TRUE). */
2446 sg_check_ret();
2448 if (saving->scenario) {
2449 wld.map.server.generator = MAPGEN_SCENARIO; /* We want a scenario. */
2452 settings_game_save(saving->file, "settings");
2453 /* Restore real map generator. */
2454 wld.map.server.generator = real_generator;
2456 /* Add all compatibility settings here. */
2459 /* =======================================================================
2460 * Load / save the main map.
2461 * ======================================================================= */
2463 /****************************************************************************
2464 Load '[map'].
2465 ****************************************************************************/
2466 static void sg_load_map(struct loaddata *loading)
2468 /* Check status and return if not OK (sg_success != TRUE). */
2469 sg_check_ret();
2471 /* This defaults to TRUE even if map has not been generated.
2472 * We rely on that
2473 * 1) scenario maps have it explicitly right.
2474 * 2) when map is actually generated, it re-initialize this to FALSE. */
2475 wld.map.server.have_huts
2476 = secfile_lookup_bool_default(loading->file, TRUE, "map.have_huts");
2477 game.scenario.have_resources
2478 = secfile_lookup_bool_default(loading->file, TRUE, "map.have_resources");
2480 wld.map.server.have_resources = game.scenario.have_resources;
2482 if (S_S_INITIAL == loading->server_state
2483 && MAPGEN_SCENARIO == wld.map.server.generator) {
2484 /* Generator MAPGEN_SCENARIO is used;
2485 * this map was done with the map editor. */
2487 /* Load tiles. */
2488 sg_load_map_tiles(loading);
2489 sg_load_map_startpos(loading);
2490 sg_load_map_tiles_extras(loading);
2492 /* Nothing more needed for a scenario. */
2493 return;
2496 if (S_S_INITIAL == loading->server_state) {
2497 /* Nothing more to do if it is not a scenario but in initial state. */
2498 return;
2501 sg_load_map_tiles(loading);
2502 sg_load_map_startpos(loading);
2503 sg_load_map_tiles_extras(loading);
2504 sg_load_map_known(loading);
2505 sg_load_map_owner(loading);
2506 sg_load_map_worked(loading);
2509 /****************************************************************************
2510 Save 'map'.
2511 ****************************************************************************/
2512 static void sg_save_map(struct savedata *saving)
2514 /* Check status and return if not OK (sg_success != TRUE). */
2515 sg_check_ret();
2517 if (map_is_empty()) {
2518 /* No map. */
2519 return;
2522 if (saving->scenario) {
2523 secfile_insert_bool(saving->file, wld.map.server.have_huts,
2524 "map.have_huts");
2525 secfile_insert_bool(saving->file, game.scenario.have_resources,
2526 "map.have_resources");
2527 } else {
2528 secfile_insert_bool(saving->file, TRUE, "map.have_huts");
2529 secfile_insert_bool(saving->file, TRUE, "map.have_resources");
2532 /* For debugging purposes only.
2533 * Do not save it if it's 0 (not known);
2534 * this confuses people reading this 'document' less than
2535 * saving 0. */
2536 if (wld.map.server.seed) {
2537 secfile_insert_int(saving->file, wld.map.server.seed,
2538 "map.random_seed");
2541 sg_save_map_tiles(saving);
2542 sg_save_map_startpos(saving);
2543 sg_save_map_tiles_extras(saving);
2544 sg_save_map_owner(saving);
2545 sg_save_map_worked(saving);
2546 sg_save_map_known(saving);
2549 /****************************************************************************
2550 Load tiles of the map.
2551 ****************************************************************************/
2552 static void sg_load_map_tiles(struct loaddata *loading)
2554 /* Check status and return if not OK (sg_success != TRUE). */
2555 sg_check_ret();
2557 /* Initialize the map for the current topology. 'map.xsize' and
2558 * 'map.ysize' must be set. */
2559 map_init_topology();
2561 /* Allocate map. */
2562 main_map_allocate();
2564 /* get the terrain type */
2565 LOAD_MAP_CHAR(ch, ptile, ptile->terrain = char2terrain(ch), loading->file,
2566 "map.t%04d");
2567 assign_continent_numbers();
2569 /* Check for special tile sprites. */
2570 whole_map_iterate(&(wld.map), ptile) {
2571 const char *spec_sprite;
2572 const char *label;
2573 int nat_x, nat_y;
2575 index_to_native_pos(&nat_x, &nat_y, tile_index(ptile));
2576 spec_sprite = secfile_lookup_str(loading->file, "map.spec_sprite_%d_%d",
2577 nat_x, nat_y);
2578 label = secfile_lookup_str_default(loading->file, NULL, "map.label_%d_%d",
2579 nat_x, nat_y);
2580 if (NULL != ptile->spec_sprite) {
2581 ptile->spec_sprite = fc_strdup(spec_sprite);
2583 if (label != NULL) {
2584 tile_set_label(ptile, label);
2586 } whole_map_iterate_end;
2589 /****************************************************************************
2590 Save all map tiles
2591 ****************************************************************************/
2592 static void sg_save_map_tiles(struct savedata *saving)
2594 /* Check status and return if not OK (sg_success != TRUE). */
2595 sg_check_ret();
2597 /* Save the terrain type. */
2598 SAVE_MAP_CHAR(ptile, terrain2char(ptile->terrain), saving->file,
2599 "map.t%04d");
2601 /* Save special tile sprites. */
2602 whole_map_iterate(&(wld.map), ptile) {
2603 int nat_x, nat_y;
2605 index_to_native_pos(&nat_x, &nat_y, tile_index(ptile));
2606 if (ptile->spec_sprite) {
2607 secfile_insert_str(saving->file, ptile->spec_sprite,
2608 "map.spec_sprite_%d_%d", nat_x, nat_y);
2610 if (ptile->label != NULL) {
2611 secfile_insert_str(saving->file, ptile->label,
2612 "map.label_%d_%d", nat_x, nat_y);
2614 } whole_map_iterate_end;
2617 /****************************************************************************
2618 Load extras to map
2619 ****************************************************************************/
2620 static void sg_load_map_tiles_extras(struct loaddata *loading)
2622 /* Check status and return if not OK (sg_success != TRUE). */
2623 sg_check_ret();
2625 /* Load extras. */
2626 halfbyte_iterate_extras(j, loading->extra.size) {
2627 LOAD_MAP_CHAR(ch, ptile, sg_extras_set(&ptile->extras, ch, loading->extra.order + 4 * j),
2628 loading->file, "map.e%02d_%04d", j);
2629 } halfbyte_iterate_extras_end;
2631 if (S_S_INITIAL != loading->server_state
2632 || MAPGEN_SCENARIO != wld.map.server.generator
2633 || game.scenario.have_resources) {
2634 whole_map_iterate(&(wld.map), ptile) {
2635 extra_type_by_cause_iterate(EC_RESOURCE, pres) {
2636 if (tile_has_extra(ptile, pres)) {
2637 tile_set_resource(ptile, pres);
2639 if (!terrain_has_resource(ptile->terrain, ptile->resource)) {
2640 BV_CLR(ptile->extras, extra_index(pres));
2643 } extra_type_by_cause_iterate_end;
2644 } whole_map_iterate_end;
2648 /****************************************************************************
2649 Save information about extras on map
2650 ****************************************************************************/
2651 static void sg_save_map_tiles_extras(struct savedata *saving)
2653 /* Check status and return if not OK (sg_success != TRUE). */
2654 sg_check_ret();
2656 /* Save extras. */
2657 halfbyte_iterate_extras(j, game.control.num_extra_types) {
2658 int mod[4];
2659 int l;
2661 for (l = 0; l < 4; l++) {
2662 if (4 * j + 1 > game.control.num_extra_types) {
2663 mod[l] = -1;
2664 } else {
2665 mod[l] = 4 * j + l;
2668 SAVE_MAP_CHAR(ptile, sg_extras_get(ptile->extras, ptile->resource, mod),
2669 saving->file, "map.e%02d_%04d", j);
2670 } halfbyte_iterate_extras_end;
2673 /****************************************************************************
2674 Load starting positions for the players from a savegame file. There should
2675 be at least enough for every player.
2676 ****************************************************************************/
2677 static void sg_load_map_startpos(struct loaddata *loading)
2679 struct nation_type *pnation;
2680 struct startpos *psp;
2681 struct tile *ptile;
2682 const char SEPARATOR = '#';
2683 const char *nation_names;
2684 int nat_x, nat_y;
2685 bool exclude;
2686 int i, startpos_count;
2688 /* Check status and return if not OK (sg_success != TRUE). */
2689 sg_check_ret();
2691 startpos_count
2692 = secfile_lookup_int_default(loading->file, 0, "map.startpos_count");
2694 if (0 == startpos_count) {
2695 /* Nothing to do. */
2696 return;
2699 for (i = 0; i < startpos_count; i++) {
2700 if (!secfile_lookup_int(loading->file, &nat_x, "map.startpos%d.x", i)
2701 || !secfile_lookup_int(loading->file, &nat_y,
2702 "map.startpos%d.y", i)) {
2703 log_sg("Warning: Undefined coordinates for startpos %d", i);
2704 continue;
2707 ptile = native_pos_to_tile(&(wld.map), nat_x, nat_y);
2708 if (NULL == ptile) {
2709 log_error("Start position native coordinates (%d, %d) do not exist "
2710 "in this map. Skipping...", nat_x, nat_y);
2711 continue;
2714 exclude = secfile_lookup_bool_default(loading->file, FALSE,
2715 "map.startpos%d.exclude", i);
2717 psp = map_startpos_new(ptile);
2719 nation_names = secfile_lookup_str(loading->file,
2720 "map.startpos%d.nations", i);
2721 if (NULL != nation_names && '\0' != nation_names[0]) {
2722 const size_t size = strlen(nation_names) + 1;
2723 char buf[size], *start, *end;
2725 memcpy(buf, nation_names, size);
2726 for (start = buf - 1; NULL != start; start = end) {
2727 start++;
2728 if ((end = strchr(start, SEPARATOR))) {
2729 *end = '\0';
2732 pnation = nation_by_rule_name(start);
2733 if (NO_NATION_SELECTED != pnation) {
2734 if (exclude) {
2735 startpos_disallow(psp, pnation);
2736 } else {
2737 startpos_allow(psp, pnation);
2739 } else {
2740 log_verbose("Missing nation \"%s\".", start);
2746 if (0 < map_startpos_count()
2747 && loading->server_state == S_S_INITIAL
2748 && map_startpos_count() < game.server.max_players) {
2749 log_verbose("Number of starts (%d) are lower than rules.max_players "
2750 "(%d), lowering rules.max_players.",
2751 map_startpos_count(), game.server.max_players);
2752 game.server.max_players = map_startpos_count();
2755 /* Re-initialize nation availability in light of start positions.
2756 * This has to be after loading [scenario] and [map].startpos and
2757 * before we seek nations for players. */
2758 update_nations_with_startpos();
2761 /****************************************************************************
2762 Save the map start positions.
2763 ****************************************************************************/
2764 static void sg_save_map_startpos(struct savedata *saving)
2766 struct tile *ptile;
2767 const char SEPARATOR = '#';
2768 int i = 0;
2770 /* Check status and return if not OK (sg_success != TRUE). */
2771 sg_check_ret();
2773 if (!game.server.save_options.save_starts) {
2774 return;
2777 secfile_insert_int(saving->file, map_startpos_count(),
2778 "map.startpos_count");
2780 map_startpos_iterate(psp) {
2781 int nat_x, nat_y;
2783 ptile = startpos_tile(psp);
2785 index_to_native_pos(&nat_x, &nat_y, tile_index(ptile));
2786 secfile_insert_int(saving->file, nat_x, "map.startpos%d.x", i);
2787 secfile_insert_int(saving->file, nat_y, "map.startpos%d.y", i);
2789 secfile_insert_bool(saving->file, startpos_is_excluding(psp),
2790 "map.startpos%d.exclude", i);
2791 if (startpos_allows_all(psp)) {
2792 secfile_insert_str(saving->file, "", "map.startpos%d.nations", i);
2793 } else {
2794 const struct nation_hash *nations = startpos_raw_nations(psp);
2795 char nation_names[MAX_LEN_NAME * nation_hash_size(nations)];
2797 nation_names[0] = '\0';
2798 nation_hash_iterate(nations, pnation) {
2799 if ('\0' == nation_names[0]) {
2800 fc_strlcpy(nation_names, nation_rule_name(pnation),
2801 sizeof(nation_names));
2802 } else {
2803 cat_snprintf(nation_names, sizeof(nation_names),
2804 "%c%s", SEPARATOR, nation_rule_name(pnation));
2806 } nation_hash_iterate_end;
2807 secfile_insert_str(saving->file, nation_names,
2808 "map.startpos%d.nations", i);
2810 i++;
2811 } map_startpos_iterate_end;
2813 fc_assert(map_startpos_count() == i);
2816 /****************************************************************************
2817 Load tile owner information
2818 ****************************************************************************/
2819 static void sg_load_map_owner(struct loaddata *loading)
2821 int x, y;
2822 struct player *owner = NULL;
2823 struct tile *claimer = NULL;
2824 struct player *eowner = NULL;
2826 /* Check status and return if not OK (sg_success != TRUE). */
2827 sg_check_ret();
2829 if (game.info.is_new_game) {
2830 /* No owner/source information for a new game / scenario. */
2831 return;
2834 /* Owner and ownership source are stored as plain numbers */
2835 for (y = 0; y < wld.map.ysize; y++) {
2836 const char *buffer1 = secfile_lookup_str(loading->file,
2837 "map.owner%04d", y);
2838 const char *buffer2 = secfile_lookup_str(loading->file,
2839 "map.source%04d", y);
2840 const char *buffer3 = secfile_lookup_str(loading->file,
2841 "map.eowner%04d", y);
2842 const char *ptr1 = buffer1;
2843 const char *ptr2 = buffer2;
2844 const char *ptr3 = buffer3;
2846 sg_failure_ret(buffer1 != NULL, "%s", secfile_error());
2847 sg_failure_ret(buffer2 != NULL, "%s", secfile_error());
2848 sg_failure_ret(buffer3 != NULL, "%s", secfile_error());
2850 for (x = 0; x < wld.map.xsize; x++) {
2851 char token1[TOKEN_SIZE];
2852 char token2[TOKEN_SIZE];
2853 char token3[TOKEN_SIZE];
2854 int number;
2855 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
2857 scanin(&ptr1, ",", token1, sizeof(token1));
2858 sg_failure_ret(token1[0] != '\0',
2859 "Map size not correct (map.owner%d).", y);
2860 if (strcmp(token1, "-") == 0) {
2861 owner = NULL;
2862 } else {
2863 sg_failure_ret(str_to_int(token1, &number),
2864 "Got map owner %s in (%d, %d).", token1, x, y);
2865 owner = player_by_number(number);
2868 scanin(&ptr2, ",", token2, sizeof(token2));
2869 sg_failure_ret(token2[0] != '\0',
2870 "Map size not correct (map.source%d).", y);
2871 if (strcmp(token2, "-") == 0) {
2872 claimer = NULL;
2873 } else {
2874 sg_failure_ret(str_to_int(token2, &number),
2875 "Got map source %s in (%d, %d).", token2, x, y);
2876 claimer = index_to_tile(&(wld.map), number);
2879 scanin(&ptr3, ",", token3, sizeof(token3));
2880 sg_failure_ret(token3[0] != '\0',
2881 "Map size not correct (map.eowner%d).", y);
2882 if (strcmp(token3, "-") == 0) {
2883 eowner = NULL;
2884 } else {
2885 sg_failure_ret(str_to_int(token3, &number),
2886 "Got base owner %s in (%d, %d).", token3, x, y);
2887 eowner = player_by_number(number);
2890 map_claim_ownership(ptile, owner, claimer, FALSE);
2891 tile_claim_bases(ptile, eowner);
2892 log_debug("extras_owner(%d, %d) = %s", TILE_XY(ptile), player_name(eowner));
2897 /****************************************************************************
2898 Save tile owner information
2899 ****************************************************************************/
2900 static void sg_save_map_owner(struct savedata *saving)
2902 int x, y;
2904 /* Check status and return if not OK (sg_success != TRUE). */
2905 sg_check_ret();
2907 if (saving->scenario && !saving->save_players) {
2908 /* Nothing to do for a scenario without saved players. */
2909 return;
2912 /* Store owner and ownership source as plain numbers. */
2913 for (y = 0; y < wld.map.ysize; y++) {
2914 char line[wld.map.xsize * TOKEN_SIZE];
2916 line[0] = '\0';
2917 for (x = 0; x < wld.map.xsize; x++) {
2918 char token[TOKEN_SIZE];
2919 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
2921 if (!saving->save_players || tile_owner(ptile) == NULL) {
2922 strcpy(token, "-");
2923 } else {
2924 fc_snprintf(token, sizeof(token), "%d",
2925 player_number(tile_owner(ptile)));
2927 strcat(line, token);
2928 if (x + 1 < wld.map.xsize) {
2929 strcat(line, ",");
2932 secfile_insert_str(saving->file, line, "map.owner%04d", y);
2935 for (y = 0; y < wld.map.ysize; y++) {
2936 char line[wld.map.xsize * TOKEN_SIZE];
2938 line[0] = '\0';
2939 for (x = 0; x < wld.map.xsize; x++) {
2940 char token[TOKEN_SIZE];
2941 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
2943 if (ptile->claimer == NULL) {
2944 strcpy(token, "-");
2945 } else {
2946 fc_snprintf(token, sizeof(token), "%d", tile_index(ptile->claimer));
2948 strcat(line, token);
2949 if (x + 1 < wld.map.xsize) {
2950 strcat(line, ",");
2953 secfile_insert_str(saving->file, line, "map.source%04d", y);
2956 for (y = 0; y < wld.map.ysize; y++) {
2957 char line[wld.map.xsize * TOKEN_SIZE];
2959 line[0] = '\0';
2960 for (x = 0; x < wld.map.xsize; x++) {
2961 char token[TOKEN_SIZE];
2962 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
2964 if (!saving->save_players || extra_owner(ptile) == NULL) {
2965 strcpy(token, "-");
2966 } else {
2967 fc_snprintf(token, sizeof(token), "%d",
2968 player_number(extra_owner(ptile)));
2970 strcat(line, token);
2971 if (x + 1 < wld.map.xsize) {
2972 strcat(line, ",");
2975 secfile_insert_str(saving->file, line, "map.eowner%04d", y);
2979 /****************************************************************************
2980 Load worked tiles information
2981 ****************************************************************************/
2982 static void sg_load_map_worked(struct loaddata *loading)
2984 int x, y;
2986 /* Check status and return if not OK (sg_success != TRUE). */
2987 sg_check_ret();
2989 sg_failure_ret(loading->worked_tiles == NULL,
2990 "City worked map not loaded!");
2992 loading->worked_tiles = fc_malloc(MAP_INDEX_SIZE *
2993 sizeof(*loading->worked_tiles));
2995 for (y = 0; y < wld.map.ysize; y++) {
2996 const char *buffer = secfile_lookup_str(loading->file, "map.worked%04d",
2998 const char *ptr = buffer;
3000 sg_failure_ret(NULL != buffer,
3001 "Savegame corrupt - map line %d not found.", y);
3002 for (x = 0; x < wld.map.xsize; x++) {
3003 char token[TOKEN_SIZE];
3004 int number;
3005 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3007 scanin(&ptr, ",", token, sizeof(token));
3008 sg_failure_ret('\0' != token[0],
3009 "Savegame corrupt - map size not correct.");
3010 if (strcmp(token, "-") == 0) {
3011 number = -1;
3012 } else {
3013 sg_failure_ret(str_to_int(token, &number) && 0 < number,
3014 "Savegame corrupt - got tile worked by city "
3015 "id=%s in (%d, %d).", token, x, y);
3018 loading->worked_tiles[ptile->index] = number;
3023 /****************************************************************************
3024 Save worked tiles information
3025 ****************************************************************************/
3026 static void sg_save_map_worked(struct savedata *saving)
3028 int x, y;
3030 /* Check status and return if not OK (sg_success != TRUE). */
3031 sg_check_ret();
3033 if (saving->scenario && !saving->save_players) {
3034 /* Nothing to do for a scenario without saved players. */
3035 return;
3038 /* additionally save the tiles worked by the cities */
3039 for (y = 0; y < wld.map.ysize; y++) {
3040 char line[wld.map.xsize * TOKEN_SIZE];
3042 line[0] = '\0';
3043 for (x = 0; x < wld.map.xsize; x++) {
3044 char token[TOKEN_SIZE];
3045 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3046 struct city *pcity = tile_worked(ptile);
3048 if (pcity == NULL) {
3049 strcpy(token, "-");
3050 } else {
3051 fc_snprintf(token, sizeof(token), "%d", pcity->id);
3053 strcat(line, token);
3054 if (x < wld.map.xsize) {
3055 strcat(line, ",");
3058 secfile_insert_str(saving->file, line, "map.worked%04d", y);
3062 /****************************************************************************
3063 Load tile known status
3064 ****************************************************************************/
3065 static void sg_load_map_known(struct loaddata *loading)
3067 /* Check status and return if not OK (sg_success != TRUE). */
3068 sg_check_ret();
3070 players_iterate(pplayer) {
3071 /* Allocate player private map here; it is needed in different modules
3072 * besides this one ((i.e. sg_load_player_*()). */
3073 player_map_init(pplayer);
3074 } players_iterate_end;
3076 if (secfile_lookup_bool_default(loading->file, TRUE,
3077 "game.save_known")) {
3078 int lines = player_slot_max_used_number()/32 + 1, j, p, l, i;
3079 unsigned int *known = fc_calloc(lines * MAP_INDEX_SIZE, sizeof(*known));
3081 for (l = 0; l < lines; l++) {
3082 for (j = 0; j < 8; j++) {
3083 for (i = 0; i < 4; i++) {
3084 /* Only bother trying to load the map for this halfbyte if at least
3085 * one of the corresponding player slots is in use. */
3086 if (player_slot_is_used(player_slot_by_number(l*32 + j*4 + i))) {
3087 LOAD_MAP_CHAR(ch, ptile,
3088 known[l * MAP_INDEX_SIZE + tile_index(ptile)]
3089 |= ascii_hex2bin(ch, j),
3090 loading->file, "map.k%02d_%04d", l * 8 + j);
3091 break;
3097 players_iterate(pplayer) {
3098 dbv_clr_all(&pplayer->tile_known);
3099 } players_iterate_end;
3101 /* HACK: we read the known data from hex into 32-bit integers, and
3102 * now we convert it to the known tile data of each player. */
3103 whole_map_iterate(&(wld.map), ptile) {
3104 players_iterate(pplayer) {
3105 p = player_index(pplayer);
3106 l = player_index(pplayer) / 32;
3108 if (known[l * MAP_INDEX_SIZE + tile_index(ptile)] & (1u << (p % 32))) {
3109 map_set_known(ptile, pplayer);
3111 } players_iterate_end;
3112 } whole_map_iterate_end;
3114 FC_FREE(known);
3118 /****************************************************************************
3119 Save tile known status for whole map and all players
3120 ****************************************************************************/
3121 static void sg_save_map_known(struct savedata *saving)
3123 /* Check status and return if not OK (sg_success != TRUE). */
3124 sg_check_ret();
3126 if (!saving->save_players) {
3127 secfile_insert_bool(saving->file, FALSE, "game.save_known");
3128 return;
3129 } else {
3130 int lines = player_slot_max_used_number()/32 + 1;
3132 secfile_insert_bool(saving->file, game.server.save_options.save_known,
3133 "game.save_known");
3134 if (game.server.save_options.save_known) {
3135 int j, p, l, i;
3136 unsigned int *known = fc_calloc(lines * MAP_INDEX_SIZE, sizeof(*known));
3138 /* HACK: we convert the data into a 32-bit integer, and then save it as
3139 * hex. */
3141 whole_map_iterate(&(wld.map), ptile) {
3142 players_iterate(pplayer) {
3143 if (map_is_known(ptile, pplayer)) {
3144 p = player_index(pplayer);
3145 l = p / 32;
3146 known[l * MAP_INDEX_SIZE + tile_index(ptile)]
3147 |= (1u << (p % 32)); /* "p % 32" = "p - l * 32" */
3149 } players_iterate_end;
3150 } whole_map_iterate_end;
3152 for (l = 0; l < lines; l++) {
3153 for (j = 0; j < 8; j++) {
3154 for (i = 0; i < 4; i++) {
3155 /* Only bother saving the map for this halfbyte if at least one
3156 * of the corresponding player slots is in use */
3157 if (player_slot_is_used(player_slot_by_number(l*32 + j*4 + i))) {
3158 /* put 4-bit segments of the 32-bit "known" field */
3159 SAVE_MAP_CHAR(ptile, bin2ascii_hex(known[l * MAP_INDEX_SIZE
3160 + tile_index(ptile)], j),
3161 saving->file, "map.k%02d_%04d", l * 8 + j);
3162 break;
3168 FC_FREE(known);
3173 /* =======================================================================
3174 * Load / save player data.
3176 * This is splitted into two parts as some data can only be loaded if the
3177 * number of players is known and the corresponding player slots are
3178 * defined.
3179 * ======================================================================= */
3181 /****************************************************************************
3182 Load '[player]' (basic data).
3183 ****************************************************************************/
3184 static void sg_load_players_basic(struct loaddata *loading)
3186 int i, k, nplayers;
3187 const char *str;
3188 bool shuffle_loaded = TRUE;
3190 /* Check status and return if not OK (sg_success != TRUE). */
3191 sg_check_ret();
3193 if (S_S_INITIAL == loading->server_state
3194 || game.info.is_new_game) {
3195 /* Nothing more to do. */
3196 return;
3199 /* Load destroyed wonders: */
3200 str = secfile_lookup_str(loading->file,
3201 "players.destroyed_wonders");
3202 sg_failure_ret(str != NULL, "%s", secfile_error());
3203 sg_failure_ret(strlen(str) == loading->improvement.size,
3204 "Invalid length for 'players.destroyed_wonders' "
3205 "(%lu ~= %lu)", (unsigned long) strlen(str),
3206 (unsigned long) loading->improvement.size);
3207 for (k = 0; k < loading->improvement.size; k++) {
3208 sg_failure_ret(str[k] == '1' || str[k] == '0',
3209 "Undefined value '%c' within "
3210 "'players.destroyed_wonders'.", str[k]);
3212 if (str[k] == '1') {
3213 struct impr_type *pimprove =
3214 improvement_by_rule_name(loading->improvement.order[k]);
3215 if (pimprove) {
3216 game.info.great_wonder_owners[improvement_index(pimprove)]
3217 = WONDER_DESTROYED;
3222 server.identity_number
3223 = secfile_lookup_int_default(loading->file, server.identity_number,
3224 "players.identity_number_used");
3226 /* First remove all defined players. */
3227 players_iterate(pplayer) {
3228 server_remove_player(pplayer);
3229 } players_iterate_end;
3231 /* Now, load the players from the savefile. */
3232 player_slots_iterate(pslot) {
3233 struct player *pplayer;
3234 struct rgbcolor *prgbcolor = NULL;
3235 int pslot_id = player_slot_index(pslot);
3237 if (NULL == secfile_section_lookup(loading->file, "player%d",
3238 pslot_id)) {
3239 continue;
3242 /* Get player AI type. */
3243 str = secfile_lookup_str(loading->file, "player%d.ai_type",
3244 player_slot_index(pslot));
3245 sg_failure_ret(str != NULL, "%s", secfile_error());
3247 /* Get player color */
3248 if (!rgbcolor_load(loading->file, &prgbcolor, "player%d.color",
3249 pslot_id)) {
3250 if (game_was_started()) {
3251 log_sg("Game has started, yet player %d has no color defined.",
3252 pslot_id);
3253 /* This will be fixed up later */
3254 } else {
3255 log_verbose("No color defined for player %d.", pslot_id);
3256 /* Colors will be assigned on game start, or at end of savefile
3257 * loading if game has already started */
3261 /* Create player. */
3262 pplayer = server_create_player(player_slot_index(pslot), str,
3263 prgbcolor, game.scenario.allow_ai_type_fallback);
3264 sg_failure_ret(pplayer != NULL, "Invalid AI type: '%s'!", str);
3266 server_player_init(pplayer, FALSE, FALSE);
3268 /* Free the color definition. */
3269 rgbcolor_destroy(prgbcolor);
3271 /* Multipliers (policies) */
3273 /* First initialise player values with ruleset defaults; this will
3274 * cover any in the ruleset not known when the savefile was created. */
3275 multipliers_iterate(pmul) {
3276 pplayer->multipliers[multiplier_index(pmul)]
3277 = pplayer->multipliers_target[multiplier_index(pmul)] = pmul->def;
3278 } multipliers_iterate_end;
3280 /* Now override with any values from the savefile. */
3281 for (k = 0; k < loading->multiplier.size; k++) {
3282 const struct multiplier *pmul = loading->multiplier.order[k];
3284 if (pmul) {
3285 Multiplier_type_id idx = multiplier_index(pmul);
3286 int val =
3287 secfile_lookup_int_default(loading->file, pmul->def,
3288 "player%d.multiplier%d.val",
3289 player_slot_index(pslot), k);
3290 int rval = (((CLIP(pmul->start, val, pmul->stop)
3291 - pmul->start) / pmul->step) * pmul->step) + pmul->start;
3293 if (rval != val) {
3294 log_verbose("Player %d had illegal value for multiplier \"%s\": "
3295 "was %d, clamped to %d", pslot_id,
3296 multiplier_rule_name(pmul), val, rval);
3298 pplayer->multipliers[idx] = rval;
3300 val =
3301 secfile_lookup_int_default(loading->file,
3302 pplayer->multipliers[idx],
3303 "player%d.multiplier%d.target",
3304 player_slot_index(pslot), k);
3305 rval = (((CLIP(pmul->start, val, pmul->stop)
3306 - pmul->start) / pmul->step) * pmul->step) + pmul->start;
3308 if (rval != val) {
3309 log_verbose("Player %d had illegal value for multiplier_target "
3310 " \"%s\": was %d, clamped to %d", pslot_id,
3311 multiplier_rule_name(pmul), val, rval);
3313 pplayer->multipliers_target[idx] = rval;
3314 } /* else silently discard multiplier not in current ruleset */
3317 /* Must be loaded before tile owner is set. */
3318 pplayer->server.border_vision =
3319 secfile_lookup_bool_default(loading->file, FALSE,
3320 "player%d.border_vision",
3321 player_slot_index(pslot));
3322 } player_slots_iterate_end;
3324 /* check number of players */
3325 nplayers = secfile_lookup_int_default(loading->file, 0, "players.nplayers");
3326 sg_failure_ret(player_count() == nplayers, "The value of players.nplayers "
3327 "(%d) from the loaded game does not match the number of "
3328 "players present (%d).", nplayers, player_count());
3330 /* Load team informations. */
3331 players_iterate(pplayer) {
3332 int team;
3333 struct team_slot *tslot = NULL;
3335 sg_failure_ret(secfile_lookup_int(loading->file, &team,
3336 "player%d.team_no",
3337 player_number(pplayer))
3338 && (tslot = team_slot_by_number(team)),
3339 "Invalid team definition for player %s (nb %d).",
3340 player_name(pplayer), player_number(pplayer));
3341 team_add_player(pplayer, team_new(tslot));
3342 } players_iterate_end;
3344 /* Loading the shuffle list is quite complex. At the time of saving the
3345 * shuffle data is saved as
3346 * shuffled_player_<number> = player_slot_id
3347 * where number is an increasing number and player_slot_id is a number
3348 * between 0 and the maximum number of player slots. Now we have to create
3349 * a list
3350 * shuffler_players[number] = player_slot_id
3351 * where all player slot IDs are used exactly one time. The code below
3352 * handles this ... */
3353 if (secfile_lookup_int_default(loading->file, -1,
3354 "players.shuffled_player_%d", 0) >= 0) {
3355 int shuffled_players[player_slot_count()];
3356 bool shuffled_player_set[player_slot_count()];
3358 player_slots_iterate(pslot) {
3359 int plrid = player_slot_index(pslot);
3361 /* Array to save used numbers. */
3362 shuffled_player_set[plrid] = FALSE;
3363 /* List of all player IDs (needed for set_shuffled_players()). It is
3364 * initialised with the value -1 to indicate that no value is set. */
3365 shuffled_players[plrid] = -1;
3366 } player_slots_iterate_end;
3368 /* Load shuffled player list. */
3369 for (i = 0; i < player_count(); i++){
3370 int shuffle
3371 = secfile_lookup_int_default(loading->file, -1,
3372 "players.shuffled_player_%d", i);
3374 if (shuffle == -1) {
3375 log_sg("Missing player shuffle information (index %d) "
3376 "- reshuffle player list!", i);
3377 shuffle_loaded = FALSE;
3378 break;
3379 } else if (shuffled_player_set[shuffle]) {
3380 log_sg("Player shuffle %d used two times "
3381 "- reshuffle player list!", shuffle);
3382 shuffle_loaded = FALSE;
3383 break;
3385 /* Set this ID as used. */
3386 shuffled_player_set[shuffle] = TRUE;
3388 /* Save the player ID in the shuffle list. */
3389 shuffled_players[i] = shuffle;
3392 if (shuffle_loaded) {
3393 /* Insert missing numbers. */
3394 int shuffle_index = player_count();
3395 for (i = 0; i < player_slot_count(); i++){
3396 if (!shuffled_player_set[i]) {
3397 shuffled_players[shuffle_index] = i;
3398 shuffle_index++;
3400 /* shuffle_index must not grow behind the size of shuffled_players. */
3401 sg_failure_ret(shuffle_index <= player_slot_count(),
3402 "Invalid player shuffle data!");
3405 #ifdef FREECIV_DEBUG
3406 log_debug("[load shuffle] player_count() = %d", player_count());
3407 player_slots_iterate(pslot) {
3408 int plrid = player_slot_index(pslot);
3409 log_debug("[load shuffle] id: %3d => slot: %3d | slot %3d: %s",
3410 plrid, shuffled_players[plrid], plrid,
3411 shuffled_player_set[plrid] ? "is used" : "-");
3412 } player_slots_iterate_end;
3413 #endif /* FREECIV_DEBUG */
3415 /* Set shuffle list from savegame. */
3416 set_shuffled_players(shuffled_players);
3420 if (!shuffle_loaded) {
3421 /* No shuffled players included or error loading them, so shuffle them
3422 * (this may include scenarios). */
3423 shuffle_players();
3427 /****************************************************************************
3428 Load '[player]'.
3429 ****************************************************************************/
3430 static void sg_load_players(struct loaddata *loading)
3432 /* Check status and return if not OK (sg_success != TRUE). */
3433 sg_check_ret();
3435 if (game.info.is_new_game) {
3436 /* Nothing to do. */
3437 return;
3440 players_iterate(pplayer) {
3441 sg_load_player_main(loading, pplayer);
3442 sg_load_player_cities(loading, pplayer);
3443 sg_load_player_units(loading, pplayer);
3444 sg_load_player_attributes(loading, pplayer);
3446 /* Check the sucess of the functions above. */
3447 sg_check_ret();
3449 /* print out some informations */
3450 if (is_ai(pplayer)) {
3451 log_normal(_("%s has been added as %s level AI-controlled player "
3452 "(%s)."), player_name(pplayer),
3453 ai_level_translated_name(pplayer->ai_common.skill_level),
3454 ai_name(pplayer->ai));
3455 } else {
3456 log_normal(_("%s has been added as human player."),
3457 player_name(pplayer));
3459 } players_iterate_end;
3461 /* Also load the transport status of the units here. It must be a special
3462 * case as all units must be known (unit on an allied transporter). */
3463 players_iterate(pplayer) {
3464 /* Load unit transport status. */
3465 sg_load_player_units_transport(loading, pplayer);
3466 } players_iterate_end;
3468 /* Savegame may contain nation assignments that are incompatible with the
3469 * current nationset -- for instance, if it predates the introduction of
3470 * nationsets. Ensure they are compatible, one way or another. */
3471 fit_nationset_to_players();
3473 /* Some players may have invalid nations in the ruleset. Once all players
3474 * are loaded, pick one of the remaining nations for them. */
3475 players_iterate(pplayer) {
3476 if (pplayer->nation == NO_NATION_SELECTED) {
3477 player_set_nation(pplayer, pick_a_nation(NULL, FALSE, TRUE,
3478 NOT_A_BARBARIAN));
3479 /* TRANS: Minor error message: <Leader> ... <Poles>. */
3480 log_sg(_("%s had invalid nation; changing to %s."),
3481 player_name(pplayer), nation_plural_for_player(pplayer));
3483 ai_traits_init(pplayer);
3485 } players_iterate_end;
3487 /* Sanity check alliances, prevent allied-with-ally-of-enemy. */
3488 players_iterate_alive(plr) {
3489 players_iterate_alive(aplayer) {
3490 if (pplayers_allied(plr, aplayer)) {
3491 enum dipl_reason can_ally = pplayer_can_make_treaty(plr, aplayer,
3492 DS_ALLIANCE);
3493 if (can_ally == DIPL_ALLIANCE_PROBLEM_US
3494 || can_ally == DIPL_ALLIANCE_PROBLEM_THEM) {
3495 log_sg("Illegal alliance structure detected: "
3496 "%s alliance to %s reduced to peace treaty.",
3497 nation_rule_name(nation_of_player(plr)),
3498 nation_rule_name(nation_of_player(aplayer)));
3499 player_diplstate_get(plr, aplayer)->type = DS_PEACE;
3500 player_diplstate_get(aplayer, plr)->type = DS_PEACE;
3503 } players_iterate_alive_end;
3504 } players_iterate_alive_end;
3506 /* Update cached city illness. This can depend on trade routes,
3507 * so can't be calculated until all players have been loaded. */
3508 if (game.info.illness_on) {
3509 cities_iterate(pcity) {
3510 pcity->server.illness
3511 = city_illness_calc(pcity, NULL, NULL,
3512 &(pcity->illness_trade), NULL);
3513 } cities_iterate_end;
3516 /* Update all city information. This must come after all cities are
3517 * loaded (in player_load) but before player (dumb) cities are loaded
3518 * in player_load_vision(). */
3519 players_iterate(plr) {
3520 city_list_iterate(plr->cities, pcity) {
3521 city_refresh(pcity);
3522 sanity_check_city(pcity);
3523 CALL_PLR_AI_FUNC(city_got, plr, plr, pcity);
3524 } city_list_iterate_end;
3525 } players_iterate_end;
3527 /* Since the cities must be placed on the map to put them on the
3528 player map we do this afterwards */
3529 players_iterate(pplayer) {
3530 sg_load_player_vision(loading, pplayer);
3531 /* Check the sucess of the function above. */
3532 sg_check_ret();
3533 } players_iterate_end;
3535 /* Check shared vision. */
3536 players_iterate(pplayer) {
3537 BV_CLR_ALL(pplayer->gives_shared_vision);
3538 BV_CLR_ALL(pplayer->server.really_gives_vision);
3539 } players_iterate_end;
3541 players_iterate(pplayer) {
3542 int plr1 = player_index(pplayer);
3544 players_iterate(pplayer2) {
3545 int plr2 = player_index(pplayer2);
3546 if (secfile_lookup_bool_default(loading->file, FALSE,
3547 "player%d.diplstate%d.gives_shared_vision", plr1, plr2)) {
3548 give_shared_vision(pplayer, pplayer2);
3550 } players_iterate_end;
3551 } players_iterate_end;
3553 initialize_globals();
3554 unit_ordering_apply();
3556 /* All vision is ready; this calls city_thaw_workers_queue(). */
3557 map_calculate_borders();
3559 /* Make sure everything is consistent. */
3560 players_iterate(pplayer) {
3561 unit_list_iterate(pplayer->units, punit) {
3562 if (!can_unit_continue_current_activity(punit)) {
3563 log_sg("Unit doing illegal activity in savegame!");
3564 log_sg("Activity: %s, Target: %s",
3565 unit_activity_name(punit->activity),
3566 punit->activity_target ? extra_rule_name(
3567 punit->activity_target)
3568 : "missing");
3569 punit->activity = ACTIVITY_IDLE;
3571 } unit_list_iterate_end;
3572 } players_iterate_end;
3574 cities_iterate(pcity) {
3575 city_refresh(pcity);
3576 city_thaw_workers(pcity); /* may auto_arrange_workers() */
3577 } cities_iterate_end;
3579 /* Player colors are always needed once game has started. Pre-2.4 savegames
3580 * lack them. This cannot be in compatibility conversion layer as we need
3581 * all the player data available to be able to assign best colors. */
3582 if (game_was_started()) {
3583 assign_player_colors();
3587 /****************************************************************************
3588 Save '[player]'.
3589 ****************************************************************************/
3590 static void sg_save_players(struct savedata *saving)
3592 /* Check status and return if not OK (sg_success != TRUE). */
3593 sg_check_ret();
3595 if ((saving->scenario && !saving->save_players)
3596 || !game_was_started()) {
3597 /* Nothing to do for a scenario without saved players or a game in
3598 * INITIAL state. */
3599 return;
3602 secfile_insert_int(saving->file, player_count(), "players.nplayers");
3604 /* Save destroyed wonders as bitvector. Note that improvement order
3605 * is saved in 'savefile.improvement.order'. */
3607 char destroyed[B_LAST+1];
3609 improvement_iterate(pimprove) {
3610 if (is_great_wonder(pimprove)
3611 && great_wonder_is_destroyed(pimprove)) {
3612 destroyed[improvement_index(pimprove)] = '1';
3613 } else {
3614 destroyed[improvement_index(pimprove)] = '0';
3616 } improvement_iterate_end;
3617 destroyed[improvement_count()] = '\0';
3618 secfile_insert_str(saving->file, destroyed,
3619 "players.destroyed_wonders");
3622 secfile_insert_int(saving->file, server.identity_number,
3623 "players.identity_number_used");
3625 /* Save player order. */
3627 int i = 0;
3628 shuffled_players_iterate(pplayer) {
3629 secfile_insert_int(saving->file, player_number(pplayer),
3630 "players.shuffled_player_%d", i);
3631 i++;
3632 } shuffled_players_iterate_end;
3635 /* Sort units. */
3636 unit_ordering_calc();
3638 /* Save players. */
3639 players_iterate(pplayer) {
3640 sg_save_player_main(saving, pplayer);
3641 sg_save_player_cities(saving, pplayer);
3642 sg_save_player_units(saving, pplayer);
3643 sg_save_player_attributes(saving, pplayer);
3644 sg_save_player_vision(saving, pplayer);
3645 } players_iterate_end;
3648 /****************************************************************************
3649 Main player data loading function
3650 ****************************************************************************/
3651 static void sg_load_player_main(struct loaddata *loading,
3652 struct player *plr)
3654 const char **slist;
3655 int i, plrno = player_number(plr);
3656 const char *str;
3657 struct government *gov;
3658 const char *level;
3659 const char *barb_str;
3660 size_t nval;
3661 const char *kind;
3663 /* Check status and return if not OK (sg_success != TRUE). */
3664 sg_check_ret();
3666 /* Basic player data. */
3667 str = secfile_lookup_str(loading->file, "player%d.name", plrno);
3668 sg_failure_ret(str != NULL, "%s", secfile_error());
3669 server_player_set_name(plr, str);
3670 sz_strlcpy(plr->username,
3671 secfile_lookup_str_default(loading->file, "",
3672 "player%d.username", plrno));
3673 sg_failure_ret(secfile_lookup_bool(loading->file, &plr->unassigned_user,
3674 "player%d.unassigned_user", plrno),
3675 "%s", secfile_error());
3676 sz_strlcpy(plr->ranked_username,
3677 secfile_lookup_str_default(loading->file, "",
3678 "player%d.ranked_username",
3679 plrno));
3680 sg_failure_ret(secfile_lookup_bool(loading->file, &plr->unassigned_ranked,
3681 "player%d.unassigned_ranked", plrno),
3682 "%s", secfile_error());
3683 str = secfile_lookup_str_default(loading->file, "",
3684 "player%d.delegation_username",
3685 plrno);
3686 /* Defaults to no delegation. */
3687 if (strlen(str)) {
3688 player_delegation_set(plr, str);
3691 /* Player flags */
3692 BV_CLR_ALL(plr->flags);
3693 slist = secfile_lookup_str_vec(loading->file, &nval, "player%d.flags", plrno);
3694 for (i = 0; i < nval; i++) {
3695 const char *sval = slist[i];
3696 enum plr_flag_id fid = plr_flag_id_by_name(sval, fc_strcasecmp);
3698 BV_SET(plr->flags, fid);
3700 free(slist);
3702 /* Nation */
3703 str = secfile_lookup_str(loading->file, "player%d.nation", plrno);
3704 player_set_nation(plr, nation_by_rule_name(str));
3705 if (plr->nation != NULL) {
3706 ai_traits_init(plr);
3709 /* Government */
3710 str = secfile_lookup_str(loading->file, "player%d.government_name",
3711 plrno);
3712 gov = government_by_rule_name(str);
3713 sg_failure_ret(gov != NULL, "Player%d: unsupported government \"%s\".",
3714 plrno, str);
3715 plr->government = gov;
3717 /* Target government */
3718 str = secfile_lookup_str(loading->file,
3719 "player%d.target_government_name", plrno);
3720 if (str != NULL) {
3721 plr->target_government = government_by_rule_name(str);
3722 } else {
3723 plr->target_government = NULL;
3725 plr->revolution_finishes
3726 = secfile_lookup_int_default(loading->file, -1,
3727 "player%d.revolution_finishes", plrno);
3729 sg_failure_ret(secfile_lookup_bool(loading->file,
3730 &plr->server.got_first_city,
3731 "player%d.got_first_city", plrno),
3732 "%s", secfile_error());
3734 /* Load diplomatic data (diplstate + embassy + vision).
3735 * Shared vision is loaded in sg_load_players(). */
3736 BV_CLR_ALL(plr->real_embassy);
3737 players_iterate(pplayer) {
3738 char buf[32];
3739 struct player_diplstate *ds = player_diplstate_get(plr, pplayer);
3740 i = player_index(pplayer);
3742 /* load diplomatic status */
3743 fc_snprintf(buf, sizeof(buf), "player%d.diplstate%d", plrno, i);
3745 ds->type =
3746 secfile_lookup_enum_default(loading->file, DS_WAR,
3747 diplstate_type, "%s.current", buf);
3748 ds->max_state =
3749 secfile_lookup_enum_default(loading->file, DS_WAR,
3750 diplstate_type, "%s.closest", buf);
3751 ds->first_contact_turn =
3752 secfile_lookup_int_default(loading->file, 0,
3753 "%s.first_contact_turn", buf);
3754 ds->turns_left =
3755 secfile_lookup_int_default(loading->file, -2, "%s.turns_left", buf);
3756 ds->has_reason_to_cancel =
3757 secfile_lookup_int_default(loading->file, 0,
3758 "%s.has_reason_to_cancel", buf);
3759 ds->contact_turns_left =
3760 secfile_lookup_int_default(loading->file, 0,
3761 "%s.contact_turns_left", buf);
3763 if (secfile_lookup_bool_default(loading->file, FALSE, "%s.embassy",
3764 buf)) {
3765 BV_SET(plr->real_embassy, i);
3767 /* 'gives_shared_vision' is loaded in sg_load_players() as all cities
3768 * must be known. */
3769 } players_iterate_end;
3771 /* load ai data */
3772 players_iterate(aplayer) {
3773 char buf[32];
3775 fc_snprintf(buf, sizeof(buf), "player%d.ai%d", plrno,
3776 player_index(aplayer));
3778 plr->ai_common.love[player_index(aplayer)] =
3779 secfile_lookup_int_default(loading->file, 1, "%s.love", buf);
3780 CALL_FUNC_EACH_AI(player_load_relations, plr, aplayer, loading->file, plrno);
3781 } players_iterate_end;
3783 CALL_FUNC_EACH_AI(player_load, plr, loading->file, plrno);
3785 /* Some sane defaults */
3786 plr->ai_common.fuzzy = 0;
3787 plr->ai_common.expand = 100;
3788 plr->ai_common.science_cost = 100;
3791 level = secfile_lookup_str_default(loading->file, NULL,
3792 "player%d.ai.level", plrno);
3793 if (level != NULL) {
3794 plr->ai_common.skill_level = ai_level_by_name(level, fc_strcasecmp);
3796 /* In builds where level "Experimental" is not supported, convert it to "Hard" */
3797 if (!ai_level_is_valid(plr->ai_common.skill_level)
3798 && !fc_strcasecmp(level, "Experimental")) {
3799 plr->ai_common.skill_level = AI_LEVEL_HARD;
3801 } else {
3802 plr->ai_common.skill_level = ai_level_invalid();
3805 if (!ai_level_is_valid(plr->ai_common.skill_level)) {
3806 plr->ai_common.skill_level
3807 = ai_level_convert(secfile_lookup_int_default(loading->file,
3808 game.info.skill_level,
3809 "player%d.ai.skill_level",
3810 plrno));
3813 barb_str = secfile_lookup_str_default(loading->file, "None",
3814 "player%d.ai.barb_type", plrno);
3815 plr->ai_common.barbarian_type = barbarian_type_by_name(barb_str, fc_strcasecmp);
3817 if (!barbarian_type_is_valid(plr->ai_common.barbarian_type)) {
3818 log_sg("Player%d: Invalid barbarian type \"%s\". "
3819 "Changed to \"None\".", plrno, barb_str);
3820 plr->ai_common.barbarian_type = NOT_A_BARBARIAN;
3823 if (is_barbarian(plr)) {
3824 server.nbarbarians++;
3827 if (is_ai(plr)) {
3828 set_ai_level_directer(plr, plr->ai_common.skill_level);
3829 CALL_PLR_AI_FUNC(gained_control, plr, plr);
3832 /* Load nation style. */
3834 struct nation_style *style;
3836 str = secfile_lookup_str(loading->file, "player%d.style_by_name", plrno);
3838 sg_failure_ret(str != NULL, "%s", secfile_error());
3839 style = style_by_rule_name(str);
3840 if (style == NULL) {
3841 style = style_by_number(0);
3842 log_sg("Player%d: unsupported city_style_name \"%s\". "
3843 "Changed to \"%s\".", plrno, str, style_rule_name(style));
3845 plr->style = style;
3848 sg_failure_ret(secfile_lookup_int(loading->file, &plr->nturns_idle,
3849 "player%d.idle_turns", plrno),
3850 "%s", secfile_error());
3851 kind = secfile_lookup_str(loading->file, "player%d.kind", plrno);
3852 if (!strcmp("male", kind)) {
3853 plr->is_male = TRUE;
3854 } else {
3855 plr->is_male = FALSE;
3857 sg_failure_ret(secfile_lookup_bool(loading->file, &plr->is_alive,
3858 "player%d.is_alive", plrno),
3859 "%s", secfile_error());
3860 sg_failure_ret(secfile_lookup_int(loading->file, &plr->turns_alive,
3861 "player%d.turns_alive", plrno),
3862 "%s", secfile_error());
3863 sg_failure_ret(secfile_lookup_int(loading->file, &plr->last_war_action,
3864 "player%d.last_war", plrno),
3865 "%s", secfile_error());
3866 plr->phase_done = secfile_lookup_bool_default(loading->file, FALSE,
3867 "player%d.phase_done", plrno);
3868 sg_failure_ret(secfile_lookup_int(loading->file, &plr->economic.gold,
3869 "player%d.gold", plrno),
3870 "%s", secfile_error());
3871 sg_failure_ret(secfile_lookup_int(loading->file, &plr->economic.tax,
3872 "player%d.rates.tax", plrno),
3873 "%s", secfile_error());
3874 sg_failure_ret(secfile_lookup_int(loading->file, &plr->economic.science,
3875 "player%d.rates.science", plrno),
3876 "%s", secfile_error());
3877 sg_failure_ret(secfile_lookup_int(loading->file, &plr->economic.luxury,
3878 "player%d.rates.luxury", plrno),
3879 "%s", secfile_error());
3880 plr->server.bulbs_last_turn =
3881 secfile_lookup_int_default(loading->file, 0,
3882 "player%d.research.bulbs_last_turn", plrno);
3884 /* Traits */
3885 if (plr->nation) {
3886 for (i = 0; i < loading->trait.size; i++) {
3887 enum trait tr = trait_by_name(loading->trait.order[i], fc_strcasecmp);
3889 if (trait_is_valid(tr)) {
3890 int val;
3892 sg_failure_ret(secfile_lookup_int(loading->file, &val, "player%d.trait%d.val",
3893 plrno, i),
3894 "%s", secfile_error());
3895 plr->ai_common.traits[tr].val = val;
3897 sg_failure_ret(secfile_lookup_int(loading->file, &val,
3898 "player%d.trait%d.mod", plrno, i),
3899 "%s", secfile_error());
3900 plr->ai_common.traits[tr].mod = val;
3905 /* Achievements */
3907 int count;
3909 count = secfile_lookup_int_default(loading->file, -1,
3910 "player%d.achievement_count", plrno);
3912 if (count > 0) {
3913 for (i = 0; i < count; i++) {
3914 const char *name;
3915 struct achievement *pach;
3916 bool first;
3918 name = secfile_lookup_str(loading->file,
3919 "player%d.achievement%d.name", plrno, i);
3920 pach = achievement_by_rule_name(name);
3922 sg_failure_ret(pach != NULL,
3923 "Unknown achievement \"%s\".", name);
3925 sg_failure_ret(secfile_lookup_bool(loading->file, &first,
3926 "player%d.achievement%d.first",
3927 plrno, i),
3928 "achievement error: %s", secfile_error());
3930 sg_failure_ret(pach->first == NULL || !first,
3931 "Multiple players listed as first to get achievement \"%s\".",
3932 name);
3934 BV_SET(pach->achievers, player_index(plr));
3936 if (first) {
3937 pach->first = plr;
3943 /* Player score. */
3944 plr->score.happy =
3945 secfile_lookup_int_default(loading->file, 0,
3946 "score%d.happy", plrno);
3947 plr->score.content =
3948 secfile_lookup_int_default(loading->file, 0,
3949 "score%d.content", plrno);
3950 plr->score.unhappy =
3951 secfile_lookup_int_default(loading->file, 0,
3952 "score%d.unhappy", plrno);
3953 plr->score.angry =
3954 secfile_lookup_int_default(loading->file, 0,
3955 "score%d.angry", plrno);
3957 /* Make sure that the score about specialists in current ruleset that
3958 * were not present at saving time are set to zero. */
3959 specialist_type_iterate(sp) {
3960 plr->score.specialists[sp] = 0;
3961 } specialist_type_iterate_end;
3963 for (i = 0; i < loading->specialist.size; i++) {
3964 plr->score.specialists[specialist_index(loading->specialist.order[i])]
3965 = secfile_lookup_int_default(loading->file, 0,
3966 "score%d.specialists%d", plrno, i);
3969 plr->score.wonders =
3970 secfile_lookup_int_default(loading->file, 0,
3971 "score%d.wonders", plrno);
3972 plr->score.techs =
3973 secfile_lookup_int_default(loading->file, 0,
3974 "score%d.techs", plrno);
3975 plr->score.techout =
3976 secfile_lookup_int_default(loading->file, 0,
3977 "score%d.techout", plrno);
3978 plr->score.landarea =
3979 secfile_lookup_int_default(loading->file, 0,
3980 "score%d.landarea", plrno);
3981 plr->score.settledarea =
3982 secfile_lookup_int_default(loading->file, 0,
3983 "score%d.settledarea", plrno);
3984 plr->score.population =
3985 secfile_lookup_int_default(loading->file, 0,
3986 "score%d.population", plrno);
3987 plr->score.cities =
3988 secfile_lookup_int_default(loading->file, 0,
3989 "score%d.cities", plrno);
3990 plr->score.units =
3991 secfile_lookup_int_default(loading->file, 0,
3992 "score%d.units", plrno);
3993 plr->score.pollution =
3994 secfile_lookup_int_default(loading->file, 0,
3995 "score%d.pollution", plrno);
3996 plr->score.literacy =
3997 secfile_lookup_int_default(loading->file, 0,
3998 "score%d.literacy", plrno);
3999 plr->score.bnp =
4000 secfile_lookup_int_default(loading->file, 0,
4001 "score%d.bnp", plrno);
4002 plr->score.mfg =
4003 secfile_lookup_int_default(loading->file, 0,
4004 "score%d.mfg", plrno);
4005 plr->score.spaceship =
4006 secfile_lookup_int_default(loading->file, 0,
4007 "score%d.spaceship", plrno);
4008 plr->score.units_built =
4009 secfile_lookup_int_default(loading->file, 0,
4010 "score%d.units_built", plrno);
4011 plr->score.units_killed =
4012 secfile_lookup_int_default(loading->file, 0,
4013 "score%d.units_killed", plrno);
4014 plr->score.units_lost =
4015 secfile_lookup_int_default(loading->file, 0,
4016 "score%d.units_lost", plrno);
4017 plr->score.culture =
4018 secfile_lookup_int_default(loading->file, 0,
4019 "score%d.culture", plrno);
4020 plr->score.game =
4021 secfile_lookup_int_default(loading->file, 0,
4022 "score%d.total", plrno);
4024 /* Load space ship data. */
4026 struct player_spaceship *ship = &plr->spaceship;
4027 char prefix[32];
4028 const char *st;
4029 int ei;
4031 fc_snprintf(prefix, sizeof(prefix), "player%d.spaceship", plrno);
4032 spaceship_init(ship);
4033 sg_failure_ret(secfile_lookup_int(loading->file,
4034 &ei,
4035 "%s.state", prefix),
4036 "%s", secfile_error());
4037 ship->state = ei;
4039 if (ship->state != SSHIP_NONE) {
4040 sg_failure_ret(secfile_lookup_int(loading->file, &ship->structurals,
4041 "%s.structurals", prefix),
4042 "%s", secfile_error());
4043 sg_failure_ret(secfile_lookup_int(loading->file, &ship->components,
4044 "%s.components", prefix),
4045 "%s", secfile_error());
4046 sg_failure_ret(secfile_lookup_int(loading->file, &ship->modules,
4047 "%s.modules", prefix),
4048 "%s", secfile_error());
4049 sg_failure_ret(secfile_lookup_int(loading->file, &ship->fuel,
4050 "%s.fuel", prefix),
4051 "%s", secfile_error());
4052 sg_failure_ret(secfile_lookup_int(loading->file, &ship->propulsion,
4053 "%s.propulsion", prefix),
4054 "%s", secfile_error());
4055 sg_failure_ret(secfile_lookup_int(loading->file, &ship->habitation,
4056 "%s.habitation", prefix),
4057 "%s", secfile_error());
4058 sg_failure_ret(secfile_lookup_int(loading->file, &ship->life_support,
4059 "%s.life_support", prefix),
4060 "%s", secfile_error());
4061 sg_failure_ret(secfile_lookup_int(loading->file, &ship->solar_panels,
4062 "%s.solar_panels", prefix),
4063 "%s", secfile_error());
4065 st = secfile_lookup_str(loading->file, "%s.structure", prefix);
4066 sg_failure_ret(st != NULL, "%s", secfile_error())
4067 for (i = 0; i < NUM_SS_STRUCTURALS && st[i]; i++) {
4068 sg_failure_ret(st[i] == '1' || st[i] == '0',
4069 "Undefined value '%c' within '%s.structure'.", st[i],
4070 prefix)
4072 if (!(st[i] == '0')) {
4073 BV_SET(ship->structure, i);
4076 if (ship->state >= SSHIP_LAUNCHED) {
4077 sg_failure_ret(secfile_lookup_int(loading->file, &ship->launch_year,
4078 "%s.launch_year", prefix),
4079 "%s", secfile_error());
4081 spaceship_calc_derived(ship);
4085 /* Load lost wonder data. */
4086 str = secfile_lookup_str(loading->file, "player%d.lost_wonders", plrno);
4087 /* If not present, probably an old savegame; nothing to be done */
4088 if (str != NULL) {
4089 int k;
4090 sg_failure_ret(strlen(str) == loading->improvement.size,
4091 "Invalid length for 'player%d.lost_wonders' "
4092 "(%lu ~= %lu)", plrno, (unsigned long) strlen(str),
4093 (unsigned long) loading->improvement.size);
4094 for (k = 0; k < loading->improvement.size; k++) {
4095 sg_failure_ret(str[k] == '1' || str[k] == '0',
4096 "Undefined value '%c' within "
4097 "'player%d.lost_wonders'.", plrno, str[k]);
4099 if (str[k] == '1') {
4100 struct impr_type *pimprove =
4101 improvement_by_rule_name(loading->improvement.order[k]);
4102 if (pimprove) {
4103 plr->wonders[improvement_index(pimprove)] = WONDER_LOST;
4109 plr->culture =
4110 secfile_lookup_int_default(loading->file, 0, "player%d.culture", plrno);
4111 plr->server.huts =
4112 secfile_lookup_int_default(loading->file, 0, "player%d.hut_count", plrno);
4115 /****************************************************************************
4116 Main player data saving function.
4117 ****************************************************************************/
4118 static void sg_save_player_main(struct savedata *saving,
4119 struct player *plr)
4121 int i, k, plrno = player_number(plr);
4122 struct player_spaceship *ship = &plr->spaceship;
4123 const char *flag_names[PLRF_COUNT];
4124 int set_count;
4126 /* Check status and return if not OK (sg_success != TRUE). */
4127 sg_check_ret();
4129 set_count = 0;
4130 for (i = 0; i < PLRF_COUNT; i++){
4131 if (player_has_flag(plr, i)) {
4132 flag_names[set_count++] = plr_flag_id_name(i);
4136 secfile_insert_str_vec(saving->file, flag_names, set_count,
4137 "player%d.flags", plrno);
4139 secfile_insert_str(saving->file, ai_name(plr->ai),
4140 "player%d.ai_type", plrno);
4141 secfile_insert_str(saving->file, player_name(plr),
4142 "player%d.name", plrno);
4143 secfile_insert_str(saving->file, plr->username,
4144 "player%d.username", plrno);
4145 secfile_insert_bool(saving->file, plr->unassigned_user,
4146 "player%d.unassigned_user", plrno);
4147 if (plr->rgb != NULL) {
4148 rgbcolor_save(saving->file, plr->rgb, "player%d.color", plrno);
4149 } else {
4150 /* Colorless players are ok in pregame */
4151 if (game_was_started()) {
4152 log_sg("Game has started, yet player %d has no color defined.", plrno);
4155 secfile_insert_str(saving->file, plr->ranked_username,
4156 "player%d.ranked_username", plrno);
4157 secfile_insert_bool(saving->file, plr->unassigned_ranked,
4158 "player%d.unassigned_ranked", plrno);
4159 secfile_insert_str(saving->file,
4160 player_delegation_get(plr) ? player_delegation_get(plr)
4161 : "",
4162 "player%d.delegation_username", plrno);
4163 secfile_insert_str(saving->file, nation_rule_name(nation_of_player(plr)),
4164 "player%d.nation", plrno);
4165 secfile_insert_int(saving->file, plr->team ? team_index(plr->team) : -1,
4166 "player%d.team_no", plrno);
4168 secfile_insert_str(saving->file,
4169 government_rule_name(government_of_player(plr)),
4170 "player%d.government_name", plrno);
4172 if (plr->target_government) {
4173 secfile_insert_str(saving->file,
4174 government_rule_name(plr->target_government),
4175 "player%d.target_government_name", plrno);
4178 secfile_insert_str(saving->file, style_rule_name(plr->style),
4179 "player%d.style_by_name", plrno);
4181 secfile_insert_int(saving->file, plr->nturns_idle,
4182 "player%d.idle_turns", plrno);
4183 if (plr->is_male) {
4184 secfile_insert_str(saving->file, "male",
4185 "player%d.kind", plrno);
4186 } else {
4187 secfile_insert_str(saving->file, "female",
4188 "player%d.kind", plrno);
4190 secfile_insert_bool(saving->file, plr->is_alive,
4191 "player%d.is_alive", plrno);
4192 secfile_insert_int(saving->file, plr->turns_alive,
4193 "player%d.turns_alive", plrno);
4194 secfile_insert_int(saving->file, plr->last_war_action,
4195 "player%d.last_war", plrno);
4196 secfile_insert_bool(saving->file, plr->phase_done,
4197 "player%d.phase_done", plrno);
4199 players_iterate(pplayer) {
4200 char buf[32];
4201 struct player_diplstate *ds = player_diplstate_get(plr, pplayer);
4203 i = player_index(pplayer);
4205 /* save diplomatic state */
4206 fc_snprintf(buf, sizeof(buf), "player%d.diplstate%d", plrno, i);
4208 secfile_insert_enum(saving->file, ds->type,
4209 diplstate_type, "%s.current", buf);
4210 secfile_insert_enum(saving->file, ds->max_state,
4211 diplstate_type, "%s.closest", buf);
4212 secfile_insert_int(saving->file, ds->first_contact_turn,
4213 "%s.first_contact_turn", buf);
4214 secfile_insert_int(saving->file, ds->turns_left,
4215 "%s.turns_left", buf);
4216 secfile_insert_int(saving->file, ds->has_reason_to_cancel,
4217 "%s.has_reason_to_cancel", buf);
4218 secfile_insert_int(saving->file, ds->contact_turns_left,
4219 "%s.contact_turns_left", buf);
4220 secfile_insert_bool(saving->file, player_has_real_embassy(plr, pplayer),
4221 "%s.embassy", buf);
4222 secfile_insert_bool(saving->file, gives_shared_vision(plr, pplayer),
4223 "%s.gives_shared_vision", buf);
4224 } players_iterate_end;
4226 players_iterate(aplayer) {
4227 i = player_index(aplayer);
4228 /* save ai data */
4229 secfile_insert_int(saving->file, plr->ai_common.love[i],
4230 "player%d.ai%d.love", plrno, i);
4231 CALL_FUNC_EACH_AI(player_save_relations, plr, aplayer, saving->file, plrno);
4232 } players_iterate_end;
4234 CALL_FUNC_EACH_AI(player_save, plr, saving->file, plrno);
4236 /* Multipliers (policies) */
4237 i = multiplier_count();
4239 for (k = 0; k < i; k++) {
4240 secfile_insert_int(saving->file, plr->multipliers[k],
4241 "player%d.multiplier%d.val", plrno, k);
4242 secfile_insert_int(saving->file, plr->multipliers_target[k],
4243 "player%d.multiplier%d.target", plrno, k);
4246 secfile_insert_str(saving->file, ai_level_name(plr->ai_common.skill_level),
4247 "player%d.ai.level", plrno);
4248 secfile_insert_str(saving->file, barbarian_type_name(plr->ai_common.barbarian_type),
4249 "player%d.ai.barb_type", plrno);
4250 secfile_insert_int(saving->file, plr->economic.gold,
4251 "player%d.gold", plrno);
4252 secfile_insert_int(saving->file, plr->economic.tax,
4253 "player%d.rates.tax", plrno);
4254 secfile_insert_int(saving->file, plr->economic.science,
4255 "player%d.rates.science", plrno);
4256 secfile_insert_int(saving->file, plr->economic.luxury,
4257 "player%d.rates.luxury", plrno);
4258 secfile_insert_int(saving->file, plr->server.bulbs_last_turn,
4259 "player%d.research.bulbs_last_turn", plrno);
4261 /* Save traits */
4263 enum trait tr;
4264 int j;
4266 for (tr = trait_begin(), j = 0; tr != trait_end(); tr = trait_next(tr), j++) {
4267 secfile_insert_int(saving->file, plr->ai_common.traits[tr].val,
4268 "player%d.trait%d.val", plrno, j);
4269 secfile_insert_int(saving->file, plr->ai_common.traits[tr].mod,
4270 "player%d.trait%d.mod", plrno, j);
4274 /* Save achievements */
4276 int j = 0;
4278 achievements_iterate(pach) {
4279 if (achievement_player_has(pach, plr)) {
4280 secfile_insert_str(saving->file, achievement_rule_name(pach),
4281 "player%d.achievement%d.name", plrno, j);
4282 if (pach->first == plr) {
4283 secfile_insert_bool(saving->file, TRUE,
4284 "player%d.achievement%d.first", plrno, j);
4285 } else {
4286 secfile_insert_bool(saving->file, FALSE,
4287 "player%d.achievement%d.first", plrno, j);
4290 j++;
4292 } achievements_iterate_end;
4294 secfile_insert_int(saving->file, j,
4295 "player%d.achievement_count", plrno);
4298 secfile_insert_bool(saving->file, plr->server.got_first_city,
4299 "player%d.got_first_city", plrno);
4300 secfile_insert_int(saving->file, plr->revolution_finishes,
4301 "player%d.revolution_finishes", plrno);
4303 /* Player score */
4304 secfile_insert_int(saving->file, plr->score.happy,
4305 "score%d.happy", plrno);
4306 secfile_insert_int(saving->file, plr->score.content,
4307 "score%d.content", plrno);
4308 secfile_insert_int(saving->file, plr->score.unhappy,
4309 "score%d.unhappy", plrno);
4310 secfile_insert_int(saving->file, plr->score.angry,
4311 "score%d.angry", plrno);
4312 specialist_type_iterate(sp) {
4313 secfile_insert_int(saving->file, plr->score.specialists[sp],
4314 "score%d.specialists%d", plrno, sp);
4315 } specialist_type_iterate_end;
4316 secfile_insert_int(saving->file, plr->score.wonders,
4317 "score%d.wonders", plrno);
4318 secfile_insert_int(saving->file, plr->score.techs,
4319 "score%d.techs", plrno);
4320 secfile_insert_int(saving->file, plr->score.techout,
4321 "score%d.techout", plrno);
4322 secfile_insert_int(saving->file, plr->score.landarea,
4323 "score%d.landarea", plrno);
4324 secfile_insert_int(saving->file, plr->score.settledarea,
4325 "score%d.settledarea", plrno);
4326 secfile_insert_int(saving->file, plr->score.population,
4327 "score%d.population", plrno);
4328 secfile_insert_int(saving->file, plr->score.cities,
4329 "score%d.cities", plrno);
4330 secfile_insert_int(saving->file, plr->score.units,
4331 "score%d.units", plrno);
4332 secfile_insert_int(saving->file, plr->score.pollution,
4333 "score%d.pollution", plrno);
4334 secfile_insert_int(saving->file, plr->score.literacy,
4335 "score%d.literacy", plrno);
4336 secfile_insert_int(saving->file, plr->score.bnp,
4337 "score%d.bnp", plrno);
4338 secfile_insert_int(saving->file, plr->score.mfg,
4339 "score%d.mfg", plrno);
4340 secfile_insert_int(saving->file, plr->score.spaceship,
4341 "score%d.spaceship", plrno);
4342 secfile_insert_int(saving->file, plr->score.units_built,
4343 "score%d.units_built", plrno);
4344 secfile_insert_int(saving->file, plr->score.units_killed,
4345 "score%d.units_killed", plrno);
4346 secfile_insert_int(saving->file, plr->score.units_lost,
4347 "score%d.units_lost", plrno);
4348 secfile_insert_int(saving->file, plr->score.culture,
4349 "score%d.culture", plrno);
4350 secfile_insert_int(saving->file, plr->score.game,
4351 "score%d.total", plrno);
4353 /* Save space ship status. */
4354 secfile_insert_int(saving->file, ship->state, "player%d.spaceship.state",
4355 plrno);
4356 if (ship->state != SSHIP_NONE) {
4357 char buf[32];
4358 char st[NUM_SS_STRUCTURALS+1];
4359 int ssi;
4361 fc_snprintf(buf, sizeof(buf), "player%d.spaceship", plrno);
4363 secfile_insert_int(saving->file, ship->structurals,
4364 "%s.structurals", buf);
4365 secfile_insert_int(saving->file, ship->components,
4366 "%s.components", buf);
4367 secfile_insert_int(saving->file, ship->modules,
4368 "%s.modules", buf);
4369 secfile_insert_int(saving->file, ship->fuel, "%s.fuel", buf);
4370 secfile_insert_int(saving->file, ship->propulsion, "%s.propulsion", buf);
4371 secfile_insert_int(saving->file, ship->habitation, "%s.habitation", buf);
4372 secfile_insert_int(saving->file, ship->life_support,
4373 "%s.life_support", buf);
4374 secfile_insert_int(saving->file, ship->solar_panels,
4375 "%s.solar_panels", buf);
4377 for (ssi = 0; ssi < NUM_SS_STRUCTURALS; ssi++) {
4378 st[ssi] = BV_ISSET(ship->structure, ssi) ? '1' : '0';
4380 st[ssi] = '\0';
4381 secfile_insert_str(saving->file, st, "%s.structure", buf);
4382 if (ship->state >= SSHIP_LAUNCHED) {
4383 secfile_insert_int(saving->file, ship->launch_year,
4384 "%s.launch_year", buf);
4388 /* Save lost wonders info. */
4390 char lost[B_LAST+1];
4392 improvement_iterate(pimprove) {
4393 if (is_wonder(pimprove) && wonder_is_lost(plr, pimprove)) {
4394 lost[improvement_index(pimprove)] = '1';
4395 } else {
4396 lost[improvement_index(pimprove)] = '0';
4398 } improvement_iterate_end;
4399 lost[improvement_count()] = '\0';
4400 secfile_insert_str(saving->file, lost,
4401 "player%d.lost_wonders", plrno);
4404 secfile_insert_int(saving->file, plr->culture,
4405 "player%d.culture", plrno);
4406 secfile_insert_int(saving->file, plr->server.huts,
4407 "player%d.hut_count", plrno);
4409 secfile_insert_bool(saving->file, plr->server.border_vision,
4410 "player%d.border_vision", plrno);
4413 /****************************************************************************
4414 Load city data
4415 ****************************************************************************/
4416 static void sg_load_player_cities(struct loaddata *loading,
4417 struct player *plr)
4419 int ncities, i, plrno = player_number(plr);
4420 bool tasks_handled;
4422 /* Check status and return if not OK (sg_success != TRUE). */
4423 sg_check_ret();
4425 sg_failure_ret(secfile_lookup_int(loading->file, &ncities,
4426 "player%d.ncities", plrno),
4427 "%s", secfile_error());
4429 if (!plr->is_alive && ncities > 0) {
4430 log_sg("'player%d.ncities' = %d for dead player!", plrno, ncities);
4431 ncities = 0;
4434 if (!plr->server.got_first_city && ncities > 0) {
4435 /* Probably barbarians in an old savegame; fix up */
4436 plr->server.got_first_city = TRUE;
4439 /* Load all cities of the player. */
4440 for (i = 0; i < ncities; i++) {
4441 char buf[32];
4442 struct city *pcity;
4444 fc_snprintf(buf, sizeof(buf), "player%d.c%d", plrno, i);
4446 /* Create a dummy city. */
4447 pcity = create_city_virtual(plr, NULL, buf);
4448 adv_city_alloc(pcity);
4449 if (!sg_load_player_city(loading, plr, pcity, buf)) {
4450 adv_city_free(pcity);
4451 destroy_city_virtual(pcity);
4452 sg_failure_ret(FALSE, "Error loading city %d of player %d.", i, plrno);
4455 identity_number_reserve(pcity->id);
4456 idex_register_city(&wld, pcity);
4458 /* Load the information about the nationality of citizens. This is done
4459 * here because the city sanity check called by citizens_update() requires
4460 * that the city is registered. */
4461 sg_load_player_city_citizens(loading, plr, pcity, buf);
4463 /* After everything is loaded, but before vision. */
4464 map_claim_ownership(city_tile(pcity), plr, city_tile(pcity), TRUE);
4466 /* adding the city contribution to fog-of-war */
4467 pcity->server.vision = vision_new(plr, city_tile(pcity));
4468 vision_reveal_tiles(pcity->server.vision, game.server.vision_reveal_tiles);
4469 city_refresh_vision(pcity);
4471 city_list_append(plr->cities, pcity);
4474 tasks_handled = FALSE;
4475 for (i = 0; !tasks_handled; i++) {
4476 int city_id;
4477 struct city *pcity = NULL;
4479 city_id = secfile_lookup_int_default(loading->file, -1, "player%d.task%d.city",
4480 plrno, i);
4482 if (city_id != -1) {
4483 pcity = player_city_by_number(plr, city_id);
4486 if (pcity != NULL) {
4487 const char *str;
4488 int nat_x, nat_y;
4489 struct worker_task *ptask = fc_malloc(sizeof(struct worker_task));
4491 nat_x = secfile_lookup_int_default(loading->file, -1, "player%d.task%d.x", plrno, i);
4492 nat_y = secfile_lookup_int_default(loading->file, -1, "player%d.task%d.y", plrno, i);
4494 ptask->ptile = native_pos_to_tile(&(wld.map), nat_x, nat_y);
4496 str = secfile_lookup_str(loading->file, "player%d.task%d.activity", plrno, i);
4497 ptask->act = unit_activity_by_name(str, fc_strcasecmp);
4499 sg_failure_ret(unit_activity_is_valid(ptask->act),
4500 "Unknown workertask activity %s", str);
4502 str = secfile_lookup_str(loading->file, "player%d.task%d.target", plrno, i);
4504 if (strcmp("-", str)) {
4505 ptask->tgt = extra_type_by_rule_name(str);
4507 sg_failure_ret(ptask->tgt != NULL,
4508 "Unknown workertask target %s", str);
4511 ptask->want = secfile_lookup_int_default(loading->file, 1,
4512 "player%d.task%d.want", plrno, i);
4514 worker_task_list_append(pcity->task_reqs, ptask);
4515 } else {
4516 tasks_handled = TRUE;
4521 /****************************************************************************
4522 Load data for one city. sg_save_player_city() is not defined.
4523 ****************************************************************************/
4524 static bool sg_load_player_city(struct loaddata *loading, struct player *plr,
4525 struct city *pcity, const char *citystr)
4527 struct player *past;
4528 const char *kind, *name, *str;
4529 int id, i, repair, sp_count = 0, workers = 0, value;
4530 int nat_x, nat_y;
4531 citizens size;
4532 const char *stylename;
4533 int partner = 1;
4535 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_x, "%s.x", citystr),
4536 FALSE, "%s", secfile_error());
4537 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_y, "%s.y", citystr),
4538 FALSE, "%s", secfile_error());
4539 pcity->tile = native_pos_to_tile(&(wld.map), nat_x, nat_y);
4540 sg_warn_ret_val(NULL != pcity->tile, FALSE,
4541 "%s has invalid center tile (%d, %d)",
4542 citystr, nat_x, nat_y);
4543 sg_warn_ret_val(NULL == tile_city(pcity->tile), FALSE,
4544 "%s duplicates city (%d, %d)", citystr, nat_x, nat_y);
4546 /* Instead of dying, use 'citystr' string for damaged name. */
4547 sz_strlcpy(pcity->name, secfile_lookup_str_default(loading->file, citystr,
4548 "%s.name", citystr));
4550 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->id, "%s.id",
4551 citystr), FALSE, "%s", secfile_error());
4553 id = secfile_lookup_int_default(loading->file, player_number(plr),
4554 "%s.original", citystr);
4555 past = player_by_number(id);
4556 if (NULL != past) {
4557 pcity->original = past;
4560 sg_warn_ret_val(secfile_lookup_int(loading->file, &value, "%s.size",
4561 citystr), FALSE, "%s", secfile_error());
4562 size = (citizens)value; /* set the correct type */
4563 sg_warn_ret_val(value == (int)size, FALSE,
4564 "Invalid city size: %d, set to %d", value, size);
4565 city_size_set(pcity, size);
4567 for (i = 0; i < loading->specialist.size; i++) {
4568 sg_warn_ret_val(secfile_lookup_int(loading->file, &value, "%s.nspe%d",
4569 citystr, i),
4570 FALSE, "%s", secfile_error());
4571 pcity->specialists[specialist_index(loading->specialist.order[i])]
4572 = (citizens)value;
4573 sp_count += value;
4576 for (i = 0; partner != 0; i++) {
4577 partner = secfile_lookup_int_default(loading->file, 0,
4578 "%s.traderoute%d", citystr, i);
4580 if (partner != 0) {
4581 struct trade_route *proute = fc_malloc(sizeof(struct trade_route));
4582 const char *dir;
4583 const char *good_str;
4585 /* Append to routes list immediately, so the pointer can be found for freeing
4586 * even if we abort */
4587 trade_route_list_append(pcity->routes, proute);
4589 proute->partner = partner;
4590 dir = secfile_lookup_str(loading->file, "%s.route_direction%d", citystr, i);
4591 sg_warn_ret_val(dir != NULL, FALSE,
4592 "No traderoute direction found for %s", citystr);
4593 proute->dir = route_direction_by_name(dir, fc_strcasecmp);
4594 sg_warn_ret_val(route_direction_is_valid(proute->dir), FALSE,
4595 "Illegal route direction %s", dir);
4596 good_str = secfile_lookup_str(loading->file, "%s.route_good%d", citystr, i);
4597 sg_warn_ret_val(dir != NULL, FALSE,
4598 "No good found for %s", citystr);
4599 proute->goods = goods_by_rule_name(good_str);
4600 sg_warn_ret_val(proute->goods != NULL, FALSE,
4601 "Illegal good %s", good_str);
4605 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->food_stock,
4606 "%s.food_stock", citystr),
4607 FALSE, "%s", secfile_error());
4608 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->shield_stock,
4609 "%s.shield_stock", citystr),
4610 FALSE, "%s", secfile_error());
4611 pcity->history =
4612 secfile_lookup_int_default(loading->file, 0, "%s.history", citystr);
4614 pcity->airlift =
4615 secfile_lookup_int_default(loading->file, 0, "%s.airlift", citystr);
4616 pcity->was_happy =
4617 secfile_lookup_bool_default(loading->file, FALSE, "%s.was_happy",
4618 citystr);
4620 pcity->turn_plague =
4621 secfile_lookup_int_default(loading->file, 0, "%s.turn_plague", citystr);
4623 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->anarchy,
4624 "%s.anarchy", citystr),
4625 FALSE, "%s", secfile_error());
4626 pcity->rapture =
4627 secfile_lookup_int_default(loading->file, 0, "%s.rapture", citystr);
4628 pcity->server.steal =
4629 secfile_lookup_int_default(loading->file, 0, "%s.steal", citystr);
4631 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->turn_founded,
4632 "%s.turn_founded", citystr),
4633 FALSE, "%s", secfile_error());
4634 sg_warn_ret_val(secfile_lookup_bool(loading->file, &pcity->did_buy, "%s.did_buy",
4635 citystr), FALSE, "%s", secfile_error());
4636 sg_warn_ret_val(secfile_lookup_bool(loading->file, &pcity->did_sell, "%s.did_sell",
4637 citystr), FALSE, "%s", secfile_error());
4639 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->turn_last_built,
4640 "%s.turn_last_built", citystr),
4641 FALSE, "%s", secfile_error());
4643 kind = secfile_lookup_str(loading->file, "%s.currently_building_kind",
4644 citystr);
4645 name = secfile_lookup_str(loading->file, "%s.currently_building_name",
4646 citystr);
4647 pcity->production = universal_by_rule_name(kind, name);
4648 sg_warn_ret_val(pcity->production.kind != universals_n_invalid(), FALSE,
4649 "%s.currently_building: unknown \"%s\" \"%s\".",
4650 citystr, kind, name);
4652 kind = secfile_lookup_str(loading->file, "%s.changed_from_kind",
4653 citystr);
4654 name = secfile_lookup_str(loading->file, "%s.changed_from_name",
4655 citystr);
4656 pcity->changed_from = universal_by_rule_name(kind, name);
4657 sg_warn_ret_val(pcity->changed_from.kind != universals_n_invalid(), FALSE,
4658 "%s.changed_from: unknown \"%s\" \"%s\".",
4659 citystr, kind, name);
4661 pcity->before_change_shields =
4662 secfile_lookup_int_default(loading->file, pcity->shield_stock,
4663 "%s.before_change_shields", citystr);
4664 pcity->caravan_shields =
4665 secfile_lookup_int_default(loading->file, 0,
4666 "%s.caravan_shields", citystr);
4667 pcity->disbanded_shields =
4668 secfile_lookup_int_default(loading->file, 0,
4669 "%s.disbanded_shields", citystr);
4670 pcity->last_turns_shield_surplus =
4671 secfile_lookup_int_default(loading->file, 0,
4672 "%s.last_turns_shield_surplus",
4673 citystr);
4675 stylename = secfile_lookup_str_default(loading->file, NULL,
4676 "%s.style", citystr);
4677 if (stylename != NULL) {
4678 pcity->style = city_style_by_rule_name(stylename);
4679 } else {
4680 pcity->style = 0;
4682 if (pcity->style < 0) {
4683 pcity->style = city_style(pcity);
4686 pcity->server.synced = FALSE; /* must re-sync with clients */
4688 /* Initialise list of city improvements. */
4689 for (i = 0; i < ARRAY_SIZE(pcity->built); i++) {
4690 pcity->built[i].turn = I_NEVER;
4693 /* Load city improvements. */
4694 str = secfile_lookup_str(loading->file, "%s.improvements", citystr);
4695 sg_warn_ret_val(str != NULL, FALSE, "%s", secfile_error());
4696 sg_warn_ret_val(strlen(str) == loading->improvement.size, FALSE,
4697 "Invalid length of '%s.improvements' (%lu ~= %lu).",
4698 citystr, (unsigned long) strlen(str),
4699 (unsigned long) loading->improvement.size);
4700 for (i = 0; i < loading->improvement.size; i++) {
4701 sg_warn_ret_val(str[i] == '1' || str[i] == '0', FALSE,
4702 "Undefined value '%c' within '%s.improvements'.",
4703 str[i], citystr)
4705 if (str[i] == '1') {
4706 struct impr_type *pimprove =
4707 improvement_by_rule_name(loading->improvement.order[i]);
4708 if (pimprove) {
4709 city_add_improvement(pcity, pimprove);
4714 sg_failure_ret_val(loading->worked_tiles != NULL, FALSE,
4715 "No worked tiles map defined.");
4717 city_freeze_workers(pcity);
4719 /* load new savegame with variable (squared) city radius and worked
4720 * tiles map */
4722 int radius_sq
4723 = secfile_lookup_int_default(loading->file, -1, "%s.city_radius_sq",
4724 citystr);
4725 city_map_radius_sq_set(pcity, radius_sq);
4727 city_tile_iterate(radius_sq, city_tile(pcity), ptile) {
4728 if (loading->worked_tiles[ptile->index] == pcity->id) {
4729 tile_set_worked(ptile, pcity);
4730 workers++;
4732 #ifdef FREECIV_DEBUG
4733 /* set this tile to unused; a check for not resetted tiles is
4734 * included in game_load_internal() */
4735 loading->worked_tiles[ptile->index] = -1;
4736 #endif /* FREECIV_DEBUG */
4738 } city_tile_iterate_end;
4740 if (tile_worked(city_tile(pcity)) != pcity) {
4741 struct city *pwork = tile_worked(city_tile(pcity));
4743 if (NULL != pwork) {
4744 log_sg("[%s] city center of '%s' (%d,%d) [%d] is worked by '%s' "
4745 "(%d,%d) [%d]; repairing ", citystr, city_name_get(pcity),
4746 TILE_XY(city_tile(pcity)), city_size_get(pcity), city_name_get(pwork),
4747 TILE_XY(city_tile(pwork)), city_size_get(pwork));
4749 tile_set_worked(city_tile(pcity), NULL); /* remove tile from pwork */
4750 pwork->specialists[DEFAULT_SPECIALIST]++;
4751 auto_arrange_workers(pwork);
4752 } else {
4753 log_sg("[%s] city center of '%s' (%d,%d) [%d] is empty; repairing ",
4754 citystr, city_name_get(pcity), TILE_XY(city_tile(pcity)),
4755 city_size_get(pcity));
4758 /* repair pcity */
4759 tile_set_worked(city_tile(pcity), pcity);
4760 city_repair_size(pcity, -1);
4763 repair = city_size_get(pcity) - sp_count - (workers - FREE_WORKED_TILES);
4764 if (0 != repair) {
4765 log_sg("[%s] size mismatch for '%s' (%d,%d): size [%d] != "
4766 "(workers [%d] - free worked tiles [%d]) + specialists [%d]",
4767 citystr, city_name_get(pcity), TILE_XY(city_tile(pcity)), city_size_get(pcity),
4768 workers, FREE_WORKED_TILES, sp_count);
4770 /* repair pcity */
4771 city_repair_size(pcity, repair);
4774 /* worklist_init() done in create_city_virtual() */
4775 worklist_load(loading->file, &pcity->worklist, "%s", citystr);
4777 /* Load city options. */
4778 BV_CLR_ALL(pcity->city_options);
4779 for (i = 0; i < CITYO_LAST; i++) {
4780 if (secfile_lookup_bool_default(loading->file, FALSE, "%s.option%d",
4781 citystr, i)) {
4782 BV_SET(pcity->city_options, i);
4786 CALL_FUNC_EACH_AI(city_load, loading->file, pcity, citystr);
4788 return TRUE;
4791 /****************************************************************************
4792 Load nationality data for one city.
4793 ****************************************************************************/
4794 static void sg_load_player_city_citizens(struct loaddata *loading,
4795 struct player *plr,
4796 struct city *pcity,
4797 const char *citystr)
4799 if (game.info.citizen_nationality) {
4800 citizens size;
4802 citizens_init(pcity);
4803 player_slots_iterate(pslot) {
4804 int nationality;
4806 nationality = secfile_lookup_int_default(loading->file, -1,
4807 "%s.citizen%d", citystr,
4808 player_slot_index(pslot));
4809 if (nationality > 0 && !player_slot_is_used(pslot)) {
4810 log_sg("Citizens of an invalid nation for %s (player slot %d)!",
4811 city_name_get(pcity), player_slot_index(pslot));
4812 continue;
4815 if (nationality != -1 && player_slot_is_used(pslot)) {
4816 sg_warn(nationality >= 0 && nationality <= MAX_CITY_SIZE,
4817 "Invalid value for citizens of player %d in %s: %d.",
4818 player_slot_index(pslot), city_name_get(pcity), nationality);
4819 citizens_nation_set(pcity, pslot, nationality);
4821 } player_slots_iterate_end;
4822 /* Sanity check. */
4823 size = citizens_count(pcity);
4824 if (size != city_size_get(pcity)) {
4825 if (size != 0) {
4826 /* size == 0 can be result from the fact that ruleset had no
4827 * nationality enabled at saving time, so no citizens at all
4828 * were saved. But something more serious must be going on if
4829 * citizens have been saved partially - if some of them are there. */
4830 log_sg("City size and number of citizens does not match in %s "
4831 "(%d != %d)! Repairing ...", city_name_get(pcity),
4832 city_size_get(pcity), size);
4834 citizens_update(pcity, NULL);
4839 /****************************************************************************
4840 Save cities data
4841 ****************************************************************************/
4842 static void sg_save_player_cities(struct savedata *saving,
4843 struct player *plr)
4845 int wlist_max_length = 0;
4846 int i = 0;
4847 int plrno = player_number(plr);
4848 bool nations[MAX_NUM_PLAYER_SLOTS];
4850 /* Check status and return if not OK (sg_success != TRUE). */
4851 sg_check_ret();
4853 secfile_insert_int(saving->file, city_list_size(plr->cities),
4854 "player%d.ncities", plrno);
4856 if (game.info.citizen_nationality) {
4857 /* Initialise the nation list for the citizens information. */
4858 player_slots_iterate(pslot) {
4859 nations[player_slot_index(pslot)] = FALSE;
4860 } player_slots_iterate_end;
4863 /* First determine lenght of longest worklist and the nations we have. */
4864 city_list_iterate(plr->cities, pcity) {
4865 /* Check the sanity of the city. */
4866 city_refresh(pcity);
4867 sanity_check_city(pcity);
4869 if (pcity->worklist.length > wlist_max_length) {
4870 wlist_max_length = pcity->worklist.length;
4873 if (game.info.citizen_nationality) {
4874 /* Find all nations of the citizens,*/
4875 players_iterate(pplayer) {
4876 if (!nations[player_index(pplayer)]
4877 && citizens_nation_get(pcity, pplayer->slot) != 0) {
4878 nations[player_index(pplayer)] = TRUE;
4880 } players_iterate_end;
4882 } city_list_iterate_end;
4884 city_list_iterate(plr->cities, pcity) {
4885 struct tile *pcenter = city_tile(pcity);
4886 char impr_buf[MAX_NUM_ITEMS + 1];
4887 char buf[32];
4888 int j, nat_x, nat_y;
4890 fc_snprintf(buf, sizeof(buf), "player%d.c%d", plrno, i);
4893 index_to_native_pos(&nat_x, &nat_y, tile_index(pcenter));
4894 secfile_insert_int(saving->file, nat_y, "%s.y", buf);
4895 secfile_insert_int(saving->file, nat_x, "%s.x", buf);
4897 secfile_insert_int(saving->file, pcity->id, "%s.id", buf);
4899 secfile_insert_int(saving->file, player_number(pcity->original),
4900 "%s.original", buf);
4901 secfile_insert_int(saving->file, city_size_get(pcity), "%s.size", buf);
4903 j = 0;
4904 specialist_type_iterate(sp) {
4905 secfile_insert_int(saving->file, pcity->specialists[sp], "%s.nspe%d",
4906 buf, j++);
4907 } specialist_type_iterate_end;
4909 j = 0;
4910 trade_routes_iterate(pcity, proute) {
4911 secfile_insert_int(saving->file, proute->partner, "%s.traderoute%d",
4912 buf, j);
4913 secfile_insert_str(saving->file, route_direction_name(proute->dir),
4914 "%s.route_direction%d", buf, j);
4915 secfile_insert_str(saving->file, goods_rule_name(proute->goods),
4916 "%s.route_good%d", buf, j);
4917 j++;
4918 } trade_routes_iterate_end;
4920 /* Save dummy values to keep tabular format happy */
4921 for (; j < MAX_TRADE_ROUTES; j++) {
4922 secfile_insert_int(saving->file, 0, "%s.traderoute%d", buf, j);
4923 secfile_insert_str(saving->file, route_direction_name(RDIR_BIDIRECTIONAL),
4924 "%s.route_direction%d", buf, j);
4925 secfile_insert_str(saving->file, goods_rule_name(goods_by_number(0)),
4926 "%s.route_good%d", buf, j);
4929 secfile_insert_int(saving->file, pcity->food_stock, "%s.food_stock",
4930 buf);
4931 secfile_insert_int(saving->file, pcity->shield_stock, "%s.shield_stock",
4932 buf);
4933 secfile_insert_int(saving->file, pcity->history, "%s.history",
4934 buf);
4936 secfile_insert_int(saving->file, pcity->airlift, "%s.airlift",
4937 buf);
4938 secfile_insert_bool(saving->file, pcity->was_happy, "%s.was_happy",
4939 buf);
4940 secfile_insert_int(saving->file, pcity->turn_plague, "%s.turn_plague",
4941 buf);
4943 secfile_insert_int(saving->file, pcity->anarchy, "%s.anarchy", buf);
4944 secfile_insert_int(saving->file, pcity->rapture, "%s.rapture", buf);
4945 secfile_insert_int(saving->file, pcity->server.steal, "%s.steal", buf);
4946 secfile_insert_int(saving->file, pcity->turn_founded, "%s.turn_founded",
4947 buf);
4948 secfile_insert_bool(saving->file, pcity->did_buy, "%s.did_buy", buf);
4949 secfile_insert_bool(saving->file, pcity->did_sell, "%s.did_sell", buf);
4950 secfile_insert_int(saving->file, pcity->turn_last_built,
4951 "%s.turn_last_built", buf);
4953 /* for visual debugging, variable length strings together here */
4954 secfile_insert_str(saving->file, city_name_get(pcity), "%s.name", buf);
4956 secfile_insert_str(saving->file, universal_type_rule_name(&pcity->production),
4957 "%s.currently_building_kind", buf);
4958 secfile_insert_str(saving->file, universal_rule_name(&pcity->production),
4959 "%s.currently_building_name", buf);
4961 secfile_insert_str(saving->file, universal_type_rule_name(&pcity->changed_from),
4962 "%s.changed_from_kind", buf);
4963 secfile_insert_str(saving->file, universal_rule_name(&pcity->changed_from),
4964 "%s.changed_from_name", buf);
4966 secfile_insert_int(saving->file, pcity->before_change_shields,
4967 "%s.before_change_shields", buf);
4968 secfile_insert_int(saving->file, pcity->caravan_shields,
4969 "%s.caravan_shields", buf);
4970 secfile_insert_int(saving->file, pcity->disbanded_shields,
4971 "%s.disbanded_shields", buf);
4972 secfile_insert_int(saving->file, pcity->last_turns_shield_surplus,
4973 "%s.last_turns_shield_surplus", buf);
4975 secfile_insert_str(saving->file, city_style_rule_name(pcity->style),
4976 "%s.style", buf);
4978 /* Save the squared city radius and all tiles within the corresponing
4979 * city map. */
4980 secfile_insert_int(saving->file, pcity->city_radius_sq,
4981 "player%d.c%d.city_radius_sq", plrno, i);
4982 /* The tiles worked by the city are saved using the main map.
4983 * See also sg_save_map_worked(). */
4985 /* Save improvement list as bytevector. Note that improvement order
4986 * is saved in savefile.improvement_order. */
4987 improvement_iterate(pimprove) {
4988 impr_buf[improvement_index(pimprove)]
4989 = (pcity->built[improvement_index(pimprove)].turn <= I_NEVER) ? '0'
4990 : '1';
4991 } improvement_iterate_end;
4992 impr_buf[improvement_count()] = '\0';
4993 sg_failure_ret(strlen(impr_buf) < sizeof(impr_buf),
4994 "Invalid size of the improvement vector (%s.improvements: "
4995 "%lu < %lu).", buf, (long unsigned int) strlen(impr_buf),
4996 (long unsigned int) sizeof(impr_buf));
4997 secfile_insert_str(saving->file, impr_buf, "%s.improvements", buf);
4999 worklist_save(saving->file, &pcity->worklist, wlist_max_length, "%s",
5000 buf);
5002 for (j = 0; j < CITYO_LAST; j++) {
5003 secfile_insert_bool(saving->file, BV_ISSET(pcity->city_options, j),
5004 "%s.option%d", buf, j);
5007 CALL_FUNC_EACH_AI(city_save, saving->file, pcity, buf);
5009 if (game.info.citizen_nationality) {
5010 /* Save nationality of the citizens,*/
5011 players_iterate(pplayer) {
5012 if (nations[player_index(pplayer)]) {
5013 secfile_insert_int(saving->file,
5014 citizens_nation_get(pcity, pplayer->slot),
5015 "%s.citizen%d", buf, player_index(pplayer));
5017 } players_iterate_end;
5020 i++;
5021 } city_list_iterate_end;
5023 i = 0;
5024 city_list_iterate(plr->cities, pcity) {
5025 worker_task_list_iterate(pcity->task_reqs, ptask) {
5026 int nat_x, nat_y;
5028 index_to_native_pos(&nat_x, &nat_y, tile_index(ptask->ptile));
5029 secfile_insert_int(saving->file, pcity->id, "player%d.task%d.city",
5030 plrno, i);
5031 secfile_insert_int(saving->file, nat_y, "player%d.task%d.y", plrno, i);
5032 secfile_insert_int(saving->file, nat_x, "player%d.task%d.x", plrno, i);
5033 secfile_insert_str(saving->file, unit_activity_name(ptask->act),
5034 "player%d.task%d.activity",
5035 plrno, i);
5036 if (ptask->tgt != NULL) {
5037 secfile_insert_str(saving->file, extra_rule_name(ptask->tgt),
5038 "player%d.task%d.target",
5039 plrno, i);
5040 } else {
5041 secfile_insert_str(saving->file, "-",
5042 "player%d.task%d.target",
5043 plrno, i);
5045 secfile_insert_int(saving->file, ptask->want, "player%d.task%d.want", plrno, i);
5047 i++;
5048 } worker_task_list_iterate_end;
5049 } city_list_iterate_end;
5052 /****************************************************************************
5053 Load unit data
5054 ****************************************************************************/
5055 static void sg_load_player_units(struct loaddata *loading,
5056 struct player *plr)
5058 int nunits, i, plrno = player_number(plr);
5060 /* Check status and return if not OK (sg_success != TRUE). */
5061 sg_check_ret();
5063 sg_failure_ret(secfile_lookup_int(loading->file, &nunits,
5064 "player%d.nunits", plrno),
5065 "%s", secfile_error());
5066 if (!plr->is_alive && nunits > 0) {
5067 log_sg("'player%d.nunits' = %d for dead player!", plrno, nunits);
5068 nunits = 0; /* Some old savegames may be buggy. */
5071 for (i = 0; i < nunits; i++) {
5072 struct unit *punit;
5073 struct city *pcity;
5074 const char *name;
5075 char buf[32];
5076 struct unit_type *type;
5077 struct tile *ptile;
5079 fc_snprintf(buf, sizeof(buf), "player%d.u%d", plrno, i);
5081 name = secfile_lookup_str(loading->file, "%s.type_by_name", buf);
5082 type = unit_type_by_rule_name(name);
5083 sg_failure_ret(type != NULL, "%s: unknown unit type \"%s\".", buf, name);
5085 /* Create a dummy unit. */
5086 punit = unit_virtual_create(plr, NULL, type, 0);
5087 if (!sg_load_player_unit(loading, plr, punit, buf)) {
5088 unit_virtual_destroy(punit);
5089 sg_failure_ret(FALSE, "Error loading unit %d of player %d.", i, plrno);
5092 identity_number_reserve(punit->id);
5093 idex_register_unit(&wld, punit);
5095 if ((pcity = game_city_by_number(punit->homecity))) {
5096 unit_list_prepend(pcity->units_supported, punit);
5097 } else if (punit->homecity > IDENTITY_NUMBER_ZERO) {
5098 log_sg("%s: bad home city %d.", buf, punit->homecity);
5099 punit->homecity = IDENTITY_NUMBER_ZERO;
5102 ptile = unit_tile(punit);
5104 /* allocate the unit's contribution to fog of war */
5105 punit->server.vision = vision_new(unit_owner(punit), ptile);
5106 unit_refresh_vision(punit);
5107 /* NOTE: There used to be some map_set_known calls here. These were
5108 * unneeded since unfogging the tile when the unit sees it will
5109 * automatically reveal that tile. */
5111 unit_list_append(plr->units, punit);
5112 unit_list_prepend(unit_tile(punit)->units, punit);
5114 /* Claim ownership of fortress? */
5115 if ((extra_owner(ptile) == NULL
5116 || pplayers_at_war(extra_owner(ptile), plr))
5117 && tile_has_claimable_base(ptile, unit_type_get(punit))) {
5118 tile_claim_bases(ptile, plr);
5123 /****************************************************************************
5124 Load one unit. sg_save_player_unit() is not defined.
5125 ****************************************************************************/
5126 static bool sg_load_player_unit(struct loaddata *loading,
5127 struct player *plr, struct unit *punit,
5128 const char *unitstr)
5130 int j;
5131 enum unit_activity activity;
5132 int nat_x, nat_y;
5133 struct extra_type *pextra = NULL;
5134 struct tile *ptile;
5135 int extra_id;
5136 int ei;
5137 const char *facing_str;
5138 enum tile_special_type cfspe;
5139 int natnbr;
5140 int unconverted;
5141 const char *str;
5143 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->id, "%s.id",
5144 unitstr), FALSE, "%s", secfile_error());
5145 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_x, "%s.x", unitstr),
5146 FALSE, "%s", secfile_error());
5147 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_y, "%s.y", unitstr),
5148 FALSE, "%s", secfile_error());
5150 ptile = native_pos_to_tile(&(wld.map), nat_x, nat_y);
5151 sg_warn_ret_val(NULL != ptile, FALSE, "%s invalid tile (%d, %d)",
5152 unitstr, nat_x, nat_y);
5153 unit_tile_set(punit, ptile);
5155 facing_str
5156 = secfile_lookup_str_default(loading->file, "x",
5157 "%s.facing", unitstr);
5158 if (facing_str[0] != 'x') {
5159 /* We don't touch punit->facing if savegame does not contain that
5160 * information. Initial orientation set by unit_virtual_create()
5161 * is as good as any. */
5162 enum direction8 facing = char2dir(facing_str[0]);
5164 if (direction8_is_valid(facing)) {
5165 punit->facing = facing;
5166 } else {
5167 log_error("Illegal unit orientation '%s'", facing_str);
5171 /* If savegame has unit nationality, it doesn't hurt to
5172 * internally set it even if nationality rules are disabled. */
5173 natnbr = secfile_lookup_int_default(loading->file,
5174 player_number(plr),
5175 "%s.nationality", unitstr);
5177 punit->nationality = player_by_number(natnbr);
5178 if (punit->nationality == NULL) {
5179 punit->nationality = plr;
5182 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->homecity,
5183 "%s.homecity", unitstr), FALSE,
5184 "%s", secfile_error());
5185 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->moves_left,
5186 "%s.moves", unitstr), FALSE,
5187 "%s", secfile_error());
5188 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->fuel,
5189 "%s.fuel", unitstr), FALSE,
5190 "%s", secfile_error());
5191 sg_warn_ret_val(secfile_lookup_int(loading->file, &ei,
5192 "%s.activity", unitstr), FALSE,
5193 "%s", secfile_error());
5194 activity = unit_activity_by_name(loading->activities.order[ei],
5195 fc_strcasecmp);
5197 punit->server.birth_turn
5198 = secfile_lookup_int_default(loading->file, game.info.turn,
5199 "%s.born", unitstr);
5201 if (activity == ACTIVITY_PATROL_UNUSED) {
5202 /* Previously ACTIVITY_PATROL and ACTIVITY_GOTO were used for
5203 * client-side goto. Now client-side goto is handled by setting
5204 * a special flag, and units with orders generally have ACTIVITY_IDLE.
5205 * Old orders are lost. Old client-side goto units will still have
5206 * ACTIVITY_GOTO and will goto the correct position via server goto.
5207 * Old client-side patrol units lose their patrol routes and are put
5208 * into idle mode. */
5209 activity = ACTIVITY_IDLE;
5212 extra_id = secfile_lookup_int_default(loading->file, -2,
5213 "%s.activity_tgt", unitstr);
5215 if (extra_id != -2) {
5216 if (extra_id >= 0 && extra_id < loading->extra.size) {
5217 pextra = loading->extra.order[extra_id];
5218 set_unit_activity_targeted(punit, activity, pextra);
5219 } else if (activity == ACTIVITY_IRRIGATE) {
5220 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
5221 EC_IRRIGATION,
5222 unit_owner(punit),
5223 punit);
5224 if (tgt != NULL) {
5225 set_unit_activity_targeted(punit, ACTIVITY_IRRIGATE, tgt);
5226 } else {
5227 set_unit_activity_targeted(punit, ACTIVITY_IRRIGATE, NULL);
5229 } else if (activity == ACTIVITY_MINE) {
5230 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
5231 EC_MINE,
5232 unit_owner(punit),
5233 punit);
5234 if (tgt != NULL) {
5235 set_unit_activity_targeted(punit, ACTIVITY_MINE, tgt);
5236 } else {
5237 set_unit_activity_targeted(punit, ACTIVITY_MINE, NULL);
5239 } else {
5240 set_unit_activity(punit, activity);
5242 } else {
5243 set_unit_activity_targeted(punit, activity, NULL);
5244 } /* activity_tgt == NULL */
5246 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->activity_count,
5247 "%s.activity_count", unitstr), FALSE,
5248 "%s", secfile_error());
5250 punit->changed_from =
5251 secfile_lookup_int_default(loading->file, ACTIVITY_IDLE,
5252 "%s.changed_from", unitstr);
5254 extra_id = secfile_lookup_int_default(loading->file, -2,
5255 "%s.changed_from_tgt", unitstr);
5257 if (extra_id != -2) {
5258 if (extra_id >= 0 && extra_id < loading->extra.size) {
5259 punit->changed_from_target = loading->extra.order[extra_id];
5260 } else {
5261 punit->changed_from_target = NULL;
5263 } else {
5264 /* extra_id == -2 -> changed_from_tgt not set */
5266 cfspe =
5267 secfile_lookup_int_default(loading->file, S_LAST,
5268 "%s.changed_from_target", unitstr);
5270 if (cfspe != S_LAST) {
5271 punit->changed_from_target = special_extra_get(cfspe);
5272 } else {
5273 punit->changed_from_target = NULL;
5276 if (punit->changed_from == ACTIVITY_IRRIGATE) {
5277 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
5278 EC_IRRIGATION,
5279 unit_owner(punit),
5280 punit);
5281 if (tgt != NULL) {
5282 punit->changed_from_target = tgt;
5283 } else {
5284 punit->changed_from_target = NULL;
5286 } else if (punit->changed_from == ACTIVITY_MINE) {
5287 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
5288 EC_MINE,
5289 unit_owner(punit),
5290 punit);
5291 if (tgt != NULL) {
5292 punit->changed_from_target = tgt;
5293 } else {
5294 punit->changed_from_target = NULL;
5296 } else if (punit->changed_from == ACTIVITY_POLLUTION) {
5297 struct extra_type *tgt = prev_extra_in_tile(unit_tile(punit),
5298 ERM_CLEANPOLLUTION,
5299 unit_owner(punit),
5300 punit);
5301 if (tgt != NULL) {
5302 punit->changed_from_target = tgt;
5303 } else {
5304 punit->changed_from_target = NULL;
5306 } else if (punit->changed_from == ACTIVITY_FALLOUT) {
5307 struct extra_type *tgt = prev_extra_in_tile(unit_tile(punit),
5308 ERM_CLEANFALLOUT,
5309 unit_owner(punit),
5310 punit);
5311 if (tgt != NULL) {
5312 punit->changed_from_target = tgt;
5313 } else {
5314 punit->changed_from_target = NULL;
5319 punit->changed_from_count =
5320 secfile_lookup_int_default(loading->file, 0,
5321 "%s.changed_from_count", unitstr);
5323 /* Special case: for a long time, we accidentally incremented
5324 * activity_count while a unit was sentried, so it could increase
5325 * without bound (bug #20641) and be saved in old savefiles.
5326 * We zero it to prevent potential trouble overflowing the range
5327 * in network packets, etc. */
5328 if (activity == ACTIVITY_SENTRY) {
5329 punit->activity_count = 0;
5331 if (punit->changed_from == ACTIVITY_SENTRY) {
5332 punit->changed_from_count = 0;
5335 punit->veteran
5336 = secfile_lookup_int_default(loading->file, 0, "%s.veteran", unitstr);
5338 /* Protect against change in veteran system in ruleset */
5339 const int levels = utype_veteran_levels(unit_type_get(punit));
5341 if (punit->veteran >= levels) {
5342 fc_assert(levels >= 1);
5343 punit->veteran = levels - 1;
5346 punit->done_moving
5347 = secfile_lookup_bool_default(loading->file, (punit->moves_left == 0),
5348 "%s.done_moving", unitstr);
5349 punit->battlegroup
5350 = secfile_lookup_int_default(loading->file, BATTLEGROUP_NONE,
5351 "%s.battlegroup", unitstr);
5353 if (secfile_lookup_bool_default(loading->file, FALSE,
5354 "%s.go", unitstr)) {
5355 int gnat_x, gnat_y;
5357 sg_warn_ret_val(secfile_lookup_int(loading->file, &gnat_x,
5358 "%s.goto_x", unitstr), FALSE,
5359 "%s", secfile_error());
5360 sg_warn_ret_val(secfile_lookup_int(loading->file, &gnat_y,
5361 "%s.goto_y", unitstr), FALSE,
5362 "%s", secfile_error());
5364 punit->goto_tile = native_pos_to_tile(&(wld.map), gnat_x, gnat_y);
5365 } else {
5366 punit->goto_tile = NULL;
5368 /* These variables are not used but needed for saving the unit table.
5369 * Load them to prevent unused variables errors. */
5370 (void) secfile_entry_lookup(loading->file, "%s.goto_x", unitstr);
5371 (void) secfile_entry_lookup(loading->file, "%s.goto_y", unitstr);
5374 /* Load AI data of the unit. */
5375 CALL_FUNC_EACH_AI(unit_load, loading->file, punit, unitstr);
5377 sg_warn_ret_val(secfile_lookup_bool(loading->file,
5378 &punit->ai_controlled,
5379 "%s.ai", unitstr), FALSE,
5380 "%s", secfile_error());
5381 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->hp,
5382 "%s.hp", unitstr), FALSE,
5383 "%s", secfile_error());
5385 punit->server.ord_map
5386 = secfile_lookup_int_default(loading->file, 0, "%s.ord_map", unitstr);
5387 punit->server.ord_city
5388 = secfile_lookup_int_default(loading->file, 0, "%s.ord_city", unitstr);
5389 punit->moved
5390 = secfile_lookup_bool_default(loading->file, FALSE, "%s.moved", unitstr);
5391 punit->paradropped
5392 = secfile_lookup_bool_default(loading->file, FALSE,
5393 "%s.paradropped", unitstr);
5394 str = secfile_lookup_str_default(loading->file, "", "%s.carrying", unitstr);
5395 if (str[0] != '\0') {
5396 punit->carrying = goods_by_rule_name(str);
5399 /* The transport status (punit->transported_by) is loaded in
5400 * sg_player_units_transport(). */
5402 /* Initialize upkeep values: these are hopefully initialized
5403 * elsewhere before use (specifically, in city_support(); but
5404 * fixme: check whether always correctly initialized?).
5405 * Below is mainly for units which don't have homecity --
5406 * otherwise these don't get initialized (and AI calculations
5407 * etc may use junk values). */
5408 output_type_iterate(o) {
5409 punit->upkeep[o] = utype_upkeep_cost(unit_type_get(punit), plr, o);
5410 } output_type_iterate_end;
5412 sg_warn_ret_val(secfile_lookup_int(loading->file, &unconverted,
5413 "%s.action_decision", unitstr),
5414 FALSE, "%s", secfile_error());
5416 if (unconverted >= 0 && unconverted < loading->act_dec.size) {
5417 /* Look up what action decision want the unconverted number
5418 * represents. */
5419 punit->action_decision_want = loading->act_dec.order[unconverted];
5420 } else {
5421 log_sg("Invalid action decision want for unit %d", punit->id);
5423 punit->action_decision_want = ACT_DEC_NOTHING;
5426 if (punit->action_decision_want != ACT_DEC_NOTHING) {
5427 /* Load the tile to act against. */
5428 int adwt_x, adwt_y;
5430 if (secfile_lookup_int(loading->file, &adwt_x,
5431 "%s.action_decision_tile_x", unitstr)
5432 && secfile_lookup_int(loading->file, &adwt_y,
5433 "%s.action_decision_tile_y", unitstr)) {
5434 punit->action_decision_tile = native_pos_to_tile(&(wld.map),
5435 adwt_x, adwt_y);
5436 } else {
5437 punit->action_decision_want = ACT_DEC_NOTHING;
5438 punit->action_decision_tile = NULL;
5439 log_sg("Bad action_decision_tile for unit %d", punit->id);
5441 } else {
5442 (void) secfile_entry_lookup(loading->file, "%s.action_decision_tile_x", unitstr);
5443 (void) secfile_entry_lookup(loading->file, "%s.action_decision_tile_y", unitstr);
5444 punit->action_decision_tile = NULL;
5447 punit->stay = secfile_lookup_bool_default(loading->file, FALSE, "%s.stay", unitstr);
5449 /* load the unit orders */
5451 int len = secfile_lookup_int_default(loading->file, 0,
5452 "%s.orders_length", unitstr);
5453 if (len > 0) {
5454 const char *orders_unitstr, *dir_unitstr, *act_unitstr;
5455 const char *action_unitstr;
5457 punit->orders.list = fc_malloc(len * sizeof(*(punit->orders.list)));
5458 punit->orders.length = len;
5459 punit->orders.index
5460 = secfile_lookup_int_default(loading->file, 0,
5461 "%s.orders_index", unitstr);
5462 punit->orders.repeat
5463 = secfile_lookup_bool_default(loading->file, FALSE,
5464 "%s.orders_repeat", unitstr);
5465 punit->orders.vigilant
5466 = secfile_lookup_bool_default(loading->file, FALSE,
5467 "%s.orders_vigilant", unitstr);
5469 orders_unitstr
5470 = secfile_lookup_str_default(loading->file, "",
5471 "%s.orders_list", unitstr);
5472 dir_unitstr
5473 = secfile_lookup_str_default(loading->file, "",
5474 "%s.dir_list", unitstr);
5475 act_unitstr
5476 = secfile_lookup_str_default(loading->file, "",
5477 "%s.activity_list", unitstr);
5478 action_unitstr
5479 = secfile_lookup_str_default(loading->file, "",
5480 "%s.action_list", unitstr);
5482 punit->has_orders = TRUE;
5483 for (j = 0; j < len; j++) {
5484 struct unit_order *order = &punit->orders.list[j];
5485 int order_tgt;
5487 if (orders_unitstr[j] == '\0' || dir_unitstr[j] == '\0'
5488 #ifndef FREECIV_DEV_SAVE_COMPAT_3_0
5489 || action_unitstr[j] == '\0'
5490 #endif /* FREECIV_DEV_SAVE_COMPAT_3_0 */
5491 || act_unitstr[j] == '\0') {
5492 log_sg("Invalid unit orders.");
5493 free_unit_orders(punit);
5494 break;
5496 order->order = char2order(orders_unitstr[j]);
5497 order->dir = char2dir(dir_unitstr[j]);
5498 order->activity = char2activity(act_unitstr[j]);
5500 if (
5501 #ifdef FREECIV_DEV_SAVE_COMPAT_3_0
5502 action_unitstr[0] == '\0'
5504 #endif /* FREECIV_DEV_SAVE_COMPAT_3_0 */
5505 action_unitstr[j] == '?') {
5506 order->action = ACTION_NONE;
5507 } else {
5508 unconverted = char2num(action_unitstr[j]);
5510 if (unconverted >= 0 && unconverted < loading->action.size) {
5511 /* Look up what action id the unconverted number represents. */
5512 order->action = loading->action.order[unconverted];
5513 } else {
5514 log_sg("Invalid action id in order for unit %d", punit->id);
5516 order->action = ACTION_NONE;
5520 #ifdef FREECIV_DEV_SAVE_COMPAT_3_0
5521 if (order->order != ORDER_PERFORM_ACTION
5522 && order->action == ACTION_NONE) {
5523 /* This order may have been replaced by the perform action
5524 * order */
5526 /* See if a corresponding action exists. */
5527 order->action = sg_order_to_action(order->order, punit,
5528 punit->goto_tile);
5530 if (order->action != ACTION_NONE) {
5531 /* The order should be upgraded. */
5532 order->order = ORDER_PERFORM_ACTION;
5535 #endif /* FREECIV_DEV_SAVE_COMPAT_3_0 */
5537 if (order->order == ORDER_LAST
5538 || (order->order == ORDER_MOVE && !direction8_is_valid(order->dir))
5539 || (order->order == ORDER_ACTION_MOVE
5540 && !direction8_is_valid(order->dir))
5541 || (order->order == ORDER_PERFORM_ACTION
5542 && !action_id_exists(order->action))
5543 || (order->order == ORDER_ACTIVITY
5544 && order->activity == ACTIVITY_LAST)) {
5545 /* An invalid order. Just drop the orders for this unit. */
5546 free(punit->orders.list);
5547 punit->orders.list = NULL;
5548 punit->has_orders = FALSE;
5549 break;
5552 order_tgt = secfile_lookup_int_default(loading->file, -1,
5553 "%s.tgt_vec,%d",
5554 unitstr, j);
5556 if (order->order == ORDER_PERFORM_ACTION) {
5557 switch ((enum gen_action)order->action) {
5558 case ACTION_SPY_TARGETED_SABOTAGE_CITY:
5559 /* Sabotage target is production (-1) or a building. */
5560 if (!(order_tgt - 1 == -1
5561 || improvement_by_number(order_tgt - 1))) {
5562 /* Sabotage target is invalid. */
5563 log_sg("Cannot find building %d for %s to sabotage",
5564 order_tgt, unit_rule_name(punit));
5565 order->target = EXTRA_NONE;
5566 } else {
5567 order->target = order_tgt;
5569 break;
5570 case ACTION_SPY_TARGETED_STEAL_TECH:
5571 if (order_tgt == A_NONE
5572 || (!valid_advance_by_number(order_tgt)
5573 && order_tgt != A_FUTURE)) {
5574 /* Target tech is invalid. */
5575 log_sg("Cannot find tech %d for %s to steal",
5576 order_tgt, unit_rule_name(punit));
5577 order->target = EXTRA_NONE;
5578 } else {
5579 order->target = order_tgt;
5581 break;
5582 case ACTION_ESTABLISH_EMBASSY:
5583 case ACTION_ESTABLISH_EMBASSY_STAY:
5584 case ACTION_SPY_INVESTIGATE_CITY:
5585 case ACTION_INV_CITY_SPEND:
5586 case ACTION_SPY_POISON:
5587 case ACTION_SPY_STEAL_GOLD:
5588 case ACTION_SPY_SABOTAGE_CITY:
5589 case ACTION_SPY_STEAL_TECH:
5590 case ACTION_SPY_INCITE_CITY:
5591 case ACTION_SPY_INCITE_CITY_ESC:
5592 case ACTION_TRADE_ROUTE:
5593 case ACTION_MARKETPLACE:
5594 case ACTION_HELP_WONDER:
5595 case ACTION_SPY_BRIBE_UNIT:
5596 case ACTION_SPY_SABOTAGE_UNIT:
5597 case ACTION_CAPTURE_UNITS:
5598 case ACTION_FOUND_CITY:
5599 case ACTION_JOIN_CITY:
5600 case ACTION_STEAL_MAPS:
5601 case ACTION_BOMBARD:
5602 case ACTION_SPY_NUKE:
5603 case ACTION_SPY_NUKE_ESC:
5604 case ACTION_NUKE:
5605 case ACTION_DESTROY_CITY:
5606 case ACTION_EXPEL_UNIT:
5607 case ACTION_RECYCLE_UNIT:
5608 case ACTION_DISBAND_UNIT:
5609 case ACTION_HOME_CITY:
5610 case ACTION_UPGRADE_UNIT:
5611 case ACTION_PARADROP:
5612 case ACTION_AIRLIFT:
5613 case ACTION_ATTACK:
5614 case ACTION_CONQUER_CITY:
5615 case ACTION_HEAL_UNIT:
5616 case ACTION_COUNT:
5617 /* Target in order unsupported. */
5619 /* Target shouldn't be specified yet. */
5620 fc_assert_msg(order_tgt == -1,
5621 "Specified target for action %d unsupported.",
5622 order->action);
5624 order->target = EXTRA_NONE;
5626 break;
5628 } else {
5629 /* Assume that this is an extra */
5630 extra_id = order_tgt;
5632 if (extra_id < 0 || extra_id >= loading->extra.size) {
5633 if (order_tgt != EXTRA_NONE) {
5634 log_sg("Cannot find extra %d for %s to build",
5635 extra_id, unit_rule_name(punit));
5638 order->target = EXTRA_NONE;
5639 } else {
5640 order->target = extra_id;
5644 } else {
5645 punit->has_orders = FALSE;
5646 punit->orders.list = NULL;
5648 (void) secfile_entry_lookup(loading->file, "%s.orders_index", unitstr);
5649 (void) secfile_entry_lookup(loading->file, "%s.orders_repeat", unitstr);
5650 (void) secfile_entry_lookup(loading->file, "%s.orders_vigilant", unitstr);
5651 (void) secfile_entry_lookup(loading->file, "%s.orders_list", unitstr);
5652 (void) secfile_entry_lookup(loading->file, "%s.dir_list", unitstr);
5653 (void) secfile_entry_lookup(loading->file, "%s.activity_list", unitstr);
5654 (void) secfile_entry_lookup(loading->file, "%s.tgt_list", unitstr);
5658 return TRUE;
5661 /*****************************************************************************
5662 Load the transport status of all units. This is seperated from the other
5663 code as all units must be known.
5664 *****************************************************************************/
5665 static void sg_load_player_units_transport(struct loaddata *loading,
5666 struct player *plr)
5668 int nunits, i, plrno = player_number(plr);
5670 /* Check status and return if not OK (sg_success != TRUE). */
5671 sg_check_ret();
5673 /* Recheck the number of units for the player. This is a copied from
5674 * sg_load_player_units(). */
5675 sg_failure_ret(secfile_lookup_int(loading->file, &nunits,
5676 "player%d.nunits", plrno),
5677 "%s", secfile_error());
5678 if (!plr->is_alive && nunits > 0) {
5679 log_sg("'player%d.nunits' = %d for dead player!", plrno, nunits);
5680 nunits = 0; /* Some old savegames may be buggy. */
5683 for (i = 0; i < nunits; i++) {
5684 int id_unit, id_trans;
5685 struct unit *punit, *ptrans;
5687 id_unit = secfile_lookup_int_default(loading->file, -1,
5688 "player%d.u%d.id",
5689 plrno, i);
5690 punit = player_unit_by_number(plr, id_unit);
5691 fc_assert_action(punit != NULL, continue);
5693 id_trans = secfile_lookup_int_default(loading->file, -1,
5694 "player%d.u%d.transported_by",
5695 plrno, i);
5696 if (id_trans == -1) {
5697 /* Not transported. */
5698 continue;
5701 ptrans = game_unit_by_number(id_trans);
5702 fc_assert_action(id_trans == -1 || ptrans != NULL, continue);
5704 if (ptrans) {
5705 bool load_success = unit_transport_load(punit, ptrans, TRUE);
5707 fc_assert_action(load_success == TRUE, continue);
5712 /****************************************************************************
5713 Save unit data
5714 ****************************************************************************/
5715 static void sg_save_player_units(struct savedata *saving,
5716 struct player *plr)
5718 int i = 0;
5719 int longest_order = 0;
5721 /* Check status and return if not OK (sg_success != TRUE). */
5722 sg_check_ret();
5724 secfile_insert_int(saving->file, unit_list_size(plr->units),
5725 "player%d.nunits", player_number(plr));
5727 /* Find the longest unit order so different order length won't break
5728 * storing units in the tabular format. */
5729 unit_list_iterate(plr->units, punit) {
5730 if (punit->has_orders) {
5731 if (longest_order < punit->orders.length) {
5732 longest_order = punit->orders.length;
5735 } unit_list_iterate_end;
5737 unit_list_iterate(plr->units, punit) {
5738 char buf[32];
5739 char dirbuf[2] = " ";
5740 int nat_x, nat_y;
5741 int last_order, j;
5743 fc_snprintf(buf, sizeof(buf), "player%d.u%d", player_number(plr), i);
5744 dirbuf[0] = dir2char(punit->facing);
5745 secfile_insert_int(saving->file, punit->id, "%s.id", buf);
5747 index_to_native_pos(&nat_x, &nat_y, tile_index(unit_tile(punit)));
5748 secfile_insert_int(saving->file, nat_x, "%s.x", buf);
5749 secfile_insert_int(saving->file, nat_y, "%s.y", buf);
5751 secfile_insert_str(saving->file, dirbuf, "%s.facing", buf);
5752 if (game.info.citizen_nationality) {
5753 secfile_insert_int(saving->file, player_number(unit_nationality(punit)),
5754 "%s.nationality", buf);
5756 secfile_insert_int(saving->file, punit->veteran, "%s.veteran", buf);
5757 secfile_insert_int(saving->file, punit->hp, "%s.hp", buf);
5758 secfile_insert_int(saving->file, punit->homecity, "%s.homecity", buf);
5759 secfile_insert_str(saving->file, unit_rule_name(punit),
5760 "%s.type_by_name", buf);
5762 secfile_insert_int(saving->file, punit->activity, "%s.activity", buf);
5763 secfile_insert_int(saving->file, punit->activity_count,
5764 "%s.activity_count", buf);
5765 if (punit->activity_target == NULL) {
5766 secfile_insert_int(saving->file, -1, "%s.activity_tgt", buf);
5767 } else {
5768 secfile_insert_int(saving->file, extra_index(punit->activity_target),
5769 "%s.activity_tgt", buf);
5772 secfile_insert_int(saving->file, punit->changed_from,
5773 "%s.changed_from", buf);
5774 secfile_insert_int(saving->file, punit->changed_from_count,
5775 "%s.changed_from_count", buf);
5776 if (punit->changed_from_target == NULL) {
5777 secfile_insert_int(saving->file, -1, "%s.changed_from_tgt", buf);
5778 } else {
5779 secfile_insert_int(saving->file, extra_index(punit->changed_from_target),
5780 "%s.changed_from_tgt", buf);
5783 secfile_insert_bool(saving->file, punit->done_moving,
5784 "%s.done_moving", buf);
5785 secfile_insert_int(saving->file, punit->moves_left, "%s.moves", buf);
5786 secfile_insert_int(saving->file, punit->fuel, "%s.fuel", buf);
5787 secfile_insert_int(saving->file, punit->server.birth_turn,
5788 "%s.born", buf);
5789 secfile_insert_int(saving->file, punit->battlegroup,
5790 "%s.battlegroup", buf);
5792 if (punit->goto_tile) {
5793 index_to_native_pos(&nat_x, &nat_y, tile_index(punit->goto_tile));
5794 secfile_insert_bool(saving->file, TRUE, "%s.go", buf);
5795 secfile_insert_int(saving->file, nat_x, "%s.goto_x", buf);
5796 secfile_insert_int(saving->file, nat_y, "%s.goto_y", buf);
5797 } else {
5798 secfile_insert_bool(saving->file, FALSE, "%s.go", buf);
5799 /* Set this values to allow saving it as table. */
5800 secfile_insert_int(saving->file, 0, "%s.goto_x", buf);
5801 secfile_insert_int(saving->file, 0, "%s.goto_y", buf);
5804 secfile_insert_bool(saving->file, punit->ai_controlled,
5805 "%s.ai", buf);
5807 /* Save AI data of the unit. */
5808 CALL_FUNC_EACH_AI(unit_save, saving->file, punit, buf);
5810 secfile_insert_int(saving->file, punit->server.ord_map,
5811 "%s.ord_map", buf);
5812 secfile_insert_int(saving->file, punit->server.ord_city,
5813 "%s.ord_city", buf);
5814 secfile_insert_bool(saving->file, punit->moved, "%s.moved", buf);
5815 secfile_insert_bool(saving->file, punit->paradropped,
5816 "%s.paradropped", buf);
5817 secfile_insert_int(saving->file, unit_transport_get(punit)
5818 ? unit_transport_get(punit)->id : -1,
5819 "%s.transported_by", buf);
5820 if (punit->carrying != NULL) {
5821 secfile_insert_str(saving->file, goods_rule_name(punit->carrying),
5822 "%s.carrying", buf);
5823 } else {
5824 secfile_insert_str(saving->file, "", "%s.carrying", buf);
5827 secfile_insert_int(saving->file, punit->action_decision_want,
5828 "%s.action_decision", buf);
5830 /* Stored as tile rather than direction to make sure the target tile is
5831 * sane. */
5832 if (punit->action_decision_tile) {
5833 index_to_native_pos(&nat_x, &nat_y,
5834 tile_index(punit->action_decision_tile));
5835 secfile_insert_int(saving->file, nat_x,
5836 "%s.action_decision_tile_x", buf);
5837 secfile_insert_int(saving->file, nat_y,
5838 "%s.action_decision_tile_y", buf);
5839 } else {
5840 /* Dummy values to get tabular format. */
5841 secfile_insert_int(saving->file, -1,
5842 "%s.action_decision_tile_x", buf);
5843 secfile_insert_int(saving->file, -1,
5844 "%s.action_decision_tile_y", buf);
5847 secfile_insert_bool(saving->file, punit->stay,
5848 "%s.stay", buf);
5850 if (punit->has_orders) {
5851 int len = punit->orders.length;
5852 char orders_buf[len + 1], dir_buf[len + 1];
5853 char act_buf[len + 1];
5854 char action_buf[len + 1];
5855 int tgt_vec[len];
5857 last_order = len;
5859 secfile_insert_int(saving->file, len, "%s.orders_length", buf);
5860 secfile_insert_int(saving->file, punit->orders.index,
5861 "%s.orders_index", buf);
5862 secfile_insert_bool(saving->file, punit->orders.repeat,
5863 "%s.orders_repeat", buf);
5864 secfile_insert_bool(saving->file, punit->orders.vigilant,
5865 "%s.orders_vigilant", buf);
5867 for (j = 0; j < len; j++) {
5868 orders_buf[j] = order2char(punit->orders.list[j].order);
5869 dir_buf[j] = '?';
5870 act_buf[j] = '?';
5871 tgt_vec[j] = -1;
5872 action_buf[j] = '?';
5873 switch (punit->orders.list[j].order) {
5874 case ORDER_MOVE:
5875 case ORDER_ACTION_MOVE:
5876 dir_buf[j] = dir2char(punit->orders.list[j].dir);
5877 break;
5878 case ORDER_ACTIVITY:
5879 tgt_vec[j] = punit->orders.list[j].target;
5880 act_buf[j] = activity2char(punit->orders.list[j].activity);
5881 break;
5882 case ORDER_PERFORM_ACTION:
5883 action_buf[j] = num2char(punit->orders.list[j].action);
5884 /* Encoding with num2char() limits the number of actions. */
5885 /* Note: <= is the correct operator. MAX_NUM_ACTIONS is number of
5886 * actions (the last action id + 1). strlen(num_chars) is the
5887 * number of chars (the last char position + 1). The assert is
5888 * supposed to be true. */
5889 FC_STATIC_STRLEN_ASSERT(MAX_NUM_ACTIONS <= strlen(num_chars),
5890 can_not_encode_all_actions);
5892 tgt_vec[j] = punit->orders.list[j].target;
5893 if (direction8_is_valid(punit->orders.list[j].dir)) {
5894 /* The action target is on another tile. */
5895 dir_buf[j] = dir2char(punit->orders.list[j].dir);
5897 break;
5898 case ORDER_FULL_MP:
5899 case ORDER_LAST:
5900 break;
5903 orders_buf[len] = dir_buf[len] = act_buf[len] = '\0';
5904 action_buf[len] = '\0';
5906 secfile_insert_str(saving->file, orders_buf, "%s.orders_list", buf);
5907 secfile_insert_str(saving->file, dir_buf, "%s.dir_list", buf);
5908 secfile_insert_str(saving->file, act_buf, "%s.activity_list", buf);
5909 secfile_insert_str(saving->file, action_buf, "%s.action_list", buf);
5910 secfile_insert_int_vec(saving->file, tgt_vec, len,
5911 "%s.tgt_vec", buf);
5912 } else {
5914 /* Put all the same fields into the savegame - otherwise the
5915 * registry code can't correctly use a tabular format and the
5916 * savegame will be bigger. */
5917 secfile_insert_int(saving->file, 0, "%s.orders_length", buf);
5918 secfile_insert_int(saving->file, 0, "%s.orders_index", buf);
5919 secfile_insert_bool(saving->file, FALSE, "%s.orders_repeat", buf);
5920 secfile_insert_bool(saving->file, FALSE, "%s.orders_vigilant", buf);
5921 secfile_insert_str(saving->file, "-", "%s.orders_list", buf);
5922 secfile_insert_str(saving->file, "-", "%s.dir_list", buf);
5923 secfile_insert_str(saving->file, "-", "%s.activity_list", buf);
5924 secfile_insert_str(saving->file, "-", "%s.action_list", buf);
5926 /* The start of a vector has no number. */
5927 secfile_insert_int(saving->file, -1, "%s.tgt_vec", buf);
5928 last_order = 1;
5931 for (j = last_order; j < longest_order; j++) {
5932 /* Fill in dummy values for order targets so the registry will save
5933 * the unit table in a tabular format. */
5935 secfile_insert_int(saving->file, -1, "%s.tgt_vec,%d", buf, j);
5938 i++;
5939 } unit_list_iterate_end;
5942 /****************************************************************************
5943 Load player (client) attributes data
5944 ****************************************************************************/
5945 static void sg_load_player_attributes(struct loaddata *loading,
5946 struct player *plr)
5948 int plrno = player_number(plr);
5950 /* Check status and return if not OK (sg_success != TRUE). */
5951 sg_check_ret();
5953 /* Toss any existing attribute_block (should not exist) */
5954 if (plr->attribute_block.data) {
5955 free(plr->attribute_block.data);
5956 plr->attribute_block.data = NULL;
5959 /* This is a big heap of opaque data for the client, check everything! */
5960 plr->attribute_block.length = secfile_lookup_int_default(
5961 loading->file, 0, "player%d.attribute_v2_block_length", plrno);
5963 if (0 > plr->attribute_block.length) {
5964 log_sg("player%d.attribute_v2_block_length=%d too small", plrno,
5965 plr->attribute_block.length);
5966 plr->attribute_block.length = 0;
5967 } else if (MAX_ATTRIBUTE_BLOCK < plr->attribute_block.length) {
5968 log_sg("player%d.attribute_v2_block_length=%d too big (max %d)",
5969 plrno, plr->attribute_block.length, MAX_ATTRIBUTE_BLOCK);
5970 plr->attribute_block.length = 0;
5971 } else if (0 < plr->attribute_block.length) {
5972 int part_nr, parts;
5973 size_t actual_length;
5974 int quoted_length;
5975 char *quoted;
5977 sg_failure_ret(
5978 secfile_lookup_int(loading->file, &quoted_length,
5979 "player%d.attribute_v2_block_length_quoted",
5980 plrno), "%s", secfile_error());
5981 sg_failure_ret(
5982 secfile_lookup_int(loading->file, &parts,
5983 "player%d.attribute_v2_block_parts", plrno),
5984 "%s", secfile_error());
5986 quoted = fc_malloc(quoted_length + 1);
5987 quoted[0] = '\0';
5988 plr->attribute_block.data = fc_malloc(plr->attribute_block.length);
5989 for (part_nr = 0; part_nr < parts; part_nr++) {
5990 const char *current =
5991 secfile_lookup_str(loading->file,
5992 "player%d.attribute_v2_block_data.part%d",
5993 plrno, part_nr);
5994 if (!current) {
5995 log_sg("attribute_v2_block_parts=%d actual=%d", parts, part_nr);
5996 break;
5998 log_debug("attribute_v2_block_length_quoted=%lu have=%lu part=%lu",
5999 (unsigned long) quoted_length,
6000 (unsigned long) strlen(quoted),
6001 (unsigned long) strlen(current));
6002 fc_assert(strlen(quoted) + strlen(current) <= quoted_length);
6003 strcat(quoted, current);
6005 fc_assert_msg(quoted_length == strlen(quoted),
6006 "attribute_v2_block_length_quoted=%lu actual=%lu",
6007 (unsigned long) quoted_length,
6008 (unsigned long) strlen(quoted));
6010 actual_length =
6011 unquote_block(quoted,
6012 plr->attribute_block.data,
6013 plr->attribute_block.length);
6014 fc_assert(actual_length == plr->attribute_block.length);
6015 free(quoted);
6019 /****************************************************************************
6020 Save player (client) attributes data.
6021 ****************************************************************************/
6022 static void sg_save_player_attributes(struct savedata *saving,
6023 struct player *plr)
6025 int plrno = player_number(plr);
6027 /* Check status and return if not OK (sg_success != TRUE). */
6028 sg_check_ret();
6030 /* This is a big heap of opaque data from the client. Although the binary
6031 * format is not user editable, keep the lines short enough for debugging,
6032 * and hope that data compression will keep the file a reasonable size.
6033 * Note that the "quoted" format is a multiple of 3.
6035 #define PART_SIZE (3*256)
6036 #define PART_ADJUST (3)
6037 if (plr->attribute_block.data) {
6038 char part[PART_SIZE + PART_ADJUST];
6039 int parts;
6040 int current_part_nr;
6041 char *quoted = quote_block(plr->attribute_block.data,
6042 plr->attribute_block.length);
6043 char *quoted_at = strchr(quoted, ':');
6044 size_t bytes_left = strlen(quoted);
6045 size_t bytes_at_colon = 1 + (quoted_at - quoted);
6046 size_t bytes_adjust = bytes_at_colon % PART_ADJUST;
6048 secfile_insert_int(saving->file, plr->attribute_block.length,
6049 "player%d.attribute_v2_block_length", plrno);
6050 secfile_insert_int(saving->file, bytes_left,
6051 "player%d.attribute_v2_block_length_quoted", plrno);
6053 /* Try to wring some compression efficiencies out of the "quoted" format.
6054 * The first line has a variable length decimal, mis-aligning triples.
6056 if ((bytes_left - bytes_adjust) > PART_SIZE) {
6057 /* first line can be longer */
6058 parts = 1 + (bytes_left - bytes_adjust - 1) / PART_SIZE;
6059 } else {
6060 parts = 1;
6063 secfile_insert_int(saving->file, parts,
6064 "player%d.attribute_v2_block_parts", plrno);
6066 if (parts > 1) {
6067 size_t size_of_current_part = PART_SIZE + bytes_adjust;
6069 /* first line can be longer */
6070 memcpy(part, quoted, size_of_current_part);
6071 part[size_of_current_part] = '\0';
6072 secfile_insert_str(saving->file, part,
6073 "player%d.attribute_v2_block_data.part%d",
6074 plrno, 0);
6075 bytes_left -= size_of_current_part;
6076 quoted_at = &quoted[size_of_current_part];
6077 current_part_nr = 1;
6078 } else {
6079 quoted_at = quoted;
6080 current_part_nr = 0;
6083 for (; current_part_nr < parts; current_part_nr++) {
6084 size_t size_of_current_part = MIN(bytes_left, PART_SIZE);
6086 memcpy(part, quoted_at, size_of_current_part);
6087 part[size_of_current_part] = '\0';
6088 secfile_insert_str(saving->file, part,
6089 "player%d.attribute_v2_block_data.part%d",
6090 plrno,
6091 current_part_nr);
6092 bytes_left -= size_of_current_part;
6093 quoted_at = &quoted_at[size_of_current_part];
6095 fc_assert(bytes_left == 0);
6096 free(quoted);
6098 #undef PART_ADJUST
6099 #undef PART_SIZE
6102 /****************************************************************************
6103 Load vision data
6104 ****************************************************************************/
6105 static void sg_load_player_vision(struct loaddata *loading,
6106 struct player *plr)
6108 int plrno = player_number(plr);
6109 int total_ncities =
6110 secfile_lookup_int_default(loading->file, -1,
6111 "player%d.dc_total", plrno);
6112 int i;
6114 /* Check status and return if not OK (sg_success != TRUE). */
6115 sg_check_ret();
6117 if (!plr->is_alive) {
6118 if (game.server.revealmap & REVEAL_MAP_DEAD
6119 && player_list_size(team_members(plr->team)) == 1) {
6120 /* Reveal all for dead players. */
6121 map_know_and_see_all(plr);
6125 if (-1 == total_ncities
6126 || FALSE == game.info.fogofwar
6127 || !secfile_lookup_bool_default(loading->file, TRUE,
6128 "game.save_private_map")) {
6129 /* We have:
6130 * - a dead player;
6131 * - fogged cities are not saved for any reason;
6132 * - a savegame with fog of war turned off;
6133 * - or game.save_private_map is not set to FALSE in the scenario /
6134 * savegame. The players private knowledge is set to be what he could
6135 * see without fog of war. */
6136 whole_map_iterate(&(wld.map), ptile) {
6137 if (map_is_known(ptile, plr)) {
6138 struct city *pcity = tile_city(ptile);
6140 update_player_tile_last_seen(plr, ptile);
6141 update_player_tile_knowledge(plr, ptile);
6143 if (NULL != pcity) {
6144 update_dumb_city(plr, pcity);
6147 } whole_map_iterate_end;
6149 /* Nothing more to do; */
6150 return;
6153 /* Load player map (terrain). */
6154 LOAD_MAP_CHAR(ch, ptile,
6155 map_get_player_tile(ptile, plr)->terrain
6156 = char2terrain(ch), loading->file,
6157 "player%d.map_t%04d", plrno);
6159 /* Load player map (extras). */
6160 halfbyte_iterate_extras(j, loading->extra.size) {
6161 LOAD_MAP_CHAR(ch, ptile,
6162 sg_extras_set(&map_get_player_tile(ptile, plr)->extras,
6163 ch, loading->extra.order + 4 * j),
6164 loading->file, "player%d.map_e%02d_%04d", plrno, j);
6165 } halfbyte_iterate_extras_end;
6167 if (game.server.foggedborders) {
6168 /* Load player map (border). */
6169 int x, y;
6171 for (y = 0; y < wld.map.ysize; y++) {
6172 const char *buffer
6173 = secfile_lookup_str(loading->file, "player%d.map_owner%04d",
6174 plrno, y);
6175 const char *buffer2
6176 = secfile_lookup_str(loading->file, "player%d.extras_owner%04d",
6177 plrno, y);
6178 const char *ptr = buffer;
6179 const char *ptr2 = buffer2;
6181 sg_failure_ret(NULL != buffer,
6182 "Savegame corrupt - map line %d not found.", y);
6183 for (x = 0; x < wld.map.xsize; x++) {
6184 char token[TOKEN_SIZE];
6185 char token2[TOKEN_SIZE];
6186 int number;
6187 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
6189 scanin(&ptr, ",", token, sizeof(token));
6190 sg_failure_ret('\0' != token[0],
6191 "Savegame corrupt - map size not correct.");
6192 if (strcmp(token, "-") == 0) {
6193 map_get_player_tile(ptile, plr)->owner = NULL;
6194 } else {
6195 sg_failure_ret(str_to_int(token, &number),
6196 "Savegame corrupt - got tile owner=%s in (%d, %d).",
6197 token, x, y);
6198 map_get_player_tile(ptile, plr)->owner = player_by_number(number);
6201 scanin(&ptr2, ",", token2, sizeof(token2));
6202 sg_failure_ret('\0' != token2[0],
6203 "Savegame corrupt - map size not correct.");
6204 if (strcmp(token2, "-") == 0) {
6205 map_get_player_tile(ptile, plr)->extras_owner = NULL;
6206 } else {
6207 sg_failure_ret(str_to_int(token2, &number),
6208 "Savegame corrupt - got extras owner=%s in (%d, %d).",
6209 token, x, y);
6210 map_get_player_tile(ptile, plr)->extras_owner = player_by_number(number);
6216 /* Load player map (update time). */
6217 for (i = 0; i < 4; i++) {
6218 /* put 4-bit segments of 16-bit "updated" field */
6219 if (i == 0) {
6220 LOAD_MAP_CHAR(ch, ptile,
6221 map_get_player_tile(ptile, plr)->last_updated
6222 = ascii_hex2bin(ch, i),
6223 loading->file, "player%d.map_u%02d_%04d", plrno, i);
6224 } else {
6225 LOAD_MAP_CHAR(ch, ptile,
6226 map_get_player_tile(ptile, plr)->last_updated
6227 |= ascii_hex2bin(ch, i),
6228 loading->file, "player%d.map_u%02d_%04d", plrno, i);
6232 /* Load player map known cities. */
6233 for (i = 0; i < total_ncities; i++) {
6234 struct vision_site *pdcity;
6235 char buf[32];
6236 fc_snprintf(buf, sizeof(buf), "player%d.dc%d", plrno, i);
6238 pdcity = vision_site_new(0, NULL, NULL);
6239 if (sg_load_player_vision_city(loading, plr, pdcity, buf)) {
6240 change_playertile_site(map_get_player_tile(pdcity->location, plr),
6241 pdcity);
6242 identity_number_reserve(pdcity->identity);
6243 } else {
6244 /* Error loading the data. */
6245 log_sg("Skipping seen city %d for player %d.", i, plrno);
6246 if (pdcity != NULL) {
6247 vision_site_destroy(pdcity);
6252 /* Repair inconsistent player maps. */
6253 whole_map_iterate(&(wld.map), ptile) {
6254 if (map_is_known_and_seen(ptile, plr, V_MAIN)) {
6255 struct city *pcity = tile_city(ptile);
6257 update_player_tile_knowledge(plr, ptile);
6258 reality_check_city(plr, ptile);
6260 if (NULL != pcity) {
6261 update_dumb_city(plr, pcity);
6264 } whole_map_iterate_end;
6267 /****************************************************************************
6268 Load data for one seen city. sg_save_player_vision_city() is not defined.
6269 ****************************************************************************/
6270 static bool sg_load_player_vision_city(struct loaddata *loading,
6271 struct player *plr,
6272 struct vision_site *pdcity,
6273 const char *citystr)
6275 const char *str;
6276 int i, id, size;
6277 citizens city_size;
6278 int nat_x, nat_y;
6279 const char *stylename;
6281 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_x, "%s.x",
6282 citystr),
6283 FALSE, "%s", secfile_error());
6284 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_y, "%s.y",
6285 citystr),
6286 FALSE, "%s", secfile_error());
6287 pdcity->location = native_pos_to_tile(&(wld.map), nat_x, nat_y);
6288 sg_warn_ret_val(NULL != pdcity->location, FALSE,
6289 "%s invalid tile (%d,%d)", citystr, nat_x, nat_y);
6291 sg_warn_ret_val(secfile_lookup_int(loading->file, &id, "%s.owner",
6292 citystr),
6293 FALSE, "%s", secfile_error());
6294 pdcity->owner = player_by_number(id);
6295 sg_warn_ret_val(NULL != pdcity->owner, FALSE,
6296 "%s has invalid owner (%d); skipping.", citystr, id);
6298 sg_warn_ret_val(secfile_lookup_int(loading->file, &pdcity->identity,
6299 "%s.id", citystr),
6300 FALSE, "%s", secfile_error());
6301 sg_warn_ret_val(IDENTITY_NUMBER_ZERO < pdcity->identity, FALSE,
6302 "%s has invalid id (%d); skipping.", citystr, id);
6304 sg_warn_ret_val(secfile_lookup_int(loading->file, &size,
6305 "%s.size", citystr),
6306 FALSE, "%s", secfile_error());
6307 city_size = (citizens)size; /* set the correct type */
6308 sg_warn_ret_val(size == (int)city_size, FALSE,
6309 "Invalid city size: %d; set to %d.", size, city_size);
6310 vision_site_size_set(pdcity, city_size);
6312 /* Initialise list of improvements */
6313 BV_CLR_ALL(pdcity->improvements);
6314 str = secfile_lookup_str(loading->file, "%s.improvements", citystr);
6315 sg_warn_ret_val(str != NULL, FALSE, "%s", secfile_error());
6316 sg_warn_ret_val(strlen(str) == loading->improvement.size, FALSE,
6317 "Invalid length of '%s.improvements' (%lu ~= %lu).",
6318 citystr, (unsigned long) strlen(str),
6319 (unsigned long) loading->improvement.size);
6320 for (i = 0; i < loading->improvement.size; i++) {
6321 sg_warn_ret_val(str[i] == '1' || str[i] == '0', FALSE,
6322 "Undefined value '%c' within '%s.improvements'.",
6323 str[i], citystr)
6325 if (str[i] == '1') {
6326 struct impr_type *pimprove =
6327 improvement_by_rule_name(loading->improvement.order[i]);
6328 if (pimprove) {
6329 BV_SET(pdcity->improvements, improvement_index(pimprove));
6334 /* Use the section as backup name. */
6335 sz_strlcpy(pdcity->name, secfile_lookup_str_default(loading->file, citystr,
6336 "%s.name", citystr));
6338 pdcity->occupied = secfile_lookup_bool_default(loading->file, FALSE,
6339 "%s.occupied", citystr);
6340 pdcity->walls = secfile_lookup_bool_default(loading->file, FALSE,
6341 "%s.walls", citystr);
6342 pdcity->happy = secfile_lookup_bool_default(loading->file, FALSE,
6343 "%s.happy", citystr);
6344 pdcity->unhappy = secfile_lookup_bool_default(loading->file, FALSE,
6345 "%s.unhappy", citystr);
6346 stylename = secfile_lookup_str_default(loading->file, NULL,
6347 "%s.style", citystr);
6348 if (stylename != NULL) {
6349 pdcity->style = city_style_by_rule_name(stylename);
6350 } else {
6351 pdcity->style = 0;
6353 if (pdcity->style < 0) {
6354 pdcity->style = 0;
6357 pdcity->city_image = secfile_lookup_int_default(loading->file, -100,
6358 "%s.city_image", citystr);
6360 return TRUE;
6363 /****************************************************************************
6364 Save vision data
6365 ****************************************************************************/
6366 static void sg_save_player_vision(struct savedata *saving,
6367 struct player *plr)
6369 int i, plrno = player_number(plr);
6371 /* Check status and return if not OK (sg_success != TRUE). */
6372 sg_check_ret();
6374 if (!game.info.fogofwar || !game.server.save_options.save_private_map) {
6375 /* The player can see all, there's no reason to save the private map. */
6376 return;
6379 /* Save the map (terrain). */
6380 SAVE_MAP_CHAR(ptile,
6381 terrain2char(map_get_player_tile(ptile, plr)->terrain),
6382 saving->file, "player%d.map_t%04d", plrno);
6384 if (game.server.foggedborders) {
6385 /* Save the map (borders). */
6386 int x, y;
6388 for (y = 0; y < wld.map.ysize; y++) {
6389 char line[wld.map.xsize * TOKEN_SIZE];
6391 line[0] = '\0';
6392 for (x = 0; x < wld.map.xsize; x++) {
6393 char token[TOKEN_SIZE];
6394 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
6395 struct player_tile *plrtile = map_get_player_tile(ptile, plr);
6397 if (plrtile == NULL || plrtile->owner == NULL) {
6398 strcpy(token, "-");
6399 } else {
6400 fc_snprintf(token, sizeof(token), "%d",
6401 player_number(plrtile->owner));
6403 strcat(line, token);
6404 if (x < wld.map.xsize) {
6405 strcat(line, ",");
6408 secfile_insert_str(saving->file, line, "player%d.map_owner%04d",
6409 plrno, y);
6412 for (y = 0; y < wld.map.ysize; y++) {
6413 char line[wld.map.xsize * TOKEN_SIZE];
6415 line[0] = '\0';
6416 for (x = 0; x < wld.map.xsize; x++) {
6417 char token[TOKEN_SIZE];
6418 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
6419 struct player_tile *plrtile = map_get_player_tile(ptile, plr);
6421 if (plrtile == NULL || plrtile->extras_owner == NULL) {
6422 strcpy(token, "-");
6423 } else {
6424 fc_snprintf(token, sizeof(token), "%d",
6425 player_number(plrtile->extras_owner));
6427 strcat(line, token);
6428 if (x < wld.map.xsize) {
6429 strcat(line, ",");
6432 secfile_insert_str(saving->file, line, "player%d.extras_owner%04d",
6433 plrno, y);
6437 /* Save the map (extras). */
6438 halfbyte_iterate_extras(j, game.control.num_extra_types) {
6439 int mod[4];
6440 int l;
6442 for (l = 0; l < 4; l++) {
6443 if (4 * j + 1 > game.control.num_extra_types) {
6444 mod[l] = -1;
6445 } else {
6446 mod[l] = 4 * j + l;
6450 SAVE_MAP_CHAR(ptile,
6451 sg_extras_get(map_get_player_tile(ptile, plr)->extras,
6452 map_get_player_tile(ptile, plr)->resource,
6453 mod),
6454 saving->file, "player%d.map_e%02d_%04d", plrno, j);
6455 } halfbyte_iterate_extras_end;
6457 /* Save the map (update time). */
6458 for (i = 0; i < 4; i++) {
6459 /* put 4-bit segments of 16-bit "updated" field */
6460 SAVE_MAP_CHAR(ptile,
6461 bin2ascii_hex(
6462 map_get_player_tile(ptile, plr)->last_updated, i),
6463 saving->file, "player%d.map_u%02d_%04d", plrno, i);
6466 /* Save known cities. */
6467 i = 0;
6468 whole_map_iterate(&(wld.map), ptile) {
6469 struct vision_site *pdcity = map_get_player_city(ptile, plr);
6470 char impr_buf[MAX_NUM_ITEMS + 1];
6471 char buf[32];
6473 fc_snprintf(buf, sizeof(buf), "player%d.dc%d", plrno, i);
6475 if (NULL != pdcity && plr != vision_site_owner(pdcity)) {
6476 int nat_x, nat_y;
6478 index_to_native_pos(&nat_x, &nat_y, tile_index(ptile));
6479 secfile_insert_int(saving->file, nat_y, "%s.y", buf);
6480 secfile_insert_int(saving->file, nat_x, "%s.x", buf);
6482 secfile_insert_int(saving->file, pdcity->identity, "%s.id", buf);
6483 secfile_insert_int(saving->file, player_number(vision_site_owner(pdcity)),
6484 "%s.owner", buf);
6486 secfile_insert_int(saving->file, vision_site_size_get(pdcity),
6487 "%s.size", buf);
6488 secfile_insert_bool(saving->file, pdcity->occupied,
6489 "%s.occupied", buf);
6490 secfile_insert_bool(saving->file, pdcity->walls, "%s.walls", buf);
6491 secfile_insert_bool(saving->file, pdcity->happy, "%s.happy", buf);
6492 secfile_insert_bool(saving->file, pdcity->unhappy, "%s.unhappy", buf);
6493 secfile_insert_str(saving->file, city_style_rule_name(pdcity->style),
6494 "%s.style", buf);
6495 secfile_insert_int(saving->file, pdcity->city_image, "%s.city_image", buf);
6497 /* Save improvement list as bitvector. Note that improvement order
6498 * is saved in savefile.improvement.order. */
6499 improvement_iterate(pimprove) {
6500 impr_buf[improvement_index(pimprove)]
6501 = BV_ISSET(pdcity->improvements, improvement_index(pimprove))
6502 ? '1' : '0';
6503 } improvement_iterate_end;
6504 impr_buf[improvement_count()] = '\0';
6505 sg_failure_ret(strlen(impr_buf) < sizeof(impr_buf),
6506 "Invalid size of the improvement vector (%s.improvements: "
6507 "%lu < %lu).", buf, (long unsigned int) strlen(impr_buf),
6508 (long unsigned int) sizeof(impr_buf));
6509 secfile_insert_str(saving->file, impr_buf, "%s.improvements", buf);
6510 secfile_insert_str(saving->file, pdcity->name, "%s.name", buf);
6512 i++;
6514 } whole_map_iterate_end;
6516 secfile_insert_int(saving->file, i, "player%d.dc_total", plrno);
6519 /* =======================================================================
6520 * Load / save the researches.
6521 * ======================================================================= */
6523 /****************************************************************************
6524 Load '[research]'.
6525 ****************************************************************************/
6526 static void sg_load_researches(struct loaddata *loading)
6528 struct research *presearch;
6529 int count;
6530 int number;
6531 const char *str;
6532 int i, j;
6534 /* Check status and return if not OK (sg_success != TRUE). */
6535 sg_check_ret();
6537 /* Initialize all researches. */
6538 researches_iterate(pinitres) {
6539 init_tech(pinitres, FALSE);
6540 } researches_iterate_end;
6542 /* May be unsaved (e.g. scenario case). */
6543 count = secfile_lookup_int_default(loading->file, 0, "research.count");
6544 for (i = 0; i < count; i++) {
6545 sg_failure_ret(secfile_lookup_int(loading->file, &number,
6546 "research.r%d.number", i),
6547 "%s", secfile_error());
6548 presearch = research_by_number(number);
6549 sg_failure_ret(presearch != NULL,
6550 "Invalid research number %d in 'research.r%d.number'",
6551 number, i);
6553 presearch->tech_goal = technology_load(loading->file,
6554 "research.r%d.goal", i);
6555 sg_failure_ret(secfile_lookup_int(loading->file,
6556 &presearch->techs_researched,
6557 "research.r%d.techs", i),
6558 "%s", secfile_error());
6559 sg_failure_ret(secfile_lookup_int(loading->file,
6560 &presearch->future_tech,
6561 "research.r%d.futuretech", i),
6562 "%s", secfile_error());
6563 sg_failure_ret(secfile_lookup_int(loading->file,
6564 &presearch->bulbs_researched,
6565 "research.r%d.bulbs", i),
6566 "%s", secfile_error());
6567 sg_failure_ret(secfile_lookup_int(loading->file,
6568 &presearch->bulbs_researching_saved,
6569 "research.r%d.bulbs_before", i),
6570 "%s", secfile_error());
6571 presearch->researching_saved = technology_load(loading->file,
6572 "research.r%d.saved", i);
6573 presearch->researching = technology_load(loading->file,
6574 "research.r%d.now", i);
6575 sg_failure_ret(secfile_lookup_bool(loading->file,
6576 &presearch->got_tech,
6577 "research.r%d.got_tech", i),
6578 "%s", secfile_error());
6580 str = secfile_lookup_str(loading->file, "research.r%d.done", i);
6581 sg_failure_ret(str != NULL, "%s", secfile_error());
6582 sg_failure_ret(strlen(str) == loading->technology.size,
6583 "Invalid length of 'research.r%d.done' (%lu ~= %lu).",
6584 i, (unsigned long) strlen(str),
6585 (unsigned long) loading->technology.size);
6586 for (j = 0; j < loading->technology.size; j++) {
6587 sg_failure_ret(str[j] == '1' || str[j] == '0',
6588 "Undefined value '%c' within 'research.r%d.done'.",
6589 str[j], i);
6591 if (str[j] == '1') {
6592 struct advance *padvance =
6593 advance_by_rule_name(loading->technology.order[j]);
6595 if (padvance) {
6596 research_invention_set(presearch, advance_number(padvance),
6597 TECH_KNOWN);
6603 /* In case of tech_leakage, we can update research only after all the
6604 * researches have been loaded */
6605 researches_iterate(pupres) {
6606 research_update(pupres);
6607 } researches_iterate_end;
6610 /****************************************************************************
6611 Save '[research]'.
6612 ****************************************************************************/
6613 static void sg_save_researches(struct savedata *saving)
6615 char invs[A_LAST];
6616 int i = 0;
6618 /* Check status and return if not OK (sg_success != TRUE). */
6619 sg_check_ret();
6621 if (saving->save_players) {
6622 researches_iterate(presearch) {
6623 secfile_insert_int(saving->file, research_number(presearch),
6624 "research.r%d.number", i);
6625 technology_save(saving->file, "research.r%d.goal",
6626 i, presearch->tech_goal);
6627 secfile_insert_int(saving->file, presearch->techs_researched,
6628 "research.r%d.techs", i);
6629 secfile_insert_int(saving->file, presearch->future_tech,
6630 "research.r%d.futuretech", i);
6631 secfile_insert_int(saving->file, presearch->bulbs_researching_saved,
6632 "research.r%d.bulbs_before", i);
6633 technology_save(saving->file, "research.r%d.saved",
6634 i, presearch->researching_saved);
6635 secfile_insert_int(saving->file, presearch->bulbs_researched,
6636 "research.r%d.bulbs", i);
6637 technology_save(saving->file, "research.r%d.now",
6638 i, presearch->researching);
6639 secfile_insert_bool(saving->file, presearch->got_tech,
6640 "research.r%d.got_tech", i);
6641 /* Save technology lists as bytevector. Note that technology order is
6642 * saved in savefile.technology.order */
6643 advance_index_iterate(A_NONE, tech_id) {
6644 invs[tech_id] = (research_invention_state(presearch, tech_id)
6645 == TECH_KNOWN ? '1' : '0');
6646 } advance_index_iterate_end;
6647 invs[game.control.num_tech_types] = '\0';
6648 secfile_insert_str(saving->file, invs, "research.r%d.done", i);
6649 i++;
6650 } researches_iterate_end;
6651 secfile_insert_int(saving->file, i, "research.count");
6655 /* =======================================================================
6656 * Load / save the event cache. Should be the last thing to do.
6657 * ======================================================================= */
6659 /****************************************************************************
6660 Load '[event_cache]'.
6661 ****************************************************************************/
6662 static void sg_load_event_cache(struct loaddata *loading)
6664 /* Check status and return if not OK (sg_success != TRUE). */
6665 sg_check_ret();
6667 event_cache_load(loading->file, "event_cache");
6670 /****************************************************************************
6671 Save '[event_cache]'.
6672 ****************************************************************************/
6673 static void sg_save_event_cache(struct savedata *saving)
6675 /* Check status and return if not OK (sg_success != TRUE). */
6676 sg_check_ret();
6678 if (saving->scenario) {
6679 /* Do _not_ save events in a scenario. */
6680 return;
6683 event_cache_save(saving->file, "event_cache");
6686 /* =======================================================================
6687 * Load / save the open treaties
6688 * ======================================================================= */
6690 /****************************************************************************
6691 Load '[treaty_xxx]'.
6692 ****************************************************************************/
6693 static void sg_load_treaties(struct loaddata *loading)
6695 int tidx;
6696 const char *plr0;
6697 struct treaty_list *treaties = get_all_treaties();
6699 for (tidx = 0; (plr0 = secfile_lookup_str_default(loading->file, NULL,
6700 "treaty%d.plr0", tidx)) != NULL ;
6701 tidx++) {
6702 const char *plr1;
6703 const char *ct;
6704 int cidx;
6705 struct player *p0, *p1;
6707 plr1 = secfile_lookup_str(loading->file, "treaty%d.plr1", tidx);
6709 p0 = player_by_name(plr0);
6710 p1 = player_by_name(plr1);
6712 if (p0 == NULL || p1 == NULL) {
6713 log_error("Treaty between unknown players %s and %s", plr0, plr1);
6714 } else {
6715 struct Treaty *ptreaty = fc_malloc(sizeof(*ptreaty));
6717 init_treaty(ptreaty, p0, p1);
6718 treaty_list_prepend(treaties, ptreaty);
6720 for (cidx = 0; (ct = secfile_lookup_str_default(loading->file, NULL,
6721 "treaty%d.clause%d.type",
6722 tidx, cidx)) != NULL ;
6723 cidx++ ) {
6724 enum clause_type type = clause_type_by_name(ct, fc_strcasecmp);
6725 const char *plrx;
6727 if (!clause_type_is_valid(type)) {
6728 log_error("Invalid clause type \"%s\"", ct);
6729 } else {
6730 struct player *pgiver = NULL;
6732 plrx = secfile_lookup_str(loading->file, "treaty%d.clause%d.from",
6733 tidx, cidx);
6735 if (!fc_strcasecmp(plrx, plr0)) {
6736 pgiver = p0;
6737 } else if (!fc_strcasecmp(plrx, plr1)) {
6738 pgiver = p1;
6739 } else {
6740 log_error("Clause giver %s is not participant of the treaty"
6741 "between %s and %s", plrx, plr0, plr1);
6744 if (pgiver != NULL) {
6745 int value;
6747 value = secfile_lookup_int_default(loading->file, 0,
6748 "treaty%d.clause%d.value",
6749 tidx, cidx);
6751 add_clause(ptreaty, pgiver, type, value);
6755 /* These must be after clauses have been added so that acceptance
6756 * does not get cleared by what seems like changes to the treaty. */
6757 ptreaty->accept0 = secfile_lookup_bool_default(loading->file, FALSE,
6758 "treaty%d.accept0", tidx);
6759 ptreaty->accept1 = secfile_lookup_bool_default(loading->file, FALSE,
6760 "treaty%d.accept1", tidx);
6766 /****************************************************************************
6767 Save '[treaty_xxx]'.
6768 ****************************************************************************/
6769 static void sg_save_treaties(struct savedata *saving)
6771 struct treaty_list *treaties = get_all_treaties();
6772 int tidx = 0;
6774 treaty_list_iterate(treaties, ptr) {
6775 char tpath[512];
6776 int cidx = 0;
6778 fc_snprintf(tpath, sizeof(tpath), "treaty%d", tidx++);
6780 secfile_insert_str(saving->file, player_name(ptr->plr0), "%s.plr0", tpath);
6781 secfile_insert_str(saving->file, player_name(ptr->plr1), "%s.plr1", tpath);
6782 secfile_insert_bool(saving->file, ptr->accept0, "%s.accept0", tpath);
6783 secfile_insert_bool(saving->file, ptr->accept1, "%s.accept1", tpath);
6785 clause_list_iterate(ptr->clauses, pclaus) {
6786 char cpath[512];
6788 fc_snprintf(cpath, sizeof(cpath), "%s.clause%d", tpath, cidx++);
6790 secfile_insert_str(saving->file, clause_type_name(pclaus->type), "%s.type", cpath);
6791 secfile_insert_str(saving->file, player_name(pclaus->from), "%s.from", cpath);
6792 secfile_insert_int(saving->file, pclaus->value, "%s.value", cpath);
6793 } clause_list_iterate_end;
6794 } treaty_list_iterate_end;
6797 /* =======================================================================
6798 * Load / save the history report
6799 * ======================================================================= */
6801 /****************************************************************************
6802 Load '[history]'.
6803 ****************************************************************************/
6804 static void sg_load_history(struct loaddata *loading)
6806 struct history_report *hist = history_report_get();
6807 int turn;
6809 turn = secfile_lookup_int_default(loading->file, -2, "history.turn");
6811 if (turn + 1 >= game.info.turn) {
6812 const char *str;
6814 hist->turn = turn;
6815 str = secfile_lookup_str(loading->file, "history.title");
6816 sg_failure_ret(str != NULL, "%s", secfile_error());
6817 strncpy(hist->title, str, REPORT_TITLESIZE);
6818 str = secfile_lookup_str(loading->file, "history.body");
6819 sg_failure_ret(str != NULL, "%s", secfile_error());
6820 strncpy(hist->body, str, REPORT_BODYSIZE);
6824 /****************************************************************************
6825 Save '[history]'.
6826 ****************************************************************************/
6827 static void sg_save_history(struct savedata *saving)
6829 struct history_report *hist = history_report_get();
6831 secfile_insert_int(saving->file, hist->turn, "history.turn");
6833 if (hist->turn + 1 >= game.info.turn) {
6834 secfile_insert_str(saving->file, hist->title, "history.title");
6835 secfile_insert_str(saving->file, hist->body, "history.body");
6839 /* =======================================================================
6840 * Load / save the mapimg definitions.
6841 * ======================================================================= */
6843 /****************************************************************************
6844 Load '[mapimg]'.
6845 ****************************************************************************/
6846 static void sg_load_mapimg(struct loaddata *loading)
6848 int mapdef_count, i;
6850 /* Check status and return if not OK (sg_success != TRUE). */
6851 sg_check_ret();
6853 /* Clear all defined map images. */
6854 while (mapimg_count() > 0) {
6855 mapimg_delete(0);
6858 mapdef_count = secfile_lookup_int_default(loading->file, 0,
6859 "mapimg.count");
6860 log_verbose("Saved map image definitions: %d.", mapdef_count);
6862 if (0 >= mapdef_count) {
6863 return;
6866 for (i = 0; i < mapdef_count; i++) {
6867 const char *p;
6869 p = secfile_lookup_str(loading->file, "mapimg.mapdef%d", i);
6870 if (NULL == p) {
6871 log_verbose("[Mapimg %4d] Missing definition.", i);
6872 continue;
6875 if (!mapimg_define(p, FALSE)) {
6876 log_error("Invalid map image definition %4d: %s.", i, p);
6879 log_verbose("Mapimg %4d loaded.", i);
6883 /****************************************************************************
6884 Save '[mapimg]'.
6885 ****************************************************************************/
6886 static void sg_save_mapimg(struct savedata *saving)
6888 /* Check status and return if not OK (sg_success != TRUE). */
6889 sg_check_ret();
6891 secfile_insert_int(saving->file, mapimg_count(), "mapimg.count");
6892 if (mapimg_count() > 0) {
6893 int i;
6895 for (i = 0; i < mapimg_count(); i++) {
6896 char buf[MAX_LEN_MAPDEF];
6898 mapimg_id2str(i, buf, sizeof(buf));
6899 secfile_insert_str(saving->file, buf, "mapimg.mapdef%d", i);
6904 /* =======================================================================
6905 * Sanity checks for loading / saving a game.
6906 * ======================================================================= */
6908 /****************************************************************************
6909 Sanity check for loaded game.
6910 ****************************************************************************/
6911 static void sg_load_sanitycheck(struct loaddata *loading)
6913 int players;
6915 /* Check status and return if not OK (sg_success != TRUE). */
6916 sg_check_ret();
6918 if (game.info.is_new_game) {
6919 /* Nothing to do for new games (or not started scenarios). */
6920 return;
6923 /* Old savegames may have maxplayers lower than current player count,
6924 * fix. */
6925 players = normal_player_count();
6926 if (game.server.max_players < players) {
6927 log_verbose("Max players lower than current players, fixing");
6928 game.server.max_players = players;
6931 /* Fix ferrying sanity */
6932 players_iterate(pplayer) {
6933 unit_list_iterate_safe(pplayer->units, punit) {
6934 if (!unit_transport_get(punit)
6935 && !can_unit_exist_at_tile(&(wld.map), punit, unit_tile(punit))) {
6936 log_sg("Removing %s unferried %s in %s at (%d, %d)",
6937 nation_rule_name(nation_of_player(pplayer)),
6938 unit_rule_name(punit),
6939 terrain_rule_name(unit_tile(punit)->terrain),
6940 TILE_XY(unit_tile(punit)));
6941 bounce_unit(punit, TRUE);
6943 } unit_list_iterate_safe_end;
6944 } players_iterate_end;
6946 /* Fix stacking issues. We don't rely on the savegame preserving
6947 * alliance invariants (old savegames often did not) so if there are any
6948 * unallied units on the same tile we just bounce them. */
6949 players_iterate(pplayer) {
6950 players_iterate(aplayer) {
6951 resolve_unit_stacks(pplayer, aplayer, TRUE);
6952 } players_iterate_end;
6954 /* Backward compatibility: if we had any open-ended orders (pillage)
6955 * in the savegame, assign specific targets now */
6956 unit_list_iterate(pplayer->units, punit) {
6957 unit_assign_specific_activity_target(punit,
6958 &punit->activity,
6959 &punit->activity_target);
6960 } unit_list_iterate_end;
6961 } players_iterate_end;
6963 /* Recalculate the potential buildings for each city. Has caused some
6964 * problems with game random state.
6965 * This also changes the game state if you save the game directly after
6966 * loading it and compare the results. */
6967 players_iterate(pplayer) {
6968 bool saved_ai_control = is_ai(pplayer);
6970 /* Recalculate for all players. */
6971 set_as_human(pplayer);
6973 /* Building advisor needs data phase open in order to work */
6974 adv_data_phase_init(pplayer, FALSE);
6975 building_advisor(pplayer);
6976 /* Close data phase again so it can be opened again when game starts. */
6977 adv_data_phase_done(pplayer);
6979 if (saved_ai_control) {
6980 set_as_ai(pplayer);
6982 } players_iterate_end;
6984 /* Check worked tiles map */
6985 #ifdef FREECIV_DEBUG
6986 if (loading->worked_tiles != NULL) {
6987 /* check the entire map for unused worked tiles */
6988 whole_map_iterate(&(wld.map), ptile) {
6989 if (loading->worked_tiles[ptile->index] != -1) {
6990 log_error("[city id: %d] Unused worked tile at (%d, %d).",
6991 loading->worked_tiles[ptile->index], TILE_XY(ptile));
6993 } whole_map_iterate_end;
6995 #endif /* FREECIV_DEBUG */
6997 /* Check researching technologies and goals. */
6998 researches_iterate(presearch) {
6999 if (presearch->researching != A_UNSET
7000 && !is_future_tech(presearch->researching)
7001 && (valid_advance_by_number(presearch->researching) == NULL
7002 || (research_invention_state(presearch, presearch->researching)
7003 != TECH_PREREQS_KNOWN))) {
7004 log_sg(_("%s had invalid researching technology."),
7005 research_name_translation(presearch));
7006 presearch->researching = A_UNSET;
7008 if (presearch->tech_goal != A_UNSET
7009 && !is_future_tech(presearch->tech_goal)
7010 && (valid_advance_by_number(presearch->researching) == NULL
7011 || !research_invention_reachable(presearch, presearch->tech_goal)
7012 || (research_invention_state(presearch, presearch->tech_goal)
7013 == TECH_KNOWN))) {
7014 log_sg(_("%s had invalid technology goal."),
7015 research_name_translation(presearch));
7016 presearch->tech_goal = A_UNSET;
7018 } researches_iterate_end;
7020 /* Check if some player has more than one of some UTYF_UNIQUE unit type */
7021 players_iterate(pplayer) {
7022 int unique_count[U_LAST];
7024 memset(unique_count, 0, sizeof(unique_count));
7026 unit_list_iterate(pplayer->units, punit) {
7027 unique_count[utype_index(unit_type_get(punit))]++;
7028 } unit_list_iterate_end;
7030 unit_type_iterate(ut) {
7031 if (unique_count[utype_index(ut)] > 1 && utype_has_flag(ut, UTYF_UNIQUE)) {
7032 log_sg(_("%s has multiple units of type %s though it should be possible "
7033 "to have only one."),
7034 player_name(pplayer), utype_name_translation(ut));
7036 } unit_type_iterate_end;
7037 } players_iterate_end;
7039 if (0 == strlen(server.game_identifier)
7040 || !is_base64url(server.game_identifier)) {
7041 /* This uses fc_rand(), so random state has to be initialized before. */
7042 randomize_base64url_string(server.game_identifier,
7043 sizeof(server.game_identifier));
7046 /* Restore game random state, just in case various initialization code
7047 * inexplicably altered the previously existing state. */
7048 if (!game.info.is_new_game) {
7049 fc_rand_set_state(loading->rstate);
7052 /* At the end do the default sanity checks. */
7053 sanity_check();
7056 /****************************************************************************
7057 Sanity check for saved game.
7058 ****************************************************************************/
7059 static void sg_save_sanitycheck(struct savedata *saving)
7061 /* Check status and return if not OK (sg_success != TRUE). */
7062 sg_check_ret();