Freeciv-3.1
Loading...
Searching...
No Matches
savegame3.c
Go to the documentation of this file.
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.
7
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***********************************************************************/
13
14/*
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.
22
23 Structure of this file:
24
25 - The main function for saving is savegame3_save().
26
27 - The real work is done by savegame3_load() and savegame3_save_real().
28 This function call all submodules (settings, players, etc.)
29
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)
33
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.
37
38 - The submodules can be further divided as:
39 sg_load_<submodule>_<subsubmodule>
40
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).
44
45 Creating a savegame:
46
47 (nothing at the moment)
48
49 Loading a savegame:
50
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.
56
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.
61
62*/
63
64#ifdef HAVE_CONFIG_H
65#include <fc_config.h>
66#endif
67
68#include <ctype.h>
69#include <stdarg.h>
70#include <stdio.h>
71#include <stdlib.h>
72#include <string.h>
73
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"
85
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"
106
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"
128
129/* server/advisors */
130#include "advdata.h"
131#include "advbuilding.h"
132#include "infracache.h"
133
134/* server/generator */
135#include "mapgen.h"
136#include "mapgen_utils.h"
137
138/* server/scripting */
139#include "script_server.h"
140
141/* ai */
142#include "aitraits.h"
143#include "difficulty.h"
144
145#include "savegame3.h"
146
147extern bool sg_success;
148
149#ifdef FREECIV_TESTMATIC
150#define SAVE_DUMMY_TURN_CHANGE_TIME 1
151#endif
152
153/*
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.
156 *
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 y coordinate
163 * Example:
164 * SAVE_MAP_CHAR(ptile, terrain2char(ptile->terrain), file, "map.t%04d");
165 */
166#define SAVE_MAP_CHAR(ptile, GET_XY_CHAR, secfile, secpath, ...) \
167{ \
168 char _line[wld.map.xsize + 1]; \
169 int _nat_x, _nat_y; \
170 \
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]); \
180 } \
181 _line[wld.map.xsize] = '\0'; \
182 secfile_insert_str(secfile, _line, secpath, ## __VA_ARGS__, _nat_y); \
183 } \
184}
185
186/*
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.
192 *
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 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);
205 *
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.
212 */
213#define LOAD_MAP_CHAR(ch, ptile, SET_XY_CHAR, secfile, secpath, ...) \
214{ \
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 " SIZE_T_PRINTF \
230 ")='%s'", wld.map.xsize, strlen(_line), buf); \
231 _printed_warning = TRUE; \
232 continue; \
233 } \
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); \
238 } \
239 } \
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.")); \
245 } \
246}
247
248/* Iterate on the extras half-bytes */
249#define halfbyte_iterate_extras(e, num_extras_types) \
250{ \
251 int e; \
252 for (e = 0; 4 * e < (num_extras_types); e++) {
253
254#define halfbyte_iterate_extras_end \
255 } \
256}
257
258struct savedata {
261
262 /* set by the caller */
263 const char *save_reason;
265
266 /* Set in sg_save_game(); needed in sg_save_map_*(); ... */
268};
269
270#define TOKEN_SIZE 10
271
272static 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(). */
277
278static void savegame3_save_real(struct section_file *file,
279 const char *save_reason,
280 bool scenario);
281static struct loaddata *loaddata_new(struct section_file *file);
282static void loaddata_destroy(struct loaddata *loading);
283
284static struct savedata *savedata_new(struct section_file *file,
285 const char *save_reason,
286 bool scenario);
287static void savedata_destroy(struct savedata *saving);
288
289static enum unit_orders char2order(char order);
290static char order2char(enum unit_orders order);
291static enum direction8 char2dir(char dir);
292static char dir2char(enum direction8 dir);
293static char activity2char(enum unit_activity activity);
294static enum unit_activity char2activity(char activity);
295static char *quote_block(const void *const data, int length);
296static int unquote_block(const char *const quoted_, void *dest,
297 int dest_length);
298static void worklist_load(struct section_file *file, int wlist_max_length,
299 struct worklist *pwl, const char *path, ...);
300static void worklist_save(struct section_file *file,
301 const struct worklist *pwl,
302 int max_length, const char *path, ...);
303static void unit_ordering_calc(void);
304static void unit_ordering_apply(void);
305static void sg_extras_set(bv_extras *extras, char ch, struct extra_type **idx);
306static char sg_extras_get(bv_extras extras, struct extra_type *presource,
307 const int *idx);
308static struct terrain *char2terrain(char ch);
309static char terrain2char(const struct terrain *pterrain);
310static Tech_type_id technology_load(struct section_file *file,
311 const char *path, int plrno);
312static void technology_save(struct section_file *file,
313 const char *path, int plrno, Tech_type_id tech);
314
315static void sg_load_savefile(struct loaddata *loading);
316static void sg_save_savefile(struct savedata *saving);
317static void sg_save_savefile_options(struct savedata *saving,
318 const char *option);
319
320static void sg_load_game(struct loaddata *loading);
321static void sg_save_game(struct savedata *saving);
322
323static void sg_load_ruledata(struct loaddata *loading);
324static void sg_save_ruledata(struct savedata *saving);
325
326static void sg_load_random(struct loaddata *loading);
327static void sg_save_random(struct savedata *saving);
328
329static void sg_load_script(struct loaddata *loading);
330static void sg_save_script(struct savedata *saving);
331
332static void sg_load_scenario(struct loaddata *loading);
333static void sg_save_scenario(struct savedata *saving);
334
335static void sg_load_settings(struct loaddata *loading);
336static void sg_save_settings(struct savedata *saving);
337
338static void sg_load_map(struct loaddata *loading);
339static void sg_save_map(struct savedata *saving);
340static void sg_load_map_tiles(struct loaddata *loading);
341static void sg_save_map_tiles(struct savedata *saving);
342static void sg_load_map_tiles_extras(struct loaddata *loading);
343static void sg_save_map_tiles_extras(struct savedata *saving);
344
345static void sg_load_map_startpos(struct loaddata *loading);
346static void sg_save_map_startpos(struct savedata *saving);
347static void sg_load_map_owner(struct loaddata *loading);
348static void sg_save_map_owner(struct savedata *saving);
349static void sg_load_map_worked(struct loaddata *loading);
350static void sg_save_map_worked(struct savedata *saving);
351static void sg_load_map_known(struct loaddata *loading);
352static void sg_save_map_known(struct savedata *saving);
353
354static void sg_load_players_basic(struct loaddata *loading);
355static void sg_load_players(struct loaddata *loading);
356static void sg_load_player_main(struct loaddata *loading,
357 struct player *plr);
358static void sg_load_player_cities(struct loaddata *loading,
359 struct player *plr);
360static bool sg_load_player_city(struct loaddata *loading, struct player *plr,
361 struct city *pcity, const char *citystr,
362 int wlist_max_length);
363static void sg_load_player_city_citizens(struct loaddata *loading,
364 struct player *plr,
365 struct city *pcity,
366 const char *citystr);
367static void sg_load_player_units(struct loaddata *loading,
368 struct player *plr);
369static bool sg_load_player_unit(struct loaddata *loading,
370 struct player *plr, struct unit *punit,
371 int orders_max_length,
372 const char *unitstr);
373static void sg_load_player_units_transport(struct loaddata *loading,
374 struct player *plr);
375static void sg_load_player_attributes(struct loaddata *loading,
376 struct player *plr);
377static void sg_load_player_vision(struct loaddata *loading,
378 struct player *plr);
379static bool sg_load_player_vision_city(struct loaddata *loading,
380 struct player *plr,
381 struct vision_site *pdcity,
382 const char *citystr);
383static void sg_save_players(struct savedata *saving);
384static void sg_save_player_main(struct savedata *saving,
385 struct player *plr);
386static void sg_save_player_cities(struct savedata *saving,
387 struct player *plr);
388static void sg_save_player_units(struct savedata *saving,
389 struct player *plr);
390static void sg_save_player_attributes(struct savedata *saving,
391 struct player *plr);
392static void sg_save_player_vision(struct savedata *saving,
393 struct player *plr);
394
395static void sg_load_researches(struct loaddata *loading);
396static void sg_save_researches(struct savedata *saving);
397
398static void sg_load_event_cache(struct loaddata *loading);
399static void sg_save_event_cache(struct savedata *saving);
400
401static void sg_load_treaties(struct loaddata *loading);
402static void sg_save_treaties(struct savedata *saving);
403
404static void sg_load_history(struct loaddata *loading);
405static void sg_save_history(struct savedata *saving);
406
407static void sg_load_mapimg(struct loaddata *loading);
408static void sg_save_mapimg(struct savedata *saving);
409
410static void sg_load_sanitycheck(struct loaddata *loading);
411static void sg_save_sanitycheck(struct savedata *saving);
412
413
414/************************************************************************/
417void savegame3_save(struct section_file *sfile, const char *save_reason,
418 bool scenario)
419{
420 fc_assert_ret(sfile != NULL);
421
422#ifdef DEBUG_TIMERS
423 struct timer *savetimer = timer_new(TIMER_CPU, TIMER_DEBUG);
424 timer_start(savetimer);
425#endif
426
427 log_verbose("saving game in new format ...");
428 savegame3_save_real(sfile, save_reason, scenario);
429
430#ifdef DEBUG_TIMERS
431 timer_stop(savetimer);
432 log_debug("Creating secfile in %.3f seconds.", timer_read_seconds(savetimer));
433 timer_destroy(savetimer);
434#endif /* DEBUG_TIMERS */
435}
436
437/* =======================================================================
438 * Basic load / save functions.
439 * ======================================================================= */
440
441/************************************************************************/
444void savegame3_load(struct section_file *file)
445{
446 struct loaddata *loading;
447 bool was_send_city_suppressed, was_send_tile_suppressed;
448
449 /* initialise loading */
450 was_send_city_suppressed = send_city_suppression(TRUE);
451 was_send_tile_suppressed = send_tile_suppression(TRUE);
452 loading = loaddata_new(file);
454
455 /* Load the savegame data. */
456 /* [compat] */
457 sg_load_compat(loading, SAVEGAME_3);
458 /* [scenario] */
459 sg_load_scenario(loading);
460 /* [savefile] */
461 sg_load_savefile(loading);
462 /* [game] */
463 sg_load_game(loading);
464 /* [random] */
465 sg_load_random(loading);
466 /* [settings] */
467 sg_load_settings(loading);
468 /* [ruledata] */
469 sg_load_ruledata(loading);
470 /* [players] (basic data) */
471 sg_load_players_basic(loading);
472 /* [map]; needs width and height loaded by [settings] */
473 sg_load_map(loading);
474 /* [research] */
475 sg_load_researches(loading);
476 /* [player<i>] */
477 sg_load_players(loading);
478 /* [event_cache] */
479 sg_load_event_cache(loading);
480 /* [treaties] */
481 sg_load_treaties(loading);
482 /* [history] */
483 sg_load_history(loading);
484 /* [mapimg] */
485 sg_load_mapimg(loading);
486 /* [script] -- must come last as may reference game objects */
487 sg_load_script(loading);
488 /* [post_load_compat]; needs the game loaded by [savefile] */
490
491 /* Sanity checks for the loaded game. */
492 sg_load_sanitycheck(loading);
493
494 /* deinitialise loading */
495 loaddata_destroy(loading);
496 send_tile_suppression(was_send_tile_suppressed);
497 send_city_suppression(was_send_city_suppressed);
498
499 if (!sg_success) {
500 log_error("Failure loading savegame!");
501 /* Try to get the server back to a vaguely sane state */
504 load_rulesets(NULL, NULL, FALSE, NULL, TRUE, FALSE, TRUE);
505 }
506}
507
508/************************************************************************/
512 const char *save_reason,
513 bool scenario)
514{
515 struct savedata *saving;
516
517 /* initialise loading */
520
521 /* [scenario] */
522 /* This should be first section so scanning through all scenarios just for
523 * names and descriptions would go faster. */
524 sg_save_scenario(saving);
525 /* [savefile] */
526 sg_save_savefile(saving);
527 /* [game] */
528 sg_save_game(saving);
529 /* [random] */
530 sg_save_random(saving);
531 /* [script] */
532 sg_save_script(saving);
533 /* [settings] */
534 sg_save_settings(saving);
535 /* [ruledata] */
536 sg_save_ruledata(saving);
537 /* [map] */
538 sg_save_map(saving);
539 /* [player<i>] */
540 sg_save_players(saving);
541 /* [research] */
542 sg_save_researches(saving);
543 /* [event_cache] */
544 sg_save_event_cache(saving);
545 /* [treaty<i>] */
546 sg_save_treaties(saving);
547 /* [history] */
548 sg_save_history(saving);
549 /* [mapimg] */
550 sg_save_mapimg(saving);
551
552 /* Sanity checks for the saved game. */
553 sg_save_sanitycheck(saving);
554
555 /* deinitialise saving */
556 savedata_destroy(saving);
557
558 if (!sg_success) {
559 log_error("Failure saving savegame!");
560 }
561}
562
563/************************************************************************/
566static struct loaddata *loaddata_new(struct section_file *file)
567{
568 struct loaddata *loading = calloc(1, sizeof(*loading));
569 loading->file = file;
570 loading->secfile_options = NULL;
571
572 loading->improvement.order = NULL;
573 loading->improvement.size = -1;
574 loading->technology.order = NULL;
575 loading->technology.size = -1;
576 loading->activities.order = NULL;
577 loading->activities.size = -1;
578 loading->trait.order = NULL;
579 loading->trait.size = -1;
580 loading->extra.order = NULL;
581 loading->extra.size = -1;
582 loading->multiplier.order = NULL;
583 loading->multiplier.size = -1;
584 loading->specialist.order = NULL;
585 loading->specialist.size = -1;
586 loading->action.order = NULL;
587 loading->action.size = -1;
588 loading->act_dec.order = NULL;
589 loading->act_dec.size = -1;
590 loading->ssa.order = NULL;
591 loading->ssa.size = -1;
592
593 loading->server_state = S_S_INITIAL;
594 loading->rstate = fc_rand_state();
595 loading->worked_tiles = NULL;
596
597 return loading;
598}
599
600/************************************************************************/
603static void loaddata_destroy(struct loaddata *loading)
604{
605 if (loading->improvement.order != NULL) {
606 free(loading->improvement.order);
607 }
608
609 if (loading->technology.order != NULL) {
610 free(loading->technology.order);
611 }
612
613 if (loading->activities.order != NULL) {
614 free(loading->activities.order);
615 }
616
617 if (loading->trait.order != NULL) {
618 free(loading->trait.order);
619 }
620
621 if (loading->extra.order != NULL) {
622 free(loading->extra.order);
623 }
624
625 if (loading->multiplier.order != NULL) {
626 free(loading->multiplier.order);
627 }
628
629 if (loading->specialist.order != NULL) {
630 free(loading->specialist.order);
631 }
632
633 if (loading->action.order != NULL) {
634 free(loading->action.order);
635 }
636
637 if (loading->act_dec.order != NULL) {
638 free(loading->act_dec.order);
639 }
640
641 if (loading->ssa.order != NULL) {
642 free(loading->ssa.order);
643 }
644
645 if (loading->worked_tiles != NULL) {
646 free(loading->worked_tiles);
647 }
648
649 free(loading);
650}
651
652/************************************************************************/
655static struct savedata *savedata_new(struct section_file *file,
656 const char *save_reason,
657 bool scenario)
658{
659 struct savedata *saving = calloc(1, sizeof(*saving));
660 saving->file = file;
661 saving->secfile_options[0] = '\0';
662
663 saving->save_reason = save_reason;
664 saving->scenario = scenario;
665
666 saving->save_players = FALSE;
667
668 return saving;
669}
670
671/************************************************************************/
674static void savedata_destroy(struct savedata *saving)
675{
676 free(saving);
677}
678
679/* =======================================================================
680 * Helper functions.
681 * ======================================================================= */
682
683/************************************************************************/
686static enum unit_orders char2order(char order)
687{
688 switch (order) {
689 case 'm':
690 case 'M':
691 return ORDER_MOVE;
692 case 'w':
693 case 'W':
694 return ORDER_FULL_MP;
695 case 'a':
696 case 'A':
697 return ORDER_ACTIVITY;
698 case 'x':
699 case 'X':
700 return ORDER_ACTION_MOVE;
701 case 'p':
702 case 'P':
704 }
705
706 /* This can happen if the savegame is invalid. */
707 return ORDER_LAST;
708}
709
710/************************************************************************/
713static char order2char(enum unit_orders order)
714{
715 switch (order) {
716 case ORDER_MOVE:
717 return 'm';
718 case ORDER_FULL_MP:
719 return 'w';
720 case ORDER_ACTIVITY:
721 return 'a';
723 return 'x';
725 return 'p';
726 case ORDER_LAST:
727 break;
728 }
729
731 return '?';
732}
733
734/************************************************************************/
737static enum direction8 char2dir(char dir)
738{
739 /* Numberpad values for the directions. */
740 switch (dir) {
741 case '1':
742 return DIR8_SOUTHWEST;
743 case '2':
744 return DIR8_SOUTH;
745 case '3':
746 return DIR8_SOUTHEAST;
747 case '4':
748 return DIR8_WEST;
749 case '6':
750 return DIR8_EAST;
751 case '7':
752 return DIR8_NORTHWEST;
753 case '8':
754 return DIR8_NORTH;
755 case '9':
756 return DIR8_NORTHEAST;
757 }
758
759 /* This can happen if the savegame is invalid. */
760 return direction8_invalid();
761}
762
763/************************************************************************/
766static char dir2char(enum direction8 dir)
767{
768 /* Numberpad values for the directions. */
769 switch (dir) {
770 case DIR8_NORTH:
771 return '8';
772 case DIR8_SOUTH:
773 return '2';
774 case DIR8_EAST:
775 return '6';
776 case DIR8_WEST:
777 return '4';
778 case DIR8_NORTHEAST:
779 return '9';
780 case DIR8_NORTHWEST:
781 return '7';
782 case DIR8_SOUTHEAST:
783 return '3';
784 case DIR8_SOUTHWEST:
785 return '1';
786 }
787
789 return '?';
790}
791
792/************************************************************************/
795static char activity2char(enum unit_activity activity)
796{
797 switch (activity) {
798 case ACTIVITY_IDLE:
799 return 'w';
800 case ACTIVITY_POLLUTION:
801 return 'p';
802 case ACTIVITY_MINE:
803 return 'm';
804 case ACTIVITY_PLANT:
805 return 'M';
806 case ACTIVITY_IRRIGATE:
807 return 'i';
808 case ACTIVITY_CULTIVATE:
809 return 'I';
810 case ACTIVITY_FORTIFIED:
811 return 'f';
812 case ACTIVITY_SENTRY:
813 return 's';
814 case ACTIVITY_PILLAGE:
815 return 'e';
816 case ACTIVITY_GOTO:
817 return 'g';
818 case ACTIVITY_EXPLORE:
819 return 'x';
820 case ACTIVITY_TRANSFORM:
821 return 'o';
822 case ACTIVITY_FORTIFYING:
823 return 'y';
824 case ACTIVITY_FALLOUT:
825 return 'u';
826 case ACTIVITY_BASE:
827 return 'b';
828 case ACTIVITY_GEN_ROAD:
829 return 'R';
830 case ACTIVITY_CONVERT:
831 return 'c';
832 case ACTIVITY_OLD_ROAD:
833 case ACTIVITY_FORTRESS:
834 case ACTIVITY_OLD_RAILROAD:
835 case ACTIVITY_AIRBASE:
836 case ACTIVITY_UNKNOWN:
837 case ACTIVITY_PATROL_UNUSED:
838 return '?';
839 case ACTIVITY_LAST:
840 break;
841 }
842
844 return '?';
845}
846
847/************************************************************************/
850static enum unit_activity char2activity(char activity)
851{
852 enum unit_activity a;
853
854 for (a = 0; a < ACTIVITY_LAST; a++) {
855 char achar = activity2char(a);
856
857 if (activity == achar) {
858 return a;
859 }
860 }
861
862 /* This can happen if the savegame is invalid. */
863 return ACTIVITY_LAST;
864}
865
866/************************************************************************/
870static char *quote_block(const void *const data, int length)
871{
872 char *buffer = fc_malloc(length * 3 + 10);
873 size_t offset;
874 int i;
875
876 sprintf(buffer, "%d:", length);
877 offset = strlen(buffer);
878
879 for (i = 0; i < length; i++) {
880 sprintf(buffer + offset, "%02x ", ((unsigned char *) data)[i]);
881 offset += 3;
882 }
883 return buffer;
884}
885
886/************************************************************************/
891static int unquote_block(const char *const quoted_, void *dest,
892 int dest_length)
893{
894 int i, length, parsed, tmp;
895 char *endptr;
896 const char *quoted = quoted_;
897
898 parsed = sscanf(quoted, "%d", &length);
899
900 if (parsed != 1) {
901 log_error(_("Syntax error in attribute block."));
902 return 0;
903 }
904
905 if (length > dest_length) {
906 return 0;
907 }
908
909 quoted = strchr(quoted, ':');
910
911 if (quoted == NULL) {
912 log_error(_("Syntax error in attribute block."));
913 return 0;
914 }
915
916 quoted++;
917
918 for (i = 0; i < length; i++) {
919 tmp = strtol(quoted, &endptr, 16);
920
921 if ((endptr - quoted) != 2
922 || *endptr != ' '
923 || (tmp & 0xff) != tmp) {
924 log_error(_("Syntax error in attribute block."));
925 return 0;
926 }
927
928 ((unsigned char *) dest)[i] = tmp;
929 quoted += 3;
930 }
931
932 return length;
933}
934
935/************************************************************************/
939static void worklist_load(struct section_file *file, int wlist_max_length,
940 struct worklist *pwl, const char *path, ...)
941{
942 int i;
943 const char *kind;
944 const char *name;
945 char path_str[1024];
946 va_list ap;
947
948 /* The first part of the registry path is taken from the varargs to the
949 * function. */
950 va_start(ap, path);
951 fc_vsnprintf(path_str, sizeof(path_str), path, ap);
952 va_end(ap);
953
954 worklist_init(pwl);
956 "%s.wl_length", path_str);
957
958 for (i = 0; i < pwl->length; i++) {
959 kind = secfile_lookup_str(file, "%s.wl_kind%d", path_str, i);
960
961 /* We lookup the production value by name. An invalid entry isn't a
962 * fatal error; we just truncate the worklist. */
963 name = secfile_lookup_str_default(file, "-", "%s.wl_value%d",
964 path_str, i);
965 pwl->entries[i] = universal_by_rule_name(kind, name);
966 if (pwl->entries[i].kind == universals_n_invalid()) {
967 log_sg("%s.wl_value%d: unknown \"%s\" \"%s\".", path_str, i, kind,
968 name);
969 pwl->length = i;
970 break;
971 }
972 }
973
974 /* Padding entries */
975 for (; i < wlist_max_length; i++) {
976 (void) secfile_entry_lookup(file, "%s.wl_kind%d", path_str, i);
977 (void) secfile_entry_lookup(file, "%s.wl_value%d", path_str, i);
978 }
979}
980
981/************************************************************************/
985static void worklist_save(struct section_file *file,
986 const struct worklist *pwl,
987 int max_length, const char *path, ...)
988{
989 char path_str[1024];
990 int i;
991 va_list ap;
992
993 /* The first part of the registry path is taken from the varargs to the
994 * function. */
995 va_start(ap, path);
996 fc_vsnprintf(path_str, sizeof(path_str), path, ap);
997 va_end(ap);
998
999 secfile_insert_int(file, pwl->length, "%s.wl_length", path_str);
1000
1001 for (i = 0; i < pwl->length; i++) {
1002 const struct universal *entry = pwl->entries + i;
1004 "%s.wl_kind%d", path_str, i);
1006 "%s.wl_value%d", path_str, i);
1007 }
1008
1009 fc_assert_ret(max_length <= MAX_LEN_WORKLIST);
1010
1011 /* We want to keep savegame in tabular format, so each line has to be
1012 * of equal length. Fill table up to maximum worklist size. */
1013 for (i = pwl->length ; i < max_length; i++) {
1014 secfile_insert_str(file, "", "%s.wl_kind%d", path_str, i);
1015 secfile_insert_str(file, "", "%s.wl_value%d", path_str, i);
1016 }
1017}
1018
1019/************************************************************************/
1023static void unit_ordering_calc(void)
1024{
1025 int j;
1026
1027 players_iterate(pplayer) {
1028 /* to avoid junk values for unsupported units: */
1029 unit_list_iterate(pplayer->units, punit) {
1030 punit->server.ord_city = 0;
1032 city_list_iterate(pplayer->cities, pcity) {
1033 j = 0;
1034 unit_list_iterate(pcity->units_supported, punit) {
1035 punit->server.ord_city = j++;
1039
1040 whole_map_iterate(&(wld.map), ptile) {
1041 j = 0;
1042 unit_list_iterate(ptile->units, punit) {
1043 punit->server.ord_map = j++;
1046}
1047
1048/************************************************************************/
1052static void unit_ordering_apply(void)
1053{
1054 players_iterate(pplayer) {
1055 city_list_iterate(pplayer->cities, pcity) {
1056 unit_list_sort_ord_city(pcity->units_supported);
1057 }
1060
1061 whole_map_iterate(&(wld.map), ptile) {
1062 unit_list_sort_ord_map(ptile->units);
1064}
1065
1066/************************************************************************/
1073static void sg_extras_set(bv_extras *extras, char ch, struct extra_type **idx)
1074{
1075 int i, bin;
1076 const char *pch = strchr(hex_chars, ch);
1077
1078 if (!pch || ch == '\0') {
1079 log_sg("Unknown hex value: '%c' (%d)", ch, ch);
1080 bin = 0;
1081 } else {
1082 bin = pch - hex_chars;
1083 }
1084
1085 for (i = 0; i < 4; i++) {
1086 struct extra_type *pextra = idx[i];
1087
1088 if (pextra == NULL) {
1089 continue;
1090 }
1091 if ((bin & (1 << i))
1092 && (wld.map.server.have_huts || !is_extra_caused_by(pextra, EC_HUT))) {
1093 BV_SET(*extras, extra_index(pextra));
1094 }
1095 }
1096}
1097
1098/************************************************************************/
1104static char sg_extras_get(bv_extras extras, struct extra_type *presource,
1105 const int *idx)
1106{
1107 int i, bin = 0;
1108
1109 for (i = 0; i < 4; i++) {
1110 int extra = idx[i];
1111
1112 if (extra < 0) {
1113 break;
1114 }
1115
1116 if (BV_ISSET(extras, extra)
1117 /* An invalid resource, a resource that can't exist at the tile's
1118 * current terrain, isn't in the bit extra vector. Save it so it
1119 * can return if the tile's terrain changes to something it can
1120 * exist on. */
1121 || extra_by_number(extra) == presource) {
1122 bin |= (1 << i);
1123 }
1124 }
1125
1126 return hex_chars[bin];
1127}
1128
1129/************************************************************************/
1133static struct terrain *char2terrain(char ch)
1134{
1135 /* terrain_by_identifier plus fatal error */
1136 if (ch == TERRAIN_UNKNOWN_IDENTIFIER) {
1137 return T_UNKNOWN;
1138 }
1139 terrain_type_iterate(pterrain) {
1140 if (pterrain->identifier_load == ch) {
1141 return pterrain;
1142 }
1144
1145 log_fatal("Unknown terrain identifier '%c' in savegame.", ch);
1146
1147 exit(EXIT_FAILURE);
1148
1150}
1151
1152/************************************************************************/
1156static char terrain2char(const struct terrain *pterrain)
1157{
1158 if (pterrain == T_UNKNOWN) {
1160 } else {
1161 return pterrain->identifier;
1162 }
1163}
1164
1165/************************************************************************/
1170 const char *path, int plrno)
1171{
1172 char path_with_name[128];
1173 const char *name;
1174 struct advance *padvance;
1175
1176 fc_snprintf(path_with_name, sizeof(path_with_name),
1177 "%s_name", path);
1178
1179 name = secfile_lookup_str(file, path_with_name, plrno);
1180
1181 if (!name || name[0] == '\0') {
1182 /* used by researching_saved */
1183 return A_UNKNOWN;
1184 }
1185 if (fc_strcasecmp(name, "A_FUTURE") == 0) {
1186 return A_FUTURE;
1187 }
1188 if (fc_strcasecmp(name, "A_NONE") == 0) {
1189 return A_NONE;
1190 }
1191 if (fc_strcasecmp(name, "A_UNSET") == 0) {
1192 return A_UNSET;
1193 }
1194
1195 padvance = advance_by_rule_name(name);
1196 sg_failure_ret_val(NULL != padvance, A_NONE,
1197 "%s: unknown technology \"%s\".", path_with_name, name);
1198
1199 return advance_number(padvance);
1200}
1201
1202/************************************************************************/
1205static void technology_save(struct section_file *file,
1206 const char *path, int plrno, Tech_type_id tech)
1207{
1208 char path_with_name[128];
1209 const char *name;
1210
1211 fc_snprintf(path_with_name, sizeof(path_with_name),
1212 "%s_name", path);
1213
1214 switch (tech) {
1215 case A_UNKNOWN: /* used by researching_saved */
1216 name = "";
1217 break;
1218 case A_NONE:
1219 name = "A_NONE";
1220 break;
1221 case A_UNSET:
1222 name = "A_UNSET";
1223 break;
1224 case A_FUTURE:
1225 name = "A_FUTURE";
1226 break;
1227 default:
1229 break;
1230 }
1231
1232 secfile_insert_str(file, name, path_with_name, plrno);
1233}
1234
1235/* =======================================================================
1236 * Load / save savefile data.
1237 * ======================================================================= */
1238
1239/************************************************************************/
1242static void sg_load_savefile(struct loaddata *loading)
1243{
1244 int i;
1245 const char *terr_name;
1246 bool ruleset_datafile;
1247 bool current_ruleset_rejected;
1248
1249 /* Check status and return if not OK (sg_success FALSE). */
1250 sg_check_ret();
1251
1252 /* Load savefile options. */
1253 loading->secfile_options
1254 = secfile_lookup_str(loading->file, "savefile.options");
1255
1256 /* We don't need these entries, but read them anyway to avoid
1257 * warnings about unread secfile entries. */
1258 (void) secfile_entry_by_path(loading->file, "savefile.reason");
1259 (void) secfile_entry_by_path(loading->file, "savefile.revision");
1260
1261 if (game.scenario.datafile[0] != '\0') {
1262 ruleset_datafile = FALSE;
1263 } else {
1264 ruleset_datafile = TRUE;
1265 }
1266
1267 current_ruleset_rejected = FALSE;
1269 const char *req_caps;
1270
1271 if (!load_rulesets(NULL, NULL, FALSE, NULL, TRUE, FALSE,
1272 ruleset_datafile)) {
1273 /* Failed to load correct ruleset */
1274 sg_failure_ret(FALSE, _("Failed to load ruleset '%s'."),
1276 }
1277
1278 req_caps = secfile_lookup_str_default(loading->file, "",
1279 "scenario.ruleset_caps");
1280 strncpy(game.scenario.req_caps, req_caps,
1281 sizeof(game.scenario.req_caps) - 1);
1282 game.scenario.req_caps[sizeof(game.scenario.req_caps) - 1] = '\0';
1283
1284 if (!has_capabilities(req_caps, game.ruleset_capabilities)) {
1285 /* Current ruleset lacks required capabilities. */
1286 log_normal(_("Scenario requires ruleset capabilities: %s"), req_caps);
1287 log_normal(_("Ruleset has capabilities: %s"),
1289 /* TRANS: ... ruleset dir ... scenario name ... */
1290 log_error(_("Current ruleset %s not compatible with the scenario %s."
1291 " Trying to switch to the ruleset specified by the"
1292 " scenario."),
1294
1295 current_ruleset_rejected = TRUE;
1296 }
1297 }
1298
1300 || current_ruleset_rejected) {
1301 const char *ruleset, *alt_dir;
1302
1305 "savefile.rulesetdir");
1306
1307 /* Load ruleset. */
1309 if (!strcmp("default", game.server.rulesetdir)) {
1310 /* Here 'default' really means current default.
1311 * Saving happens with real ruleset name, so savegames containing this
1312 * are special scenarios. */
1314 log_verbose("Savegame specified ruleset '%s'. Really loading '%s'.",
1316 }
1317
1318 alt_dir = secfile_lookup_str_default(loading->file, NULL,
1319 "savefile.ruleset_alt_dir");
1320
1321 if (!load_rulesets(NULL, alt_dir, FALSE, NULL, TRUE, FALSE, ruleset_datafile)) {
1322 if (alt_dir) {
1324 _("Failed to load either of rulesets '%s' or '%s' "
1325 "needed for savegame."),
1326 ruleset, alt_dir);
1327 } else {
1329 _("Failed to load ruleset '%s' needed for savegame."),
1330 ruleset);
1331 }
1332 }
1333
1334 if (current_ruleset_rejected) {
1335 /* TRANS: ruleset dir */
1336 log_normal(_("Successfully loaded the scenario's ruleset %s."), ruleset);
1337 }
1338 }
1339
1340 /* Remove all aifill players. Correct number of them get created later
1341 * with correct skill level etc. */
1342 (void) aifill(0);
1343
1344 /* Time to load scenario specific luadata */
1345 if (game.scenario.datafile[0] != '\0') {
1346 if (!fc_strcasecmp("none", game.scenario.datafile)) {
1347 game.server.luadata = NULL;
1348 } else {
1349 const struct strvec *paths[] = { get_scenario_dirs(), NULL };
1350 const struct strvec **path;
1351 const char *found = NULL;
1352 char testfile[MAX_LEN_PATH];
1353 struct section_file *secfile;
1354
1355 for (path = paths; found == NULL && *path != NULL; path++) {
1356 fc_snprintf(testfile, sizeof(testfile), "%s.luadata", game.scenario.datafile);
1357
1358 found = fileinfoname(*path, testfile);
1359 }
1360
1361 if (found == NULL) {
1362 log_error(_("Can't find scenario luadata file %s.luadata."), game.scenario.datafile);
1363 sg_success = FALSE;
1364 return;
1365 }
1366
1367 secfile = secfile_load(found, FALSE);
1368 if (secfile == NULL) {
1369 log_error(_("Failed to load scenario luadata file %s.luadata"),
1371 sg_success = FALSE;
1372 return;
1373 }
1374
1375 game.server.luadata = secfile;
1376 }
1377 }
1378
1379 /* This is in the savegame only if the game has been started before savegame3.c time,
1380 * and in that case it's TRUE. If it's missing, it's to be considered FALSE. */
1382 "savefile.last_updated_as_year");
1383
1384 /* Load improvements. */
1385 loading->improvement.size
1386 = secfile_lookup_int_default(loading->file, 0,
1387 "savefile.improvement_size");
1388 if (loading->improvement.size) {
1389 loading->improvement.order
1390 = secfile_lookup_str_vec(loading->file, &loading->improvement.size,
1391 "savefile.improvement_vector");
1392 sg_failure_ret(loading->improvement.size != 0,
1393 "Failed to load improvement order: %s",
1394 secfile_error());
1395 }
1396
1397 /* Load technologies. */
1398 loading->technology.size
1399 = secfile_lookup_int_default(loading->file, 0,
1400 "savefile.technology_size");
1401 if (loading->technology.size) {
1402 loading->technology.order
1403 = secfile_lookup_str_vec(loading->file, &loading->technology.size,
1404 "savefile.technology_vector");
1405 sg_failure_ret(loading->technology.size != 0,
1406 "Failed to load technology order: %s",
1407 secfile_error());
1408 }
1409
1410 /* Load Activities. */
1411 loading->activities.size
1412 = secfile_lookup_int_default(loading->file, 0,
1413 "savefile.activities_size");
1414 if (loading->activities.size) {
1415 loading->activities.order
1416 = secfile_lookup_str_vec(loading->file, &loading->activities.size,
1417 "savefile.activities_vector");
1418 sg_failure_ret(loading->activities.size != 0,
1419 "Failed to load activity order: %s",
1420 secfile_error());
1421 }
1422
1423 /* Load traits. */
1424 loading->trait.size
1425 = secfile_lookup_int_default(loading->file, 0,
1426 "savefile.trait_size");
1427 if (loading->trait.size) {
1428 loading->trait.order
1429 = secfile_lookup_str_vec(loading->file, &loading->trait.size,
1430 "savefile.trait_vector");
1431 sg_failure_ret(loading->trait.size != 0,
1432 "Failed to load trait order: %s",
1433 secfile_error());
1434 }
1435
1436 /* Load extras. */
1437 loading->extra.size
1438 = secfile_lookup_int_default(loading->file, 0,
1439 "savefile.extras_size");
1440 if (loading->extra.size) {
1441 const char **modname;
1442 size_t nmod;
1443 int j;
1444
1445 modname = secfile_lookup_str_vec(loading->file, &loading->extra.size,
1446 "savefile.extras_vector");
1447 sg_failure_ret(loading->extra.size != 0,
1448 "Failed to load extras order: %s",
1449 secfile_error());
1451 "Number of extras defined by the ruleset (= %d) are "
1452 "lower than the number in the savefile (= %d).",
1453 game.control.num_extra_types, (int)loading->extra.size);
1454 /* make sure that the size of the array is divisible by 4 */
1455 nmod = 4 * ((loading->extra.size + 3) / 4);
1456 loading->extra.order = fc_calloc(nmod, sizeof(*loading->extra.order));
1457 for (j = 0; j < loading->extra.size; j++) {
1458 loading->extra.order[j] = extra_type_by_rule_name(modname[j]);
1459 }
1460 free(modname);
1461 for (; j < nmod; j++) {
1462 loading->extra.order[j] = NULL;
1463 }
1464 }
1465
1466 /* Load multipliers. */
1467 loading->multiplier.size
1468 = secfile_lookup_int_default(loading->file, 0,
1469 "savefile.multipliers_size");
1470 if (loading->multiplier.size) {
1471 const char **modname;
1472 int j;
1473
1474 modname = secfile_lookup_str_vec(loading->file, &loading->multiplier.size,
1475 "savefile.multipliers_vector");
1476 sg_failure_ret(loading->multiplier.size != 0,
1477 "Failed to load multipliers order: %s",
1478 secfile_error());
1479 /* It's OK for the set of multipliers in the savefile to differ
1480 * from those in the ruleset. */
1481 loading->multiplier.order = fc_calloc(loading->multiplier.size,
1482 sizeof(*loading->multiplier.order));
1483 for (j = 0; j < loading->multiplier.size; j++) {
1484 loading->multiplier.order[j] = multiplier_by_rule_name(modname[j]);
1485 if (!loading->multiplier.order[j]) {
1486 log_verbose("Multiplier \"%s\" in savegame but not in ruleset, "
1487 "discarding", modname[j]);
1488 }
1489 }
1490 free(modname);
1491 }
1492
1493 /* Load specialists. */
1494 loading->specialist.size
1495 = secfile_lookup_int_default(loading->file, 0,
1496 "savefile.specialists_size");
1497 if (loading->specialist.size) {
1498 const char **modname;
1499 size_t nmod;
1500 int j;
1501
1502 modname = secfile_lookup_str_vec(loading->file, &loading->specialist.size,
1503 "savefile.specialists_vector");
1504 sg_failure_ret(loading->specialist.size != 0,
1505 "Failed to load specialists order: %s",
1506 secfile_error());
1508 "Number of specialists defined by the ruleset (= %d) are "
1509 "lower than the number in the savefile (= %d).",
1511 /* make sure that the size of the array is divisible by 4 */
1512 /* That's not really needed with specialists at the moment, but done this way
1513 * for consistency with other types, and to be prepared for the time it needs
1514 * to be this way. */
1515 nmod = 4 * ((loading->specialist.size + 3) / 4);
1516 loading->specialist.order = fc_calloc(nmod, sizeof(*loading->specialist.order));
1517 for (j = 0; j < loading->specialist.size; j++) {
1518 loading->specialist.order[j] = specialist_by_rule_name(modname[j]);
1519 }
1520 free(modname);
1521 for (; j < nmod; j++) {
1522 loading->specialist.order[j] = NULL;
1523 }
1524 }
1525
1526 /* Not used by this freeciv version - for future use */
1527 {
1528 int j;
1529
1530 i = secfile_lookup_int_default(loading->file, 0, "savefile.diplstate_type_size");
1531 for (j = 0; j < i; j++) {
1532 (void) secfile_entry_lookup(loading->file,
1533 "savefile.diplstate_type_vector,%d", j);
1534 }
1535 }
1536
1537 /* Load action order. */
1538 loading->action.size = secfile_lookup_int_default(loading->file, 0,
1539 "savefile.action_size");
1540
1541 sg_failure_ret(loading->action.size > 0,
1542 "Failed to load action order: %s",
1543 secfile_error());
1544
1545 if (loading->action.size) {
1546 const char **modname;
1547 int j;
1548
1549 modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
1550 "savefile.action_vector");
1551
1552 loading->action.order = fc_calloc(loading->action.size,
1553 sizeof(*loading->action.order));
1554
1555 for (j = 0; j < loading->action.size; j++) {
1556 struct action *real_action = action_by_rule_name(modname[j]);
1557
1558 if (real_action) {
1559 loading->action.order[j] = real_action->id;
1560 } else {
1561 log_sg("Unknown action \'%s\'", modname[j]);
1562 loading->action.order[j] = ACTION_NONE;
1563 }
1564 }
1565
1566 free(modname);
1567 }
1568
1569 /* Load action decision order. */
1570 loading->act_dec.size
1571 = secfile_lookup_int_default(loading->file, 0,
1572 "savefile.action_decision_size");
1573
1574 sg_failure_ret(loading->act_dec.size > 0,
1575 "Failed to load action decision order: %s",
1576 secfile_error());
1577
1578 if (loading->act_dec.size) {
1579 const char **modname;
1580 int j;
1581
1582 modname = secfile_lookup_str_vec(loading->file, &loading->act_dec.size,
1583 "savefile.action_decision_vector");
1584
1585 loading->act_dec.order = fc_calloc(loading->act_dec.size,
1586 sizeof(*loading->act_dec.order));
1587
1588 for (j = 0; j < loading->act_dec.size; j++) {
1589 loading->act_dec.order[j] = action_decision_by_name(modname[j],
1591 }
1592
1593 free(modname);
1594 }
1595
1596 /* Load server side agent order. */
1597 loading->ssa.size
1598 = secfile_lookup_int_default(loading->file, 0,
1599 "savefile.server_side_agent_size");
1600
1601 sg_failure_ret(loading->ssa.size > 0,
1602 "Failed to load server side agent order: %s",
1603 secfile_error());
1604
1605 if (loading->ssa.size) {
1606 const char **modname;
1607 int j;
1608
1609 modname = secfile_lookup_str_vec(loading->file, &loading->ssa.size,
1610 "savefile.server_side_agent_list");
1611
1612 loading->ssa.order = fc_calloc(loading->ssa.size,
1613 sizeof(*loading->ssa.order));
1614
1615 for (j = 0; j < loading->ssa.size; j++) {
1616 loading->ssa.order[j] = server_side_agent_by_name(modname[j],
1618 }
1619
1620 free(modname);
1621 }
1622
1623 /* Not used by this freeciv version - for future use */
1624 {
1625 int j;
1626
1627 i = secfile_lookup_int_default(loading->file, 0, "savefile.city_options_size");
1628 for (j = 0; j < i; j++) {
1629 (void) secfile_entry_lookup(loading->file, "savefile.city_options_vector,%d", j);
1630 }
1631 }
1632
1633 terrain_type_iterate(pterr) {
1634 pterr->identifier_load = '\0';
1636
1637 i = 0;
1638 while ((terr_name = secfile_lookup_str_default(loading->file, NULL,
1639 "savefile.terrident%d.name", i)) != NULL) {
1640 struct terrain *pterr = terrain_by_rule_name(terr_name);
1641
1642 if (pterr != NULL) {
1643 const char *iptr = secfile_lookup_str_default(loading->file, NULL,
1644 "savefile.terrident%d.identifier", i);
1645
1646 pterr->identifier_load = *iptr;
1647 } else {
1648 log_error("Identifier for unknown terrain type %s.", terr_name);
1649 }
1650 i++;
1651 }
1652
1653 terrain_type_iterate(pterr) {
1654 terrain_type_iterate(pterr2) {
1655 if (pterr != pterr2 && pterr->identifier_load != '\0') {
1656 sg_failure_ret((pterr->identifier_load != pterr2->identifier_load),
1657 "%s and %s share a saved identifier",
1658 terrain_rule_name(pterr), terrain_rule_name(pterr2));
1659 }
1662}
1663
1664/************************************************************************/
1667static void sg_save_savefile(struct savedata *saving)
1668{
1669 int i;
1670
1671 /* Check status and return if not OK (sg_success FALSE). */
1672 sg_check_ret();
1673
1674 /* Save savefile options. */
1676
1677 secfile_insert_int(saving->file, current_compat_ver(), "savefile.version");
1678
1679 /* Save reason of the savefile generation. */
1680 secfile_insert_str(saving->file, saving->save_reason, "savefile.reason");
1681
1682 /* Save as accurate freeciv revision information as possible */
1683 secfile_insert_str(saving->file, freeciv_datafile_version(), "savefile.revision");
1684
1685 /* Save rulesetdir at this point as this ruleset is required by this
1686 * savefile. */
1687 secfile_insert_str(saving->file, game.server.rulesetdir, "savefile.rulesetdir");
1688
1689 if (game.control.version[0] != '\0') {
1690 /* Current ruleset has version information, save it.
1691 * This is never loaded, but exist in savegame file only for debugging purposes. */
1692 secfile_insert_str(saving->file, game.control.version, "savefile.rulesetversion");
1693 }
1694
1695 if (game.control.alt_dir[0] != '\0') {
1696 secfile_insert_str(saving->file, game.control.alt_dir, "savefile.ruleset_alt_dir");
1697 }
1698
1700 secfile_insert_bool(saving->file, TRUE, "savefile.last_updated_as_year");
1701 }
1702
1703 /* Save improvement order in savegame, so we are not dependent on ruleset
1704 * order. If the game isn't started improvements aren't loaded so we can
1705 * not save the order. */
1707 "savefile.improvement_size");
1708 if (improvement_count() > 0) {
1709 const char *buf[improvement_count()];
1710
1711 improvement_iterate(pimprove) {
1712 buf[improvement_index(pimprove)] = improvement_rule_name(pimprove);
1714
1716 "savefile.improvement_vector");
1717 }
1718
1719 /* Save technology order in savegame, so we are not dependent on ruleset
1720 * order. If the game isn't started advances aren't loaded so we can not
1721 * save the order. */
1723 "savefile.technology_size");
1724 if (game.control.num_tech_types > 0) {
1725 const char *buf[game.control.num_tech_types];
1726
1727 buf[A_NONE] = "A_NONE";
1729 buf[advance_index(a)] = advance_rule_name(a);
1732 "savefile.technology_vector");
1733 }
1734
1735 /* Save activities order in the savegame. */
1736 secfile_insert_int(saving->file, ACTIVITY_LAST,
1737 "savefile.activities_size");
1738 if (ACTIVITY_LAST > 0) {
1739 const char **modname;
1740 int j;
1741
1742 i = 0;
1743
1744 modname = fc_calloc(ACTIVITY_LAST, sizeof(*modname));
1745
1746 for (j = 0; j < ACTIVITY_LAST; j++) {
1747 modname[i++] = unit_activity_name(j);
1748 }
1749
1750 secfile_insert_str_vec(saving->file, modname,
1751 ACTIVITY_LAST,
1752 "savefile.activities_vector");
1753 free(modname);
1754 }
1755
1756 /* Save specialists order in the savegame. */
1758 "savefile.specialists_size");
1759 {
1760 const char **modname;
1761
1762 i = 0;
1763 modname = fc_calloc(specialist_count(), sizeof(*modname));
1764
1766 modname[i++] = specialist_rule_name(specialist_by_number(sp));
1768
1769 secfile_insert_str_vec(saving->file, modname, specialist_count(),
1770 "savefile.specialists_vector");
1771
1772 free(modname);
1773 }
1774
1775 /* Save trait order in savegame. */
1776 secfile_insert_int(saving->file, TRAIT_COUNT,
1777 "savefile.trait_size");
1778 {
1779 const char **modname;
1780 enum trait tr;
1781 int j;
1782
1783 modname = fc_calloc(TRAIT_COUNT, sizeof(*modname));
1784
1785 for (tr = trait_begin(), j = 0; tr != trait_end(); tr = trait_next(tr), j++) {
1786 modname[j] = trait_name(tr);
1787 }
1788
1789 secfile_insert_str_vec(saving->file, modname, TRAIT_COUNT,
1790 "savefile.trait_vector");
1791 free(modname);
1792 }
1793
1794 /* Save extras order in the savegame. */
1796 "savefile.extras_size");
1797 if (game.control.num_extra_types > 0) {
1798 const char **modname;
1799
1800 i = 0;
1801 modname = fc_calloc(game.control.num_extra_types, sizeof(*modname));
1802
1803 extra_type_iterate(pextra) {
1804 modname[i++] = extra_rule_name(pextra);
1806
1807 secfile_insert_str_vec(saving->file, modname,
1809 "savefile.extras_vector");
1810 free(modname);
1811 }
1812
1813 /* Save multipliers order in the savegame. */
1815 "savefile.multipliers_size");
1816 if (multiplier_count() > 0) {
1817 const char **modname;
1818
1819 modname = fc_calloc(multiplier_count(), sizeof(*modname));
1820
1821 multipliers_iterate(pmul) {
1822 modname[multiplier_index(pmul)] = multiplier_rule_name(pmul);
1824
1825 secfile_insert_str_vec(saving->file, modname,
1827 "savefile.multipliers_vector");
1828 free(modname);
1829 }
1830
1831 /* Save diplstate type order in the savegame. */
1832 secfile_insert_int(saving->file, DS_LAST,
1833 "savefile.diplstate_type_size");
1834 if (DS_LAST > 0) {
1835 const char **modname;
1836 int j;
1837
1838 i = 0;
1839 modname = fc_calloc(DS_LAST, sizeof(*modname));
1840
1841 for (j = 0; j < DS_LAST; j++) {
1842 modname[i++] = diplstate_type_name(j);
1843 }
1844
1845 secfile_insert_str_vec(saving->file, modname,
1846 DS_LAST,
1847 "savefile.diplstate_type_vector");
1848 free(modname);
1849 }
1850
1851 /* Save city_option order in the savegame. */
1852 secfile_insert_int(saving->file, CITYO_LAST,
1853 "savefile.city_options_size");
1854 if (CITYO_LAST > 0) {
1855 const char **modname;
1856 int j;
1857
1858 i = 0;
1859 modname = fc_calloc(CITYO_LAST, sizeof(*modname));
1860
1861 for (j = 0; j < CITYO_LAST; j++) {
1862 modname[i++] = city_options_name(j);
1863 }
1864
1865 secfile_insert_str_vec(saving->file, modname,
1866 CITYO_LAST,
1867 "savefile.city_options_vector");
1868 free(modname);
1869 }
1870
1871 /* Save action order in the savegame. */
1873 "savefile.action_size");
1874 if (NUM_ACTIONS > 0) {
1875 const char **modname;
1876 int j;
1877
1878 i = 0;
1879 modname = fc_calloc(NUM_ACTIONS, sizeof(*modname));
1880
1881 for (j = 0; j < NUM_ACTIONS; j++) {
1882 modname[i++] = action_id_rule_name(j);
1883 }
1884
1885 secfile_insert_str_vec(saving->file, modname,
1887 "savefile.action_vector");
1888 free(modname);
1889 }
1890
1891 /* Save action decision order in the savegame. */
1892 secfile_insert_int(saving->file, ACT_DEC_COUNT,
1893 "savefile.action_decision_size");
1894 if (ACT_DEC_COUNT > 0) {
1895 const char **modname;
1896 int j;
1897
1898 i = 0;
1899 modname = fc_calloc(ACT_DEC_COUNT, sizeof(*modname));
1900
1901 for (j = 0; j < ACT_DEC_COUNT; j++) {
1902 modname[i++] = action_decision_name(j);
1903 }
1904
1905 secfile_insert_str_vec(saving->file, modname,
1906 ACT_DEC_COUNT,
1907 "savefile.action_decision_vector");
1908 free(modname);
1909 }
1910
1911 /* Save server side agent order in the savegame. */
1912 secfile_insert_int(saving->file, SSA_COUNT,
1913 "savefile.server_side_agent_size");
1914 if (SSA_COUNT > 0) {
1915 const char **modname;
1916 int j;
1917
1918 i = 0;
1919 modname = fc_calloc(SSA_COUNT, sizeof(*modname));
1920
1921 for (j = 0; j < SSA_COUNT; j++) {
1922 modname[i++] = server_side_agent_name(j);
1923 }
1924
1925 secfile_insert_str_vec(saving->file, modname,
1926 SSA_COUNT,
1927 "savefile.server_side_agent_list");
1928 free(modname);
1929 }
1930
1931 /* Save terrain character mapping in the savegame. */
1932 i = 0;
1933 terrain_type_iterate(pterr) {
1934 char buf[2];
1935
1936 secfile_insert_str(saving->file, terrain_rule_name(pterr), "savefile.terrident%d.name", i);
1937 buf[0] = terrain_identifier(pterr);
1938 buf[1] = '\0';
1939 secfile_insert_str(saving->file, buf, "savefile.terrident%d.identifier", i++);
1941}
1942
1943/************************************************************************/
1946static void sg_save_savefile_options(struct savedata *saving,
1947 const char *option)
1948{
1949 /* Check status and return if not OK (sg_success FALSE). */
1950 sg_check_ret();
1951
1952 if (option == NULL) {
1953 /* no additional option */
1954 return;
1955 }
1956
1958 secfile_replace_str(saving->file, saving->secfile_options,
1959 "savefile.options");
1960}
1961
1962/* =======================================================================
1963 * Load / save game status.
1964 * ======================================================================= */
1965
1966/************************************************************************/
1969static void sg_load_ruledata(struct loaddata *loading)
1970{
1971 int i;
1972 const char *name;
1973
1974 /* Check status and return if not OK (sg_success FALSE). */
1975 sg_check_ret();
1976
1977 for (i = 0;
1978 (name = secfile_lookup_str_default(loading->file, NULL,
1979 "ruledata.government%d.name", i));
1980 i++) {
1982
1983 if (gov != NULL) {
1985 "ruledata.government%d.changes", i);
1986 }
1987 }
1988}
1989
1990/************************************************************************/
1993static void sg_load_game(struct loaddata *loading)
1994{
1995 const char *str;
1996 const char *level;
1997 int i;
1998
1999 /* Check status and return if not OK (sg_success FALSE). */
2000 sg_check_ret();
2001
2002 /* Load server state. */
2003 str = secfile_lookup_str_default(loading->file, "S_S_INITIAL",
2004 "game.server_state");
2005 loading->server_state = server_states_by_name(str, strcmp);
2006 if (!server_states_is_valid(loading->server_state)) {
2007 /* Don't take any risk! */
2008 loading->server_state = S_S_INITIAL;
2009 }
2010
2012 = secfile_lookup_int_default(loading->file, 0, "game.phase_seconds");
2013
2016 "game.meta_patches");
2018
2020 /* Do not overwrite this if the user requested a specific metaserver
2021 * from the command line (option --Metaserver). */
2025 "game.meta_server"));
2026 }
2027
2028 if ('\0' == srvarg.serverid[0]) {
2029 /* Do not overwrite this if the user requested a specific metaserver
2030 * from the command line (option --serverid). */
2032 secfile_lookup_str_default(loading->file, "",
2033 "game.serverid"));
2034 }
2035 sz_strlcpy(server.game_identifier,
2036 secfile_lookup_str_default(loading->file, "", "game.id"));
2037 /* We are not checking game_identifier legality just yet.
2038 * That's done when we are sure that rand seed has been initialized,
2039 * so that we can generate new game_identifier, if needed.
2040 * See sq_load_sanitycheck(). */
2041
2042 level = secfile_lookup_str_default(loading->file, NULL,
2043 "game.level");
2044 if (level != NULL && !fc_strcasecmp("Handicapped", level)) {
2045 /* Up to freeciv-3.1 Restricted AI level was known as Handicapped */
2046 game.info.skill_level = AI_LEVEL_RESTRICTED;
2047 } else {
2048 game.info.skill_level = ai_level_by_name(level, fc_strcasecmp);
2049 }
2050
2051 if (!ai_level_is_valid(game.info.skill_level)) {
2052 log_sg("Invalid AI level \"%s\". "
2053 "Changed to \"%s\".", level,
2054 ai_level_name(GAME_HARDCODED_DEFAULT_SKILL_LEVEL));
2056 }
2057
2058 str = secfile_lookup_str_default(loading->file, NULL,
2059 "game.phase_mode");
2060 if (str != NULL) {
2061 game.info.phase_mode = phase_mode_type_by_name(str, fc_strcasecmp);
2062 if (!phase_mode_type_is_valid(game.info.phase_mode)) {
2063 log_error("Illegal phase mode \"%s\"", str);
2065 }
2066 } else {
2067 log_error("Phase mode missing");
2068 }
2069
2070 str = secfile_lookup_str_default(loading->file, NULL,
2071 "game.phase_mode_stored");
2072 if (str != NULL) {
2073 game.server.phase_mode_stored = phase_mode_type_by_name(str, fc_strcasecmp);
2074 if (!phase_mode_type_is_valid(game.server.phase_mode_stored)) {
2075 log_error("Illegal stored phase mode \"%s\"", str);
2077 }
2078 } else {
2079 log_error("Stored phase mode missing");
2080 }
2082 = secfile_lookup_int_default(loading->file, 0,
2083 "game.phase");
2087 "game.scoreturn");
2088
2091 "game.timeoutint");
2094 "game.timeoutintinc");
2097 "game.timeoutinc");
2100 "game.timeoutincmult");
2103 "game.timeoutcounter");
2104
2105 game.info.turn
2106 = secfile_lookup_int_default(loading->file, 0, "game.turn");
2108 "game.year"), "%s", secfile_error());
2110 = secfile_lookup_bool_default(loading->file, FALSE, "game.year_0_hack");
2111
2113 = secfile_lookup_int_default(loading->file, 0, "game.globalwarming");
2115 = secfile_lookup_int_default(loading->file, 0, "game.heating");
2117 = secfile_lookup_int_default(loading->file, 0, "game.warminglevel");
2118
2120 = secfile_lookup_int_default(loading->file, 0, "game.nuclearwinter");
2122 = secfile_lookup_int_default(loading->file, 0, "game.cooling");
2124 = secfile_lookup_int_default(loading->file, 0, "game.coolinglevel");
2125
2126 /* Savegame may have stored random_seed for documentation purposes only,
2127 * but we want to keep it for resaving. */
2128 game.server.seed = secfile_lookup_int_default(loading->file, 0, "game.random_seed");
2129
2130 /* Global advances. */
2131 str = secfile_lookup_str_default(loading->file, NULL,
2132 "game.global_advances");
2133 if (str != NULL) {
2134 sg_failure_ret(strlen(str) == loading->technology.size,
2135 "Invalid length of 'game.global_advances' ("
2136 SIZE_T_PRINTF " ~= " SIZE_T_PRINTF ").",
2137 strlen(str), loading->technology.size);
2138 for (i = 0; i < loading->technology.size; i++) {
2139 sg_failure_ret(str[i] == '1' || str[i] == '0',
2140 "Undefined value '%c' within 'game.global_advances'.",
2141 str[i]);
2142 if (str[i] == '1') {
2143 struct advance *padvance =
2145
2146 if (padvance != NULL) {
2148 }
2149 }
2150 }
2151 }
2152
2154 = !secfile_lookup_bool_default(loading->file, TRUE, "game.save_players");
2155
2157 = secfile_lookup_int_default(loading->file, 0, "game.last_turn_change_time") / 100.0;
2158}
2159
2160/************************************************************************/
2163static void sg_save_ruledata(struct savedata *saving)
2164{
2165 int set_count = 0;
2166
2167 governments_iterate(pgov) {
2168 char path[256];
2169
2170 fc_snprintf(path, sizeof(path),
2171 "ruledata.government%d", set_count++);
2172
2174 "%s.name", path);
2175 secfile_insert_int(saving->file, pgov->changed_to_times,
2176 "%s.changes", path);
2178}
2179
2180/************************************************************************/
2183static void sg_save_game(struct savedata *saving)
2184{
2185 enum server_states srv_state;
2186 char global_advances[game.control.num_tech_types + 1];
2187 int i;
2188
2189 /* Check status and return if not OK (sg_success FALSE). */
2190 sg_check_ret();
2191
2192 /* Game state: once the game is no longer a new game (ie, has been
2193 * started the first time), it should always be considered a running
2194 * game for savegame purposes. */
2195 if (saving->scenario && !game.scenario.players) {
2196 srv_state = S_S_INITIAL;
2197 } else {
2198 srv_state = game.info.is_new_game ? server_state() : S_S_RUNNING;
2199 }
2200 secfile_insert_str(saving->file, server_states_name(srv_state),
2201 "game.server_state");
2202
2203 if (game.server.phase_timer != NULL) {
2204 secfile_insert_int(saving->file,
2207 "game.phase_seconds");
2208 }
2209
2211 "game.meta_patches");
2212 secfile_insert_str(saving->file, meta_addr_port(), "game.meta_server");
2213
2214 secfile_insert_str(saving->file, server.game_identifier, "game.id");
2215 secfile_insert_str(saving->file, srvarg.serverid, "game.serverid");
2216
2217 secfile_insert_str(saving->file, ai_level_name(game.info.skill_level),
2218 "game.level");
2219 secfile_insert_str(saving->file,
2220 phase_mode_type_name(game.info.phase_mode),
2221 "game.phase_mode");
2222 secfile_insert_str(saving->file,
2223 phase_mode_type_name(game.server.phase_mode_stored),
2224 "game.phase_mode_stored");
2226 "game.phase");
2228 "game.scoreturn");
2229
2231 "game.timeoutint");
2233 "game.timeoutintinc");
2235 "game.timeoutinc");
2237 "game.timeoutincmult");
2239 "game.timeoutcounter");
2240
2241 secfile_insert_int(saving->file, game.info.turn, "game.turn");
2242 secfile_insert_int(saving->file, game.info.year, "game.year");
2244 "game.year_0_hack");
2245
2247 "game.globalwarming");
2249 "game.heating");
2251 "game.warminglevel");
2252
2254 "game.nuclearwinter");
2256 "game.cooling");
2258 "game.coolinglevel");
2259 /* For debugging purposes only.
2260 * Do not save it if it's 0 (not known);
2261 * this confuses people reading this 'document' less than
2262 * saving 0. */
2263 if (game.server.seed != 0) {
2265 "game.random_seed");
2266 }
2267
2268 /* Global advances. */
2269 for (i = 0; i < game.control.num_tech_types; i++) {
2270 global_advances[i] = game.info.global_advances[i] ? '1' : '0';
2271 }
2272 global_advances[i] = '\0';
2273 secfile_insert_str(saving->file, global_advances, "game.global_advances");
2274
2275 if (!game_was_started()) {
2276 saving->save_players = FALSE;
2277 } else {
2278 if (saving->scenario) {
2280 } else {
2281 saving->save_players = TRUE;
2282 }
2283#ifndef SAVE_DUMMY_TURN_CHANGE_TIME
2285 "game.last_turn_change_time");
2286#else /* SAVE_DUMMY_TURN_CHANGE_TIME */
2287 secfile_insert_int(saving->file, game.info.turn * 10,
2288 "game.last_turn_change_time");
2289#endif /* SAVE_DUMMY_TURN_CHANGE_TIME */
2290 }
2291 secfile_insert_bool(saving->file, saving->save_players,
2292 "game.save_players");
2293
2294 if (srv_state != S_S_INITIAL) {
2295 const char *ainames[ai_type_get_count()];
2296
2297 i = 0;
2298 ai_type_iterate(ait) {
2299 ainames[i] = ait->name;
2300 i++;
2302
2303 secfile_insert_str_vec(saving->file, ainames, i,
2304 "game.ai_types");
2305 }
2306}
2307
2308/* =======================================================================
2309 * Load / save random status.
2310 * ======================================================================= */
2311
2312/************************************************************************/
2315static void sg_load_random(struct loaddata *loading)
2316{
2317 /* Check status and return if not OK (sg_success FALSE). */
2318 sg_check_ret();
2319
2320 if (secfile_lookup_bool_default(loading->file, FALSE, "random.saved")) {
2321 const char *str;
2322 int i;
2323
2324 sg_failure_ret(secfile_lookup_int(loading->file, &loading->rstate.j,
2325 "random.index_J"), "%s", secfile_error());
2326 sg_failure_ret(secfile_lookup_int(loading->file, &loading->rstate.k,
2327 "random.index_K"), "%s", secfile_error());
2328 sg_failure_ret(secfile_lookup_int(loading->file, &loading->rstate.x,
2329 "random.index_X"), "%s", secfile_error());
2330
2331 for (i = 0; i < 8; i++) {
2332 str = secfile_lookup_str(loading->file, "random.table%d",i);
2333 sg_failure_ret(NULL != str, "%s", secfile_error());
2334 sscanf(str, "%8x %8x %8x %8x %8x %8x %8x", &loading->rstate.v[7*i],
2335 &loading->rstate.v[7*i+1], &loading->rstate.v[7*i+2],
2336 &loading->rstate.v[7*i+3], &loading->rstate.v[7*i+4],
2337 &loading->rstate.v[7*i+5], &loading->rstate.v[7*i+6]);
2338 }
2339 loading->rstate.is_init = TRUE;
2340 fc_rand_set_state(loading->rstate);
2341 } else {
2342 /* No random values - mark the setting. */
2343 (void) secfile_entry_by_path(loading->file, "random.saved");
2344
2345 /* We're loading a game without a seed (which is okay, if it's a scenario).
2346 * We need to generate the game seed now because it will be needed later
2347 * during the load. */
2349 loading->rstate = fc_rand_state();
2350 }
2351}
2352
2353/************************************************************************/
2356static void sg_save_random(struct savedata *saving)
2357{
2358 /* Check status and return if not OK (sg_success FALSE). */
2359 sg_check_ret();
2360
2361 if (fc_rand_is_init() && (!saving->scenario || game.scenario.save_random)) {
2362 int i;
2363 RANDOM_STATE rstate = fc_rand_state();
2364
2365 secfile_insert_bool(saving->file, TRUE, "random.saved");
2366 fc_assert(rstate.is_init);
2367
2368 secfile_insert_int(saving->file, rstate.j, "random.index_J");
2369 secfile_insert_int(saving->file, rstate.k, "random.index_K");
2370 secfile_insert_int(saving->file, rstate.x, "random.index_X");
2371
2372 for (i = 0; i < 8; i++) {
2373 char vec[100];
2374
2375 fc_snprintf(vec, sizeof(vec),
2376 "%8x %8x %8x %8x %8x %8x %8x", rstate.v[7 * i],
2377 rstate.v[7 * i + 1], rstate.v[7 * i + 2],
2378 rstate.v[7 * i + 3], rstate.v[7 * i + 4],
2379 rstate.v[7 * i + 5], rstate.v[7 * i + 6]);
2380 secfile_insert_str(saving->file, vec, "random.table%d", i);
2381 }
2382 } else {
2383 secfile_insert_bool(saving->file, FALSE, "random.saved");
2384 }
2385}
2386
2387/* =======================================================================
2388 * Load / save lua script data.
2389 * ======================================================================= */
2390
2391/************************************************************************/
2394static void sg_load_script(struct loaddata *loading)
2395{
2396 /* Check status and return if not OK (sg_success FALSE). */
2397 sg_check_ret();
2398
2400}
2401
2402/************************************************************************/
2405static void sg_save_script(struct savedata *saving)
2406{
2407 /* Check status and return if not OK (sg_success FALSE). */
2408 sg_check_ret();
2409
2411}
2412
2413/* =======================================================================
2414 * Load / save scenario data.
2415 * ======================================================================= */
2416
2417/************************************************************************/
2420static void sg_load_scenario(struct loaddata *loading)
2421{
2422 const char *buf;
2423 int game_version;
2424
2425 /* Check status and return if not OK (sg_success FALSE). */
2426 sg_check_ret();
2427
2428 /* Load version. */
2429 game_version
2430 = secfile_lookup_int_default(loading->file, 0, "scenario.game_version");
2431 /* We require at least version 2.90.99 - and at that time we saved version
2432 * numbers as 10000*MAJOR+100*MINOR+PATCH */
2433 sg_failure_ret(29099 <= game_version, "Saved game is too old, at least "
2434 "version 2.90.99 required.");
2435
2436 loading->full_version = game_version;
2437
2438 game.scenario.datafile[0] = '\0';
2439
2441 "scenario.is_scenario"), "%s", secfile_error());
2442 if (!game.scenario.is_scenario) {
2443 return;
2444 }
2445
2446 buf = secfile_lookup_str_default(loading->file, "", "scenario.name");
2447 if (buf[0] != '\0') {
2449 }
2450
2451 buf = secfile_lookup_str_default(loading->file, "",
2452 "scenario.authors");
2453 if (buf[0] != '\0') {
2455 } else {
2456 game.scenario.authors[0] = '\0';
2457 }
2458
2459 buf = secfile_lookup_str_default(loading->file, "",
2460 "scenario.description");
2461 if (buf[0] != '\0') {
2463 } else {
2464 game.scenario_desc.description[0] = '\0';
2465 }
2467 = secfile_lookup_bool_default(loading->file, FALSE, "scenario.save_random");
2469 = secfile_lookup_bool_default(loading->file, TRUE, "scenario.players");
2472 "scenario.startpos_nations");
2475 "scenario.prevent_new_cities");
2478 "scenario.lake_flooding");
2481 "scenario.handmade");
2484 "scenario.allow_ai_type_fallback");
2485
2488 "scenario.ruleset_locked");
2489
2490 buf = secfile_lookup_str_default(loading->file, "",
2491 "scenario.datafile");
2492 if (buf[0] != '\0') {
2494 }
2495
2496 sg_failure_ret(loading->server_state == S_S_INITIAL
2497 || (loading->server_state == S_S_RUNNING
2498 && game.scenario.players),
2499 "Invalid scenario definition (server state '%s' and "
2500 "players are %s).",
2501 server_states_name(loading->server_state),
2502 game.scenario.players ? "saved" : "not saved");
2503}
2504
2505/************************************************************************/
2508static void sg_save_scenario(struct savedata *saving)
2509{
2510 struct entry *mod_entry;
2511 int game_version;
2512
2513 /* Check status and return if not OK (sg_success FALSE). */
2514 sg_check_ret();
2515
2516 game_version = MAJOR_VERSION * 1000000 + MINOR_VERSION * 10000 + PATCH_VERSION * 100;
2517#ifdef EMERGENCY_VERSION
2518 game_version += EMERGENCY_VERSION;
2519#endif /* EMERGENCY_VERSION */
2520 secfile_insert_int(saving->file, game_version, "scenario.game_version");
2521
2522 if (!saving->scenario || !game.scenario.is_scenario) {
2523 secfile_insert_bool(saving->file, FALSE, "scenario.is_scenario");
2524 return;
2525 }
2526
2527 secfile_insert_bool(saving->file, TRUE, "scenario.is_scenario");
2528
2529 /* Name is mandatory to the level that is saved even if empty. */
2530 mod_entry = secfile_insert_str(saving->file, game.scenario.name, "scenario.name");
2531 entry_str_set_gt_marking(mod_entry, TRUE);
2532
2533 /* Authors list is saved only if it exist */
2534 if (game.scenario.authors[0] != '\0') {
2535 mod_entry = secfile_insert_str(saving->file, game.scenario.authors,
2536 "scenario.authors");
2537 entry_str_set_gt_marking(mod_entry, TRUE);
2538 }
2539
2540 /* Description is saved only if it exist */
2541 if (game.scenario_desc.description[0] != '\0') {
2543 "scenario.description");
2544 entry_str_set_gt_marking(mod_entry, TRUE);
2545 }
2546
2547 secfile_insert_bool(saving->file, game.scenario.save_random, "scenario.save_random");
2548 secfile_insert_bool(saving->file, game.scenario.players, "scenario.players");
2550 "scenario.startpos_nations");
2553 "scenario.prevent_new_cities");
2554 }
2556 "scenario.lake_flooding");
2557 if (game.scenario.handmade) {
2559 "scenario.handmade");
2560 }
2563 "scenario.allow_ai_type_fallback");
2564 }
2565
2566 if (game.scenario.datafile[0] != '\0') {
2568 "scenario.datafile");
2569 }
2571 "scenario.ruleset_locked");
2572 if (!game.scenario.ruleset_locked && game.scenario.req_caps[0] != '\0') {
2574 "scenario.ruleset_caps");
2575 }
2576}
2577
2578/* =======================================================================
2579 * Load / save game settings.
2580 * ======================================================================= */
2581
2582/************************************************************************/
2585static void sg_load_settings(struct loaddata *loading)
2586{
2587 /* Check status and return if not OK (sg_success FALSE). */
2588 sg_check_ret();
2589
2590 settings_game_load(loading->file, "settings");
2591
2592 /* Save current status of fogofwar. */
2594
2595 /* Add all compatibility settings here. */
2596}
2597
2598/************************************************************************/
2601static void sg_save_settings(struct savedata *saving)
2602{
2603 enum map_generator real_generator = wld.map.server.generator;
2604
2605 /* Check status and return if not OK (sg_success FALSE). */
2606 sg_check_ret();
2607
2608 if (saving->scenario) {
2609 wld.map.server.generator = MAPGEN_SCENARIO; /* We want a scenario. */
2610 }
2611
2612 settings_game_save(saving->file, "settings");
2613 /* Restore real map generator. */
2614 wld.map.server.generator = real_generator;
2615
2616 /* Add all compatibility settings here. */
2617}
2618
2619/* =======================================================================
2620 * Load / save the main map.
2621 * ======================================================================= */
2622
2623/************************************************************************/
2626static void sg_load_map(struct loaddata *loading)
2627{
2628 /* Check status and return if not OK (sg_success FALSE). */
2629 sg_check_ret();
2630
2631 /* This defaults to TRUE even if map has not been generated.
2632 * We rely on that
2633 * 1) scenario maps have it explicitly right.
2634 * 2) when map is actually generated, it re-initialize this to FALSE. */
2636 = secfile_lookup_bool_default(loading->file, TRUE, "map.have_huts");
2638 = secfile_lookup_bool_default(loading->file, TRUE, "map.have_resources");
2639
2641
2642 /* Savegame may have stored random_seed for documentation purposes only,
2643 * but we want to keep it for resaving. */
2645 = secfile_lookup_int_default(loading->file, 0, "map.random_seed");
2646
2647 if (S_S_INITIAL == loading->server_state
2649 /* Generator MAPGEN_SCENARIO is used;
2650 * this map was done with the map editor. */
2651
2652 /* Load tiles. */
2653 sg_load_map_tiles(loading);
2654 sg_load_map_startpos(loading);
2655 sg_load_map_tiles_extras(loading);
2656
2657 /* Nothing more needed for a scenario. */
2658 secfile_entry_ignore(loading->file, "game.save_known");
2659
2660 return;
2661 }
2662
2663 if (S_S_INITIAL == loading->server_state) {
2664 /* Nothing more to do if it is not a scenario but in initial state. */
2665 return;
2666 }
2667
2668 sg_load_map_tiles(loading);
2669 sg_load_map_startpos(loading);
2670 sg_load_map_tiles_extras(loading);
2671 sg_load_map_known(loading);
2672 sg_load_map_owner(loading);
2673 sg_load_map_worked(loading);
2674}
2675
2676/************************************************************************/
2679static void sg_save_map(struct savedata *saving)
2680{
2681 /* Check status and return if not OK (sg_success FALSE). */
2682 sg_check_ret();
2683
2684 if (map_is_empty()) {
2685 /* No map. */
2686 return;
2687 }
2688
2689 if (saving->scenario) {
2691 "map.have_huts");
2693 "map.have_resources");
2694 } else {
2695 secfile_insert_bool(saving->file, TRUE, "map.have_huts");
2696 secfile_insert_bool(saving->file, TRUE, "map.have_resources");
2697 }
2698
2699 /* For debugging purposes only.
2700 * Do not save it if it's 0 (not known);
2701 * this confuses people reading this 'document' less than
2702 * saving 0. */
2703 if (wld.map.server.seed != 0) {
2705 "map.random_seed");
2706 }
2707
2708 sg_save_map_tiles(saving);
2709 sg_save_map_startpos(saving);
2711 sg_save_map_owner(saving);
2712 sg_save_map_worked(saving);
2713 sg_save_map_known(saving);
2714}
2715
2716/************************************************************************/
2719static void sg_load_map_tiles(struct loaddata *loading)
2720{
2721 /* Check status and return if not OK (sg_success FALSE). */
2722 sg_check_ret();
2723
2724 /* Initialize the map for the current topology. 'map.xsize' and
2725 * 'map.ysize' must be set. */
2727
2728 /* Allocate map. */
2730
2731 /* get the terrain type */
2732 LOAD_MAP_CHAR(ch, ptile, ptile->terrain = char2terrain(ch), loading->file,
2733 "map.t%04d");
2735
2736 /* Check for special tile sprites. */
2737 whole_map_iterate(&(wld.map), ptile) {
2738 const char *spec_sprite;
2739 const char *label;
2740 int nat_x, nat_y;
2741
2743 spec_sprite = secfile_lookup_str(loading->file, "map.spec_sprite_%d_%d",
2744 nat_x, nat_y);
2745 label = secfile_lookup_str_default(loading->file, NULL, "map.label_%d_%d",
2746 nat_x, nat_y);
2747 if (NULL != ptile->spec_sprite) {
2748 ptile->spec_sprite = fc_strdup(spec_sprite);
2749 }
2750 if (label != NULL) {
2751 tile_set_label(ptile, label);
2752 }
2754}
2755
2756/************************************************************************/
2759static void sg_save_map_tiles(struct savedata *saving)
2760{
2761 /* Check status and return if not OK (sg_success FALSE). */
2762 sg_check_ret();
2763
2764 /* Save the terrain type. */
2765 SAVE_MAP_CHAR(ptile, terrain2char(ptile->terrain), saving->file,
2766 "map.t%04d");
2767
2768 /* Save special tile sprites. */
2769 whole_map_iterate(&(wld.map), ptile) {
2770 int nat_x, nat_y;
2771
2773 if (ptile->spec_sprite) {
2774 secfile_insert_str(saving->file, ptile->spec_sprite,
2775 "map.spec_sprite_%d_%d", nat_x, nat_y);
2776 }
2777 if (ptile->label != NULL) {
2778 secfile_insert_str(saving->file, ptile->label,
2779 "map.label_%d_%d", nat_x, nat_y);
2780 }
2782}
2783
2784/************************************************************************/
2787static void sg_load_map_tiles_extras(struct loaddata *loading)
2788{
2789 /* Check status and return if not OK (sg_success FALSE). */
2790 sg_check_ret();
2791
2792 /* Load extras. */
2793 halfbyte_iterate_extras(j, loading->extra.size) {
2794 LOAD_MAP_CHAR(ch, ptile, sg_extras_set(&ptile->extras, ch, loading->extra.order + 4 * j),
2795 loading->file, "map.e%02d_%04d", j);
2797
2798 if (S_S_INITIAL != loading->server_state
2801 whole_map_iterate(&(wld.map), ptile) {
2802 extra_type_by_cause_iterate(EC_RESOURCE, pres) {
2803 if (tile_has_extra(ptile, pres)) {
2804 tile_set_resource(ptile, pres);
2805
2806 if (!terrain_has_resource(ptile->terrain, ptile->resource)) {
2807 BV_CLR(ptile->extras, extra_index(pres));
2808 }
2809 }
2812 }
2813}
2814
2815/************************************************************************/
2818static void sg_save_map_tiles_extras(struct savedata *saving)
2819{
2820 /* Check status and return if not OK (sg_success FALSE). */
2821 sg_check_ret();
2822
2823 /* Save extras. */
2825 int mod[4];
2826 int l;
2827
2828 for (l = 0; l < 4; l++) {
2829 if (4 * j + 1 > game.control.num_extra_types) {
2830 mod[l] = -1;
2831 } else {
2832 mod[l] = 4 * j + l;
2833 }
2834 }
2835 SAVE_MAP_CHAR(ptile, sg_extras_get(ptile->extras, ptile->resource, mod),
2836 saving->file, "map.e%02d_%04d", j);
2838}
2839
2840/************************************************************************/
2844static void sg_load_map_startpos(struct loaddata *loading)
2845{
2846 struct nation_type *pnation;
2847 struct startpos *psp;
2848 struct tile *ptile;
2849 const char SEPARATOR = '#';
2850 const char *nation_names;
2851 int nat_x, nat_y;
2852 bool exclude;
2853 int i, startpos_count;
2854
2855 /* Check status and return if not OK (sg_success FALSE). */
2856 sg_check_ret();
2857
2858 startpos_count
2859 = secfile_lookup_int_default(loading->file, 0, "map.startpos_count");
2860
2861 if (0 == startpos_count) {
2862 /* Nothing to do. */
2863 return;
2864 }
2865
2866 for (i = 0; i < startpos_count; i++) {
2867 if (!secfile_lookup_int(loading->file, &nat_x, "map.startpos%d.x", i)
2868 || !secfile_lookup_int(loading->file, &nat_y,
2869 "map.startpos%d.y", i)) {
2870 log_sg("Warning: Undefined coordinates for startpos %d", i);
2871 continue;
2872 }
2873
2874 ptile = native_pos_to_tile(&(wld.map), nat_x, nat_y);
2875 if (NULL == ptile) {
2876 log_error("Start position native coordinates (%d, %d) do not exist "
2877 "in this map. Skipping...", nat_x, nat_y);
2878 continue;
2879 }
2880
2881 exclude = secfile_lookup_bool_default(loading->file, FALSE,
2882 "map.startpos%d.exclude", i);
2883
2884 psp = map_startpos_new(ptile);
2885
2886 nation_names = secfile_lookup_str(loading->file,
2887 "map.startpos%d.nations", i);
2888 if (NULL != nation_names && '\0' != nation_names[0]) {
2889 const size_t size = strlen(nation_names) + 1;
2890 char buf[size], *start, *end;
2891
2892 memcpy(buf, nation_names, size);
2893 for (start = buf - 1; NULL != start; start = end) {
2894 start++;
2895 if ((end = strchr(start, SEPARATOR))) {
2896 *end = '\0';
2897 }
2898
2899 pnation = nation_by_rule_name(start);
2900 if (NO_NATION_SELECTED != pnation) {
2901 if (exclude) {
2902 startpos_disallow(psp, pnation);
2903 } else {
2904 startpos_allow(psp, pnation);
2905 }
2906 } else {
2907 log_verbose("Missing nation \"%s\".", start);
2908 }
2909 }
2910 }
2911 }
2912
2913 if (0 < map_startpos_count()
2914 && loading->server_state == S_S_INITIAL
2916 log_verbose("Number of starts (%d) are lower than rules.max_players "
2917 "(%d), lowering rules.max_players.",
2920 }
2921
2922 /* Re-initialize nation availability in light of start positions.
2923 * This has to be after loading [scenario] and [map].startpos and
2924 * before we seek nations for players. */
2926}
2927
2928/************************************************************************/
2931static void sg_save_map_startpos(struct savedata *saving)
2932{
2933 struct tile *ptile;
2934 const char SEPARATOR = '#';
2935 int i = 0;
2936
2937 /* Check status and return if not OK (sg_success FALSE). */
2938 sg_check_ret();
2939
2941 return;
2942 }
2943
2945 "map.startpos_count");
2946
2948 int nat_x, nat_y;
2949
2950 ptile = startpos_tile(psp);
2951
2953 secfile_insert_int(saving->file, nat_x, "map.startpos%d.x", i);
2954 secfile_insert_int(saving->file, nat_y, "map.startpos%d.y", i);
2955
2957 "map.startpos%d.exclude", i);
2958 if (startpos_allows_all(psp)) {
2959 secfile_insert_str(saving->file, "", "map.startpos%d.nations", i);
2960 } else {
2961 const struct nation_hash *nations = startpos_raw_nations(psp);
2962 char nation_names[MAX_LEN_NAME * nation_hash_size(nations)];
2963
2964 nation_names[0] = '\0';
2965 nation_hash_iterate(nations, pnation) {
2966 if ('\0' == nation_names[0]) {
2967 fc_strlcpy(nation_names, nation_rule_name(pnation),
2968 sizeof(nation_names));
2969 } else {
2970 cat_snprintf(nation_names, sizeof(nation_names),
2971 "%c%s", SEPARATOR, nation_rule_name(pnation));
2972 }
2974 secfile_insert_str(saving->file, nation_names,
2975 "map.startpos%d.nations", i);
2976 }
2977 i++;
2979
2981}
2982
2983/************************************************************************/
2986static void sg_load_map_owner(struct loaddata *loading)
2987{
2988 int x, y;
2989 struct tile *claimer = NULL;
2990 struct extra_type *placing = NULL;
2991
2992 /* Check status and return if not OK (sg_success FALSE). */
2993 sg_check_ret();
2994
2995 if (game.info.is_new_game) {
2996 /* No owner/source information for a new game / scenario. */
2997 return;
2998 }
2999
3000 /* Owner, ownership source, and infra turns are stored as plain numbers */
3001 for (y = 0; y < wld.map.ysize; y++) {
3002 const char *buffer1 = secfile_lookup_str(loading->file,
3003 "map.owner%04d", y);
3004 const char *buffer2 = secfile_lookup_str(loading->file,
3005 "map.source%04d", y);
3006 const char *buffer3 = secfile_lookup_str(loading->file,
3007 "map.eowner%04d", y);
3008 const char *buffer_placing = secfile_lookup_str_default(loading->file,
3009 NULL,
3010 "map.placing%04d", y);
3011 const char *buffer_turns = secfile_lookup_str_default(loading->file,
3012 NULL,
3013 "map.infra_turns%04d", y);
3014 const char *ptr1 = buffer1;
3015 const char *ptr2 = buffer2;
3016 const char *ptr3 = buffer3;
3017 const char *ptr_placing = buffer_placing;
3018 const char *ptr_turns = buffer_turns;
3019
3020 sg_failure_ret(buffer1 != NULL, "%s", secfile_error());
3021 sg_failure_ret(buffer2 != NULL, "%s", secfile_error());
3022 sg_failure_ret(buffer3 != NULL, "%s", secfile_error());
3023
3024 for (x = 0; x < wld.map.xsize; x++) {
3025 char token1[TOKEN_SIZE];
3026 char token2[TOKEN_SIZE];
3027 char token3[TOKEN_SIZE];
3028 char token_placing[TOKEN_SIZE];
3029 char token_turns[TOKEN_SIZE];
3030 struct player *owner = NULL;
3031 struct player *eowner = NULL;
3032 int turns;
3033 int number;
3034 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3035
3036 scanin(&ptr1, ",", token1, sizeof(token1));
3037 sg_failure_ret(token1[0] != '\0',
3038 "Map size not correct (map.owner%d).", y);
3039 if (strcmp(token1, "-") == 0) {
3040 owner = NULL;
3041 } else {
3042 sg_failure_ret(str_to_int(token1, &number),
3043 "Got map owner %s in (%d, %d).", token1, x, y);
3044 owner = player_by_number(number);
3045 }
3046
3047 scanin(&ptr2, ",", token2, sizeof(token2));
3048 sg_failure_ret(token2[0] != '\0',
3049 "Map size not correct (map.source%d).", y);
3050 if (strcmp(token2, "-") == 0) {
3051 claimer = NULL;
3052 } else {
3053 sg_failure_ret(str_to_int(token2, &number),
3054 "Got map source %s in (%d, %d).", token2, x, y);
3055 claimer = index_to_tile(&(wld.map), number);
3056 }
3057
3058 scanin(&ptr3, ",", token3, sizeof(token3));
3059 sg_failure_ret(token3[0] != '\0',
3060 "Map size not correct (map.eowner%d).", y);
3061 if (strcmp(token3, "-") == 0) {
3062 eowner = NULL;
3063 } else {
3064 sg_failure_ret(str_to_int(token3, &number),
3065 "Got base owner %s in (%d, %d).", token3, x, y);
3066 eowner = player_by_number(number);
3067 }
3068
3069 if (ptr_placing != NULL) {
3070 scanin(&ptr_placing, ",", token_placing, sizeof(token_placing));
3071 sg_failure_ret(token_placing[0] != '\0',
3072 "Map size not correct (map.placing%d).", y);
3073 if (strcmp(token_placing, "-") == 0) {
3074 placing = NULL;
3075 } else {
3076 sg_failure_ret(str_to_int(token_placing, &number),
3077 "Got placing extra %s in (%d, %d).", token_placing, x, y);
3078 placing = extra_by_number(number);
3079 }
3080 } else {
3081 placing = NULL;
3082 }
3083
3084 if (ptr_turns != NULL) {
3085 scanin(&ptr_turns, ",", token_turns, sizeof(token_turns));
3086 sg_failure_ret(token_turns[0] != '\0',
3087 "Map size not correct (map.infra_turns%d).", y);
3088 sg_failure_ret(str_to_int(token_turns, &number),
3089 "Got infra_turns %s in (%d, %d).", token_turns, x, y);
3090 turns = number;
3091 } else {
3092 turns = 1;
3093 }
3094
3096 tile_claim_bases(ptile, eowner);
3097 ptile->placing = placing;
3098 ptile->infra_turns = turns;
3099 log_debug("extras_owner(%d, %d) = %s", TILE_XY(ptile), player_name(eowner));
3100 }
3101 }
3102}
3103
3104/************************************************************************/
3107static void sg_save_map_owner(struct savedata *saving)
3108{
3109 int x, y;
3110
3111 /* Check status and return if not OK (sg_success FALSE). */
3112 sg_check_ret();
3113
3114 if (saving->scenario && !saving->save_players) {
3115 /* Nothing to do for a scenario without saved players. */
3116 return;
3117 }
3118
3119 /* Store owner and ownership source as plain numbers. */
3120 for (y = 0; y < wld.map.ysize; y++) {
3121 char line[wld.map.xsize * TOKEN_SIZE];
3122
3123 line[0] = '\0';
3124 for (x = 0; x < wld.map.xsize; x++) {
3125 char token[TOKEN_SIZE];
3126 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3127
3128 if (!saving->save_players || tile_owner(ptile) == NULL) {
3129 strcpy(token, "-");
3130 } else {
3131 fc_snprintf(token, sizeof(token), "%d",
3132 player_number(tile_owner(ptile)));
3133 }
3134 strcat(line, token);
3135 if (x + 1 < wld.map.xsize) {
3136 strcat(line, ",");
3137 }
3138 }
3139 secfile_insert_str(saving->file, line, "map.owner%04d", y);
3140 }
3141
3142 for (y = 0; y < wld.map.ysize; y++) {
3143 char line[wld.map.xsize * TOKEN_SIZE];
3144
3145 line[0] = '\0';
3146 for (x = 0; x < wld.map.xsize; x++) {
3147 char token[TOKEN_SIZE];
3148 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3149
3150 if (ptile->claimer == NULL) {
3151 strcpy(token, "-");
3152 } else {
3153 fc_snprintf(token, sizeof(token), "%d", tile_index(ptile->claimer));
3154 }
3155 strcat(line, token);
3156 if (x + 1 < wld.map.xsize) {
3157 strcat(line, ",");
3158 }
3159 }
3160 secfile_insert_str(saving->file, line, "map.source%04d", y);
3161 }
3162
3163 for (y = 0; y < wld.map.ysize; y++) {
3164 char line[wld.map.xsize * TOKEN_SIZE];
3165
3166 line[0] = '\0';
3167 for (x = 0; x < wld.map.xsize; x++) {
3168 char token[TOKEN_SIZE];
3169 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3170
3171 if (!saving->save_players || extra_owner(ptile) == NULL) {
3172 strcpy(token, "-");
3173 } else {
3174 fc_snprintf(token, sizeof(token), "%d",
3175 player_number(extra_owner(ptile)));
3176 }
3177 strcat(line, token);
3178 if (x + 1 < wld.map.xsize) {
3179 strcat(line, ",");
3180 }
3181 }
3182 secfile_insert_str(saving->file, line, "map.eowner%04d", y);
3183 }
3184
3185 for (y = 0; y < wld.map.ysize; y++) {
3186 char line[wld.map.xsize * TOKEN_SIZE];
3187
3188 line[0] = '\0';
3189 for (x = 0; x < wld.map.xsize; x++) {
3190 char token[TOKEN_SIZE];
3191 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3192
3193 if (ptile->placing == NULL) {
3194 strcpy(token, "-");
3195 } else {
3196 fc_snprintf(token, sizeof(token), "%d",
3197 extra_number(ptile->placing));
3198 }
3199 strcat(line, token);
3200 if (x + 1 < wld.map.xsize) {
3201 strcat(line, ",");
3202 }
3203 }
3204 secfile_insert_str(saving->file, line, "map.placing%04d", y);
3205 }
3206
3207 for (y = 0; y < wld.map.ysize; y++) {
3208 char line[wld.map.xsize * TOKEN_SIZE];
3209
3210 line[0] = '\0';
3211 for (x = 0; x < wld.map.xsize; x++) {
3212 char token[TOKEN_SIZE];
3213 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3214
3215 if (ptile->placing != NULL) {
3216 fc_snprintf(token, sizeof(token), "%d",
3217 ptile->infra_turns);
3218 } else {
3219 fc_snprintf(token, sizeof(token), "0");
3220 }
3221 strcat(line, token);
3222 if (x + 1 < wld.map.xsize) {
3223 strcat(line, ",");
3224 }
3225 }
3226 secfile_insert_str(saving->file, line, "map.infra_turns%04d", y);
3227 }
3228}
3229
3230/************************************************************************/
3233static void sg_load_map_worked(struct loaddata *loading)
3234{
3235 int x, y;
3236
3237 /* Check status and return if not OK (sg_success FALSE). */
3238 sg_check_ret();
3239
3240 sg_failure_ret(loading->worked_tiles == NULL,
3241 "City worked map not loaded!");
3242
3244 sizeof(*loading->worked_tiles));
3245
3246 for (y = 0; y < wld.map.ysize; y++) {
3247 const char *buffer = secfile_lookup_str(loading->file, "map.worked%04d",
3248 y);
3249 const char *ptr = buffer;
3250
3251 sg_failure_ret(NULL != buffer,
3252 "Savegame corrupt - map line %d not found.", y);
3253 for (x = 0; x < wld.map.xsize; x++) {
3254 char token[TOKEN_SIZE];
3255 int number;
3256 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3257
3258 scanin(&ptr, ",", token, sizeof(token));
3259 sg_failure_ret('\0' != token[0],
3260 "Savegame corrupt - map size not correct.");
3261 if (strcmp(token, "-") == 0) {
3262 number = -1;
3263 } else {
3264 sg_failure_ret(str_to_int(token, &number) && 0 < number,
3265 "Savegame corrupt - got tile worked by city "
3266 "id=%s in (%d, %d).", token, x, y);
3267 }
3268
3269 loading->worked_tiles[ptile->index] = number;
3270 }
3271 }
3272}
3273
3274/************************************************************************/
3277static void sg_save_map_worked(struct savedata *saving)
3278{
3279 int x, y;
3280
3281 /* Check status and return if not OK (sg_success FALSE). */
3282 sg_check_ret();
3283
3284 if (saving->scenario && !saving->save_players) {
3285 /* Nothing to do for a scenario without saved players. */
3286 return;
3287 }
3288
3289 /* additionally save the tiles worked by the cities */
3290 for (y = 0; y < wld.map.ysize; y++) {
3291 char line[wld.map.xsize * TOKEN_SIZE];
3292
3293 line[0] = '\0';
3294 for (x = 0; x < wld.map.xsize; x++) {
3295 char token[TOKEN_SIZE];
3296 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3297 struct city *pcity = tile_worked(ptile);
3298
3299 if (pcity == NULL) {
3300 strcpy(token, "-");
3301 } else {
3302 fc_snprintf(token, sizeof(token), "%d", pcity->id);
3303 }
3304 strcat(line, token);
3305 if (x < wld.map.xsize) {
3306 strcat(line, ",");
3307 }
3308 }
3309 secfile_insert_str(saving->file, line, "map.worked%04d", y);
3310 }
3311}
3312
3313/************************************************************************/
3316static void sg_load_map_known(struct loaddata *loading)
3317{
3318 /* Check status and return if not OK (sg_success FALSE). */
3319 sg_check_ret();
3320
3321 players_iterate(pplayer) {
3322 /* Allocate player private map here; it is needed in different modules
3323 * besides this one ((i.e. sg_load_player_*()). */
3324 player_map_init(pplayer);
3326
3328 "game.save_known")) {
3329 int lines = player_slot_max_used_number() / 32 + 1;
3330 int j, p, l, i;
3331 unsigned int *known = fc_calloc(lines * MAP_INDEX_SIZE, sizeof(*known));
3332
3333 for (l = 0; l < lines; l++) {
3334 for (j = 0; j < 8; j++) {
3335 for (i = 0; i < 4; i++) {
3336 /* Only bother trying to load the map for this halfbyte if at least
3337 * one of the corresponding player slots is in use. */
3338 if (player_slot_is_used(player_slot_by_number(l*32 + j*4 + i))) {
3339 LOAD_MAP_CHAR(ch, ptile,
3340 known[l * MAP_INDEX_SIZE + tile_index(ptile)]
3341 |= ascii_hex2bin(ch, j),
3342 loading->file, "map.k%02d_%04d", l * 8 + j);
3343 break;
3344 }
3345 }
3346 }
3347 }
3348
3349 players_iterate(pplayer) {
3350 dbv_clr_all(&pplayer->tile_known);
3352
3353 /* HACK: we read the known data from hex into 32-bit integers, and
3354 * now we convert it to the known tile data of each player. */
3355 whole_map_iterate(&(wld.map), ptile) {
3356 players_iterate(pplayer) {
3357 p = player_index(pplayer);
3358 l = player_index(pplayer) / 32;
3359
3360 if (known[l * MAP_INDEX_SIZE + tile_index(ptile)] & (1u << (p % 32))) {
3361 map_set_known(ptile, pplayer);
3362 }
3365
3366 FC_FREE(known);
3367 }
3368}
3369
3370/************************************************************************/
3373static void sg_save_map_known(struct savedata *saving)
3374{
3375 /* Check status and return if not OK (sg_success FALSE). */
3376 sg_check_ret();
3377
3378 if (!saving->save_players) {
3379 secfile_insert_bool(saving->file, FALSE, "game.save_known");
3380 return;
3381 } else {
3382 int lines = player_slot_max_used_number() / 32 + 1;
3383
3385 "game.save_known");
3387 int j, p, l, i;
3388 unsigned int *known = fc_calloc(lines * MAP_INDEX_SIZE, sizeof(*known));
3389
3390 /* HACK: we convert the data into a 32-bit integer, and then save it as
3391 * hex. */
3392
3393 whole_map_iterate(&(wld.map), ptile) {
3394 players_iterate(pplayer) {
3395 if (map_is_known(ptile, pplayer)) {
3396 p = player_index(pplayer);
3397 l = p / 32;
3398 known[l * MAP_INDEX_SIZE + tile_index(ptile)]
3399 |= (1u << (p % 32)); /* "p % 32" = "p - l * 32" */
3400 }
3403
3404 for (l = 0; l < lines; l++) {
3405 for (j = 0; j < 8; j++) {
3406 for (i = 0; i < 4; i++) {
3407 /* Only bother saving the map for this halfbyte if at least one
3408 * of the corresponding player slots is in use */
3409 if (player_slot_is_used(player_slot_by_number(l*32 + j*4 + i))) {
3410 /* put 4-bit segments of the 32-bit "known" field */
3412 + tile_index(ptile)], j),
3413 saving->file, "map.k%02d_%04d", l * 8 + j);
3414 break;
3415 }
3416 }
3417 }
3418 }
3419
3420 FC_FREE(known);
3421 }
3422 }
3423}
3424
3425/* =======================================================================
3426 * Load / save player data.
3427 *
3428 * This is split into two parts as some data can only be loaded if the
3429 * number of players is known and the corresponding player slots are
3430 * defined.
3431 * ======================================================================= */
3432
3433/************************************************************************/
3436static void sg_load_players_basic(struct loaddata *loading)
3437{
3438 int i, k, nplayers;
3439 const char *str;
3440 bool shuffle_loaded = TRUE;
3441
3442 /* Check status and return if not OK (sg_success FALSE). */
3443 sg_check_ret();
3444
3445 if (S_S_INITIAL == loading->server_state
3446 || game.info.is_new_game) {
3447 /* Nothing more to do. */
3448 return;
3449 }
3450
3451 /* Load destroyed wonders: */
3452 str = secfile_lookup_str(loading->file,
3453 "players.destroyed_wonders");
3454 sg_failure_ret(str != NULL, "%s", secfile_error());
3455 sg_failure_ret(strlen(str) == loading->improvement.size,
3456 "Invalid length for 'players.destroyed_wonders' ("
3457 SIZE_T_PRINTF " ~= " SIZE_T_PRINTF ")",
3458 strlen(str), loading->improvement.size);
3459 for (k = 0; k < loading->improvement.size; k++) {
3460 sg_failure_ret(str[k] == '1' || str[k] == '0',
3461 "Undefined value '%c' within "
3462 "'players.destroyed_wonders'.", str[k]);
3463
3464 if (str[k] == '1') {
3465 struct impr_type *pimprove =
3467 if (pimprove) {
3470 }
3471 }
3472 }
3473
3474 server.identity_number
3475 = secfile_lookup_int_default(loading->file, server.identity_number,
3476 "players.identity_number_used");
3477
3478 /* First remove all defined players. */
3479 players_iterate(pplayer) {
3480 server_remove_player(pplayer);
3482
3483 /* Now, load the players from the savefile. */
3484 player_slots_iterate(pslot) {
3485 struct player *pplayer;
3486 struct rgbcolor *prgbcolor = NULL;
3487 int pslot_id = player_slot_index(pslot);
3488
3489 if (NULL == secfile_section_lookup(loading->file, "player%d",
3490 pslot_id)) {
3491 continue;
3492 }
3493
3494 /* Get player AI type. */
3495 str = secfile_lookup_str(loading->file, "player%d.ai_type",
3496 player_slot_index(pslot));
3497 sg_failure_ret(str != NULL, "%s", secfile_error());
3498
3499 /* Get player color */
3500 if (!rgbcolor_load(loading->file, &prgbcolor, "player%d.color",
3501 pslot_id)) {
3502 if (game_was_started()) {
3503 log_sg("Game has started, yet player %d has no color defined.",
3504 pslot_id);
3505 /* This will be fixed up later */
3506 } else {
3507 log_verbose("No color defined for player %d.", pslot_id);
3508 /* Colors will be assigned on game start, or at end of savefile
3509 * loading if game has already started */
3510 }
3511 }
3512
3513 /* Create player. */
3514 pplayer = server_create_player(player_slot_index(pslot), str,
3515 prgbcolor,
3518 sg_failure_ret(pplayer != NULL, "Invalid AI type: '%s'!", str);
3519
3520 server_player_init(pplayer, FALSE, FALSE);
3521
3522 /* Free the color definition. */
3523 rgbcolor_destroy(prgbcolor);
3524
3525 /* Multipliers (policies) */
3526
3527 /* First initialise player values with ruleset defaults; this will
3528 * cover any in the ruleset not known when the savefile was created. */
3529 multipliers_iterate(pmul) {
3530 pplayer->multipliers[multiplier_index(pmul)].value
3531 = pplayer->multipliers[multiplier_index(pmul)].target = pmul->def;
3533
3534 /* Now override with any values from the savefile. */
3535 for (k = 0; k < loading->multiplier.size; k++) {
3536 const struct multiplier *pmul = loading->multiplier.order[k];
3537
3538 if (pmul) {
3540 int val =
3541 secfile_lookup_int_default(loading->file, pmul->def,
3542 "player%d.multiplier%d.val",
3543 player_slot_index(pslot), k);
3544 int rval = (((CLIP(pmul->start, val, pmul->stop)
3545 - pmul->start) / pmul->step) * pmul->step) + pmul->start;
3546
3547 if (rval != val) {
3548 log_verbose("Player %d had illegal value for multiplier \"%s\": "
3549 "was %d, clamped to %d", pslot_id,
3550 multiplier_rule_name(pmul), val, rval);
3551 }
3552 pplayer->multipliers[idx].value = rval;
3553
3554 val =
3556 pplayer->multipliers[idx].value,
3557 "player%d.multiplier%d.target",
3558 player_slot_index(pslot), k);
3559 rval = (((CLIP(pmul->start, val, pmul->stop)
3560 - pmul->start) / pmul->step) * pmul->step) + pmul->start;
3561
3562 if (rval != val) {
3563 log_verbose("Player %d had illegal value for multiplier_target "
3564 " \"%s\": was %d, clamped to %d", pslot_id,
3565 multiplier_rule_name(pmul), val, rval);
3566 }
3567 pplayer->multipliers[idx].target = rval;
3568
3569 pplayer->multipliers[idx].changed
3570 = secfile_lookup_int_default(loading->file, 0,
3571 "player%d.multiplier%d.changed",
3572 player_slot_index(pslot), k);
3573 } /* else silently discard multiplier not in current ruleset */
3574 }
3575
3576 /* Must be loaded before tile owner is set. */
3577 pplayer->server.border_vision =
3579 "player%d.border_vision",
3580 player_slot_index(pslot));
3582
3583 /* check number of players */
3584 nplayers = secfile_lookup_int_default(loading->file, 0, "players.nplayers");
3585 sg_failure_ret(player_count() == nplayers, "The value of players.nplayers "
3586 "(%d) from the loaded game does not match the number of "
3587 "players present (%d).", nplayers, player_count());
3588
3589 /* Load team information. */
3590 players_iterate(pplayer) {
3591 int team;
3592 struct team_slot *tslot = NULL;
3593
3595 "player%d.team_no",
3596 player_number(pplayer))
3597 && (tslot = team_slot_by_number(team)),
3598 "Invalid team definition for player %s (nb %d).",
3599 player_name(pplayer), player_number(pplayer));
3600 /* Should never fail when slot given is not NULL */
3601 team_add_player(pplayer, team_new(tslot));
3603
3604 /* Loading the shuffle list is quite complex. At the time of saving the
3605 * shuffle data is saved as
3606 * shuffled_player_<number> = player_slot_id
3607 * where number is an increasing number and player_slot_id is a number
3608 * between 0 and the maximum number of player slots. Now we have to create
3609 * a list
3610 * shuffler_players[number] = player_slot_id
3611 * where all player slot IDs are used exactly one time. The code below
3612 * handles this ... */
3613 if (secfile_lookup_int_default(loading->file, -1,
3614 "players.shuffled_player_%d", 0) >= 0) {
3615 int slots = player_slot_count();
3616 int plrcount = player_count();
3617 int shuffled_players[slots];
3618 bool shuffled_player_set[slots];
3619
3620 for (i = 0; i < slots; i++) {
3621 /* Array to save used numbers. */
3622 shuffled_player_set[i] = FALSE;
3623 /* List of all player IDs (needed for set_shuffled_players()). It is
3624 * initialised with the value -1 to indicate that no value is set. */
3625 shuffled_players[i] = -1;
3626 }
3627
3628 /* Load shuffled player list. */
3629 for (i = 0; i < plrcount; i++) {
3630 int shuffle
3631 = secfile_lookup_int_default(loading->file, -1,
3632 "players.shuffled_player_%d", i);
3633
3634 if (shuffle == -1) {
3635 log_sg("Missing player shuffle information (index %d) "
3636 "- reshuffle player list!", i);
3637 shuffle_loaded = FALSE;
3638 break;
3639 } else if (shuffled_player_set[shuffle]) {
3640 log_sg("Player shuffle %d used two times "
3641 "- reshuffle player list!", shuffle);
3642 shuffle_loaded = FALSE;
3643 break;
3644 }
3645 /* Set this ID as used. */
3646 shuffled_player_set[shuffle] = TRUE;
3647
3648 /* Save the player ID in the shuffle list. */
3649 shuffled_players[i] = shuffle;
3650 }
3651
3652 if (shuffle_loaded) {
3653 /* Insert missing numbers. */
3654 int shuffle_index = plrcount;
3655
3656 for (i = 0; i < slots; i++) {
3657 if (!shuffled_player_set[i]) {
3658 shuffled_players[shuffle_index++] = i;
3659 }
3660
3661 /* shuffle_index must not grow higher than size of shuffled_players. */
3662 sg_failure_ret(shuffle_index <= slots,
3663 "Invalid player shuffle data!");
3664 }
3665
3666#ifdef FREECIV_DEBUG
3667 log_debug("[load shuffle] player_count() = %d", player_count());
3668 player_slots_iterate(pslot) {
3669 int plrid = player_slot_index(pslot);
3670
3671 log_debug("[load shuffle] id: %3d => slot: %3d | slot %3d: %s",
3672 plrid, shuffled_players[plrid], plrid,
3673 shuffled_player_set[plrid] ? "is used" : "-");
3675#endif /* FREECIV_DEBUG */
3676
3677 /* Set shuffle list from savegame. */
3678 set_shuffled_players(shuffled_players);
3679 }
3680 }
3681
3682 if (!shuffle_loaded) {
3683 /* No shuffled players included or error loading them, so shuffle them
3684 * (this may include scenarios). */
3686 }
3687}
3688
3689/************************************************************************/
3692static void sg_load_players(struct loaddata *loading)
3693{
3694 /* Check status and return if not OK (sg_success FALSE). */
3695 sg_check_ret();
3696
3697 if (game.info.is_new_game) {
3698 /* Nothing to do. */
3699 return;
3700 }
3701
3702 players_iterate(pplayer) {
3703 sg_load_player_main(loading, pplayer);
3704 sg_load_player_cities(loading, pplayer);
3705 sg_load_player_units(loading, pplayer);
3706 sg_load_player_attributes(loading, pplayer);
3707
3708 /* Check the success of the functions above. */
3709 sg_check_ret();
3710
3711 /* Print out some information */
3712 if (is_ai(pplayer)) {
3713 log_normal(_("%s has been added as %s level AI-controlled player "
3714 "(%s)."), player_name(pplayer),
3715 ai_level_translated_name(pplayer->ai_common.skill_level),
3716 ai_name(pplayer->ai));
3717 } else {
3718 log_normal(_("%s has been added as human player."),
3719 player_name(pplayer));
3720 }
3722
3723 /* Also load the transport status of the units here. It must be a special
3724 * case as all units must be known (unit on an allied transporter). */
3725 players_iterate(pplayer) {
3726 /* Load unit transport status. */
3727 sg_load_player_units_transport(loading, pplayer);
3729
3730 /* Savegame may contain nation assignments that are incompatible with the
3731 * current nationset. Ensure they are compatible, one way or another. */
3733
3734 /* Some players may have invalid nations in the ruleset. Once all players
3735 * are loaded, pick one of the remaining nations for them. */
3736 players_iterate(pplayer) {
3737 if (pplayer->nation == NO_NATION_SELECTED) {
3738 player_set_nation(pplayer, pick_a_nation(NULL, FALSE, TRUE,
3739 NOT_A_BARBARIAN));
3740 /* TRANS: Minor error message: <Leader> ... <Poles>. */
3741 log_sg(_("%s had invalid nation; changing to %s."),
3742 player_name(pplayer), nation_plural_for_player(pplayer));
3743
3744 ai_traits_init(pplayer);
3745 }
3747
3748 /* Sanity check alliances, prevent allied-with-ally-of-enemy. */
3750 players_iterate_alive(aplayer) {
3751 if (pplayers_allied(plr, aplayer)) {
3752 enum dipl_reason can_ally = pplayer_can_make_treaty(plr, aplayer,
3753 DS_ALLIANCE);
3754
3755 if (can_ally == DIPL_ALLIANCE_PROBLEM_US
3756 || can_ally == DIPL_ALLIANCE_PROBLEM_THEM) {
3757 log_sg("Illegal alliance structure detected: "
3758 "%s alliance to %s reduced to peace treaty.",
3761 player_diplstate_get(plr, aplayer)->type = DS_PEACE;
3762 player_diplstate_get(aplayer, plr)->type = DS_PEACE;
3763 }
3764 }
3767
3768 /* Update cached city illness. This can depend on trade routes,
3769 * so can't be calculated until all players have been loaded. */
3770 if (game.info.illness_on) {
3771 cities_iterate(pcity) {
3772 pcity->server.illness
3773 = city_illness_calc(pcity, NULL, NULL,
3774 &(pcity->illness_trade), NULL);
3776 }
3777
3778 /* Update all city information. This must come after all cities are
3779 * loaded (in player_load) but before player (dumb) cities are loaded
3780 * in player_load_vision(). */
3781 players_iterate(plr) {
3782 city_list_iterate(plr->cities, pcity) {
3783 city_refresh(pcity);
3784 sanity_check_city(pcity);
3785 CALL_PLR_AI_FUNC(city_got, plr, plr, pcity);
3788
3789 /* Since the cities must be placed on the map to put them on the
3790 player map we do this afterwards */
3791 players_iterate(pplayer) {
3792 sg_load_player_vision(loading, pplayer);
3793 /* Check the success of the function above. */
3794 sg_check_ret();
3796
3797 /* Check shared vision. */
3798 players_iterate(pplayer) {
3799 BV_CLR_ALL(pplayer->gives_shared_vision);
3800 BV_CLR_ALL(pplayer->server.really_gives_vision);
3802
3803 /* Set up shared vision... */
3804 players_iterate(pplayer) {
3805 int plr1 = player_index(pplayer);
3806
3807 players_iterate(pplayer2) {
3808 int plr2 = player_index(pplayer2);
3810 "player%d.diplstate%d.gives_shared_vision", plr1, plr2)) {
3811 give_shared_vision(pplayer, pplayer2);
3812 }
3815
3816 /* ...and check it */
3817 players_iterate(pplayer1) {
3818 players_iterate(pplayer2) {
3819 /* TODO: Is there a good reason player is not marked as
3820 * giving shared vision to themselves -> really_gives_vision()
3821 * returning FALSE when pplayer1 == pplayer2 */
3822 if (pplayer1 != pplayer2
3823 && players_on_same_team(pplayer1, pplayer2)) {
3824 if (!really_gives_vision(pplayer1, pplayer2)) {
3825 sg_regr(3000900,
3826 _("%s did not give shared vision to team member %s."),
3827 player_name(pplayer1), player_name(pplayer2));
3828 give_shared_vision(pplayer1, pplayer2);
3829 }
3830 if (!really_gives_vision(pplayer2, pplayer1)) {
3831 sg_regr(3000900,
3832 _("%s did not give shared vision to team member %s."),
3833 player_name(pplayer2), player_name(pplayer1));
3834 give_shared_vision(pplayer2, pplayer1);
3835 }
3836 }
3839
3842
3843 /* All vision is ready; this calls city_thaw_workers_queue(). */
3845
3846 /* Make sure everything is consistent. */
3847 players_iterate(pplayer) {
3848 unit_list_iterate(pplayer->units, punit) {
3850 struct tile *ptile = unit_tile(punit);
3851
3852 log_sg("%s doing illegal activity in savegame!",
3854 log_sg("Activity: %s, Target: %s, Tile: (%d, %d), Terrain: %s",
3855 unit_activity_name(punit->activity),
3858 : "missing",
3859 TILE_XY(ptile), terrain_rule_name(tile_terrain(ptile)));
3860 punit->activity = ACTIVITY_IDLE;
3861 }
3864
3865 cities_iterate(pcity) {
3866 city_refresh(pcity);
3867 city_thaw_workers(pcity); /* may auto_arrange_workers() */
3869
3870 /* Player colors are always needed once game has started. Pre-2.4 savegames
3871 * lack them. This cannot be in compatibility conversion layer as we need
3872 * all the player data available to be able to assign best colors. */
3873 if (game_was_started()) {
3875 }
3876}
3877
3878/************************************************************************/
3881static void sg_save_players(struct savedata *saving)
3882{
3883 /* Check status and return if not OK (sg_success FALSE). */
3884 sg_check_ret();
3885
3886 if ((saving->scenario && !saving->save_players)
3887 || !game_was_started()) {
3888 /* Nothing to do for a scenario without saved players or a game in
3889 * INITIAL state. */
3890 return;
3891 }
3892
3893 secfile_insert_int(saving->file, player_count(), "players.nplayers");
3894
3895 /* Save destroyed wonders as bitvector. Note that improvement order
3896 * is saved in 'savefile.improvement.order'. */
3897 {
3898 char destroyed[B_LAST+1];
3899
3900 improvement_iterate(pimprove) {
3901 if (is_great_wonder(pimprove)
3902 && great_wonder_is_destroyed(pimprove)) {
3903 destroyed[improvement_index(pimprove)] = '1';
3904 } else {
3905 destroyed[improvement_index(pimprove)] = '0';
3906 }
3908 destroyed[improvement_count()] = '\0';
3909 secfile_insert_str(saving->file, destroyed,
3910 "players.destroyed_wonders");
3911 }
3912
3913 secfile_insert_int(saving->file, server.identity_number,
3914 "players.identity_number_used");
3915
3916 /* Save player order. */
3917 {
3918 int i = 0;
3919 shuffled_players_iterate(pplayer) {
3920 secfile_insert_int(saving->file, player_number(pplayer),
3921 "players.shuffled_player_%d", i);
3922 i++;
3924 }
3925
3926 /* Sort units. */
3928
3929 /* Save players. */
3930 players_iterate(pplayer) {
3931 sg_save_player_main(saving, pplayer);
3932 sg_save_player_cities(saving, pplayer);
3933 sg_save_player_units(saving, pplayer);
3934 sg_save_player_attributes(saving, pplayer);
3935 sg_save_player_vision(saving, pplayer);
3937}
3938
3939/************************************************************************/
3942static void sg_load_player_main(struct loaddata *loading,
3943 struct player *plr)
3944{
3945 const char **slist;
3946 int i, plrno = player_number(plr);
3947 const char *str;
3948 struct government *gov;
3949 const char *level;
3950 const char *barb_str;
3951 size_t nval;
3952 const char *kind;
3953
3954 /* Check status and return if not OK (sg_success FALSE). */
3955 sg_check_ret();
3956
3957 /* Basic player data. */
3958 str = secfile_lookup_str(loading->file, "player%d.name", plrno);
3959 sg_failure_ret(str != NULL, "%s", secfile_error());
3961 sz_strlcpy(plr->username,
3962 secfile_lookup_str_default(loading->file, "",
3963 "player%d.username", plrno));
3965 "player%d.unassigned_user", plrno),
3966 "%s", secfile_error());
3968 secfile_lookup_str_default(loading->file, "",
3969 "player%d.orig_username", plrno));
3971 secfile_lookup_str_default(loading->file, "",
3972 "player%d.ranked_username",
3973 plrno));
3975 "player%d.unassigned_ranked", plrno),
3976 "%s", secfile_error());
3977 str = secfile_lookup_str_default(loading->file, "",
3978 "player%d.delegation_username",
3979 plrno);
3980 /* Defaults to no delegation. */
3981 if (strlen(str)) {
3983 }
3984
3985 /* Player flags */
3986 BV_CLR_ALL(plr->flags);
3987 slist = secfile_lookup_str_vec(loading->file, &nval, "player%d.flags", plrno);
3988 for (i = 0; i < nval; i++) {
3989 const char *sval = slist[i];
3990 enum plr_flag_id fid = plr_flag_id_by_name(sval, fc_strcasecmp);
3991
3992 sg_failure_ret(plr_flag_id_is_valid(fid), "Invalid player flag \"%s\".", sval);
3993
3994 BV_SET(plr->flags, fid);
3995 }
3996 free(slist);
3997
3998 /* Nation */
3999 str = secfile_lookup_str(loading->file, "player%d.nation", plrno);
4001 if (plr->nation != NULL) {
4002 ai_traits_init(plr);
4003 }
4004
4005 /* Government */
4006 str = secfile_lookup_str(loading->file, "player%d.government_name",
4007 plrno);
4009 sg_failure_ret(gov != NULL, "Player%d: unsupported government \"%s\".",
4010 plrno, str);
4011 plr->government = gov;
4012
4013 /* Target government */
4014 str = secfile_lookup_str(loading->file,
4015 "player%d.target_government_name", plrno);
4016 if (str != NULL) {
4018 } else {
4019 plr->target_government = NULL;
4020 }
4022 = secfile_lookup_int_default(loading->file, -1,
4023 "player%d.revolution_finishes", plrno);
4024
4026 &plr->server.got_first_city,
4027 "player%d.got_first_city", plrno),
4028 "%s", secfile_error());
4029
4030 /* Load diplomatic data (diplstate + embassy + vision).
4031 * Shared vision is loaded in sg_load_players(). */
4033 players_iterate(pplayer) {
4034 char buf[32];
4035 struct player_diplstate *ds = player_diplstate_get(plr, pplayer);
4036 i = player_index(pplayer);
4037
4038 /* load diplomatic status */
4039 fc_snprintf(buf, sizeof(buf), "player%d.diplstate%d", plrno, i);
4040
4041 ds->type =
4042 secfile_lookup_enum_default(loading->file, DS_WAR,
4043 diplstate_type, "%s.current", buf);
4044 ds->max_state =
4045 secfile_lookup_enum_default(loading->file, DS_WAR,
4046 diplstate_type, "%s.closest", buf);
4047 ds->first_contact_turn =
4048 secfile_lookup_int_default(loading->file, 0,
4049 "%s.first_contact_turn", buf);
4050 ds->turns_left =
4051 secfile_lookup_int_default(loading->file, -2, "%s.turns_left", buf);
4053 secfile_lookup_int_default(loading->file, 0,
4054 "%s.has_reason_to_cancel", buf);
4055 ds->contact_turns_left =
4056 secfile_lookup_int_default(loading->file, 0,
4057 "%s.contact_turns_left", buf);
4058
4059 if (secfile_lookup_bool_default(loading->file, FALSE, "%s.embassy",
4060 buf)) {
4061 BV_SET(plr->real_embassy, i);
4062 }
4063 /* 'gives_shared_vision' is loaded in sg_load_players() as all cities
4064 * must be known. */
4066
4067 /* load ai data */
4068 players_iterate(aplayer) {
4069 char buf[32];
4070
4071 fc_snprintf(buf, sizeof(buf), "player%d.ai%d", plrno,
4072 player_index(aplayer));
4073
4074 plr->ai_common.love[player_index(aplayer)] =
4075 secfile_lookup_int_default(loading->file, 1, "%s.love", buf);
4076 CALL_FUNC_EACH_AI(player_load_relations, plr, aplayer, loading->file, plrno);
4078
4080 "player%d.adv.wonder_city",
4081 plrno);
4082
4083 CALL_FUNC_EACH_AI(player_load, plr, loading->file, plrno);
4084
4085 /* Some sane defaults */
4086 plr->ai_common.fuzzy = 0;
4087 plr->ai_common.expand = 100;
4088 plr->ai_common.science_cost = 100;
4089
4090
4091 level = secfile_lookup_str_default(loading->file, NULL,
4092 "player%d.ai.level", plrno);
4093 if (level != NULL && !fc_strcasecmp("Handicapped", level)) {
4094 /* Up to freeciv-3.1 Restricted AI level was known as Handicapped */
4095 plr->ai_common.skill_level = AI_LEVEL_RESTRICTED;
4096 } else {
4097 plr->ai_common.skill_level = ai_level_by_name(level, fc_strcasecmp);
4098 }
4099
4100 if (!ai_level_is_valid(plr->ai_common.skill_level)) {
4101 log_sg("Player%d: Invalid AI level \"%s\". "
4102 "Changed to \"%s\".", plrno, level,
4103 ai_level_name(game.info.skill_level));
4105 }
4106
4107 barb_str = secfile_lookup_str_default(loading->file, "None",
4108 "player%d.ai.barb_type", plrno);
4109 plr->ai_common.barbarian_type = barbarian_type_by_name(barb_str, fc_strcasecmp);
4110
4111 if (!barbarian_type_is_valid(plr->ai_common.barbarian_type)) {
4112 log_sg("Player%d: Invalid barbarian type \"%s\". "
4113 "Changed to \"None\".", plrno, barb_str);
4114 plr->ai_common.barbarian_type = NOT_A_BARBARIAN;
4115 }
4116
4117 if (is_barbarian(plr)) {
4118 server.nbarbarians++;
4119 }
4120
4121 if (is_ai(plr)) {
4123 CALL_PLR_AI_FUNC(gained_control, plr, plr);
4124 }
4125
4126 /* Load nation style. */
4127 {
4128 struct nation_style *style;
4129
4130 str = secfile_lookup_str(loading->file, "player%d.style_by_name", plrno);
4131
4132 sg_failure_ret(str != NULL, "%s", secfile_error());
4133 style = style_by_rule_name(str);
4134 if (style == NULL) {
4135 style = style_by_number(0);
4136 log_sg("Player%d: unsupported city_style_name \"%s\". "
4137 "Changed to \"%s\".", plrno, str, style_rule_name(style));
4138 }
4139 plr->style = style;
4140 }
4141
4143 "player%d.idle_turns", plrno),
4144 "%s", secfile_error());
4145 kind = secfile_lookup_str(loading->file, "player%d.kind", plrno);
4146 if (!strcmp("male", kind)) {
4147 plr->is_male = TRUE;
4148 } else {
4149 plr->is_male = FALSE;
4150 }
4152 "player%d.is_alive", plrno),
4153 "%s", secfile_error());
4155 "player%d.turns_alive", plrno),
4156 "%s", secfile_error());
4158 "player%d.last_war", plrno),
4159 "%s", secfile_error());
4161 "player%d.phase_done", plrno);
4163 "player%d.gold", plrno),
4164 "%s", secfile_error());
4166 "player%d.rates.tax", plrno),
4167 "%s", secfile_error());
4169 "player%d.rates.science", plrno),
4170 "%s", secfile_error());
4172 "player%d.rates.luxury", plrno),
4173 "%s", secfile_error());
4175 "player%d.infrapts",
4176 plrno);
4177 plr->server.bulbs_last_turn =
4178 secfile_lookup_int_default(loading->file, 0,
4179 "player%d.research.bulbs_last_turn", plrno);
4180
4181 /* Traits */
4182 if (plr->nation) {
4183 for (i = 0; i < loading->trait.size; i++) {
4184 enum trait tr = trait_by_name(loading->trait.order[i], fc_strcasecmp);
4185
4186 if (trait_is_valid(tr)) {
4187 int val;
4188
4189 sg_failure_ret(secfile_lookup_int(loading->file, &val, "player%d.trait%d.val",
4190 plrno, i),
4191 "%s", secfile_error());
4192 plr->ai_common.traits[tr].val = val;
4193
4194 sg_failure_ret(secfile_lookup_int(loading->file, &val,
4195 "player%d.trait%d.mod", plrno, i),
4196 "%s", secfile_error());
4197 plr->ai_common.traits[tr].mod = val;
4198 }
4199 }
4200 }
4201
4202 /* Achievements */
4203 {
4204 int count;
4205
4206 count = secfile_lookup_int_default(loading->file, -1,
4207 "player%d.achievement_count", plrno);
4208
4209 if (count > 0) {
4210 for (i = 0; i < count; i++) {
4211 const char *name;
4212 struct achievement *pach;
4213 bool first;
4214
4215 name = secfile_lookup_str(loading->file,
4216 "player%d.achievement%d.name", plrno, i);
4218
4219 sg_failure_ret(pach != NULL,
4220 "Unknown achievement \"%s\".", name);
4221
4223 "player%d.achievement%d.first",
4224 plrno, i),
4225 "achievement error: %s", secfile_error());
4226
4227 sg_failure_ret(pach->first == NULL || !first,
4228 "Multiple players listed as first to get achievement \"%s\".",
4229 name);
4230
4231 BV_SET(pach->achievers, player_index(plr));
4232
4233 if (first) {
4234 pach->first = plr;
4235 }
4236 }
4237 }
4238 }
4239
4240 /* Player score. */
4241 plr->score.happy =
4242 secfile_lookup_int_default(loading->file, 0,
4243 "score%d.happy", plrno);
4244 plr->score.content =
4245 secfile_lookup_int_default(loading->file, 0,
4246 "score%d.content", plrno);
4247 plr->score.unhappy =
4248 secfile_lookup_int_default(loading->file, 0,
4249 "score%d.unhappy", plrno);
4250 plr->score.angry =
4251 secfile_lookup_int_default(loading->file, 0,
4252 "score%d.angry", plrno);
4253
4254 /* Make sure that the score about specialists in current ruleset that
4255 * were not present at saving time are set to zero. */
4257 plr->score.specialists[sp] = 0;
4259
4260 for (i = 0; i < loading->specialist.size; i++) {
4262 = secfile_lookup_int_default(loading->file, 0,
4263 "score%d.specialists%d", plrno, i);
4264 }
4265
4266 plr->score.wonders =
4267 secfile_lookup_int_default(loading->file, 0,
4268 "score%d.wonders", plrno);
4269 plr->score.techs =
4270 secfile_lookup_int_default(loading->file, 0,
4271 "score%d.techs", plrno);
4272 plr->score.techout =
4273 secfile_lookup_int_default(loading->file, 0,
4274 "score%d.techout", plrno);
4275 plr->score.landarea =
4276 secfile_lookup_int_default(loading->file, 0,
4277 "score%d.landarea", plrno);
4278 plr->score.settledarea =
4279 secfile_lookup_int_default(loading->file, 0,
4280 "score%d.settledarea", plrno);
4281 plr->score.population =
4282 secfile_lookup_int_default(loading->file, 0,
4283 "score%d.population", plrno);
4284 plr->score.cities =
4285 secfile_lookup_int_default(loading->file, 0,
4286 "score%d.cities", plrno);
4287 plr->score.units =
4288 secfile_lookup_int_default(loading->file, 0,
4289 "score%d.units", plrno);
4290 plr->score.pollution =
4291 secfile_lookup_int_default(loading->file, 0,
4292 "score%d.pollution", plrno);
4293 plr->score.literacy =
4294 secfile_lookup_int_default(loading->file, 0,
4295 "score%d.literacy", plrno);
4296 plr->score.bnp =
4297 secfile_lookup_int_default(loading->file, 0,
4298 "score%d.bnp", plrno);
4299 plr->score.mfg =
4300 secfile_lookup_int_default(loading->file, 0,
4301 "score%d.mfg", plrno);
4302 plr->score.spaceship =
4303 secfile_lookup_int_default(loading->file, 0,
4304 "score%d.spaceship", plrno);
4305 plr->score.units_built =
4306 secfile_lookup_int_default(loading->file, 0,
4307 "score%d.units_built", plrno);
4308 plr->score.units_killed =
4309 secfile_lookup_int_default(loading->file, 0,
4310 "score%d.units_killed", plrno);
4311 plr->score.units_lost =
4312 secfile_lookup_int_default(loading->file, 0,
4313 "score%d.units_lost", plrno);
4314 plr->score.culture =
4315 secfile_lookup_int_default(loading->file, 0,
4316 "score%d.culture", plrno);
4317 plr->score.game =
4318 secfile_lookup_int_default(loading->file, 0,
4319 "score%d.total", plrno);
4320
4321 /* Load space ship data. */
4322 {
4323 struct player_spaceship *ship = &plr->spaceship;
4324 char prefix[32];
4325 const char *st;
4326 int ei;
4327
4328 fc_snprintf(prefix, sizeof(prefix), "player%d.spaceship", plrno);
4329 spaceship_init(ship);
4331 &ei,
4332 "%s.state", prefix),
4333 "%s", secfile_error());
4334 ship->state = ei;
4335
4336 if (ship->state != SSHIP_NONE) {
4338 "%s.structurals", prefix),
4339 "%s", secfile_error());
4341 "%s.components", prefix),
4342 "%s", secfile_error());
4344 "%s.modules", prefix),
4345 "%s", secfile_error());
4346 sg_failure_ret(secfile_lookup_int(loading->file, &ship->fuel,
4347 "%s.fuel", prefix),
4348 "%s", secfile_error());
4350 "%s.propulsion", prefix),
4351 "%s", secfile_error());
4353 "%s.habitation", prefix),
4354 "%s", secfile_error());
4356 "%s.life_support", prefix),
4357 "%s", secfile_error());
4359 "%s.solar_panels", prefix),
4360 "%s", secfile_error());
4361
4362 st = secfile_lookup_str(loading->file, "%s.structure", prefix);
4363 sg_failure_ret(st != NULL, "%s", secfile_error())
4364 for (i = 0; i < NUM_SS_STRUCTURALS && st[i]; i++) {
4365 sg_failure_ret(st[i] == '1' || st[i] == '0',
4366 "Undefined value '%c' within '%s.structure'.", st[i],
4367 prefix)
4368
4369 if (!(st[i] == '0')) {
4370 BV_SET(ship->structure, i);
4371 }
4372 }
4373 if (ship->state >= SSHIP_LAUNCHED) {
4375 "%s.launch_year", prefix),
4376 "%s", secfile_error());
4377 }
4379 }
4380 }
4381
4382 /* Load lost wonder data. */
4383 str = secfile_lookup_str(loading->file, "player%d.lost_wonders", plrno);
4384 /* If not present, probably an old savegame; nothing to be done */
4385 if (str != NULL) {
4386 int k;
4387
4388 sg_failure_ret(strlen(str) == loading->improvement.size,
4389 "Invalid length for 'player%d.lost_wonders' ("
4390 SIZE_T_PRINTF " ~= " SIZE_T_PRINTF ")",
4391 plrno, strlen(str), loading->improvement.size);
4392 for (k = 0; k < loading->improvement.size; k++) {
4393 sg_failure_ret(str[k] == '1' || str[k] == '0',
4394 "Undefined value '%c' within "
4395 "'player%d.lost_wonders'.", plrno, str[k]);
4396
4397 if (str[k] == '1') {
4398 struct impr_type *pimprove =
4400 if (pimprove) {
4401 plr->wonders[improvement_index(pimprove)] = WONDER_LOST;
4402 }
4403 }
4404 }
4405 }
4406
4407 plr->history =
4408 secfile_lookup_int_default(loading->file, 0, "player%d.history", plrno);
4409 plr->server.huts =
4410 secfile_lookup_int_default(loading->file, 0, "player%d.hut_count", plrno);
4411}
4412
4413/************************************************************************/
4416static void sg_save_player_main(struct savedata *saving,
4417 struct player *plr)
4418{
4419 int i, k, plrno = player_number(plr);
4420 struct player_spaceship *ship = &plr->spaceship;
4421 const char *flag_names[PLRF_COUNT];
4422 int set_count;
4423
4424 /* Check status and return if not OK (sg_success FALSE). */
4425 sg_check_ret();
4426
4427 set_count = 0;
4428 for (i = 0; i < PLRF_COUNT; i++) {
4429 if (player_has_flag(plr, i)) {
4430 flag_names[set_count++] = plr_flag_id_name(i);
4431 }
4432 }
4433
4434 secfile_insert_str_vec(saving->file, flag_names, set_count,
4435 "player%d.flags", plrno);
4436
4437 secfile_insert_str(saving->file, ai_name(plr->ai),
4438 "player%d.ai_type", plrno);
4439 secfile_insert_str(saving->file, player_name(plr),
4440 "player%d.name", plrno);
4441 secfile_insert_str(saving->file, plr->username,
4442 "player%d.username", plrno);
4444 "player%d.unassigned_user", plrno);
4445 if (plr->rgb != NULL) {
4446 rgbcolor_save(saving->file, plr->rgb, "player%d.color", plrno);
4447 } else {
4448 /* Colorless players are ok in pregame */
4449 if (game_was_started()) {
4450 log_sg("Game has started, yet player %d has no color defined.", plrno);
4451 }
4452 }
4454 "player%d.ranked_username", plrno);
4456 "player%d.unassigned_ranked", plrno);
4458 "player%d.orig_username", plrno);
4459 secfile_insert_str(saving->file,
4461 : "",
4462 "player%d.delegation_username", plrno);
4464 "player%d.nation", plrno);
4465 secfile_insert_int(saving->file, plr->team ? team_index(plr->team) : -1,
4466 "player%d.team_no", plrno);
4467
4468 secfile_insert_str(saving->file,
4470 "player%d.government_name", plrno);
4471
4472 if (plr->target_government) {
4473 secfile_insert_str(saving->file,
4475 "player%d.target_government_name", plrno);
4476 }
4477
4479 "player%d.style_by_name", plrno);
4480
4481 secfile_insert_int(saving->file, plr->nturns_idle,
4482 "player%d.idle_turns", plrno);
4483 if (plr->is_male) {
4484 secfile_insert_str(saving->file, "male",
4485 "player%d.kind", plrno);
4486 } else {
4487 secfile_insert_str(saving->file, "female",
4488 "player%d.kind", plrno);
4489 }
4490 secfile_insert_bool(saving->file, plr->is_alive,
4491 "player%d.is_alive", plrno);
4492 secfile_insert_int(saving->file, plr->turns_alive,
4493 "player%d.turns_alive", plrno);
4495 "player%d.last_war", plrno);
4496 secfile_insert_bool(saving->file, plr->phase_done,
4497 "player%d.phase_done", plrno);
4498
4499 players_iterate(pplayer) {
4500 char buf[32];
4501 struct player_diplstate *ds = player_diplstate_get(plr, pplayer);
4502
4503 i = player_index(pplayer);
4504
4505 /* save diplomatic state */
4506 fc_snprintf(buf, sizeof(buf), "player%d.diplstate%d", plrno, i);
4507
4508 secfile_insert_enum(saving->file, ds->type,
4509 diplstate_type, "%s.current", buf);
4510 secfile_insert_enum(saving->file, ds->max_state,
4511 diplstate_type, "%s.closest", buf);
4513 "%s.first_contact_turn", buf);
4514 secfile_insert_int(saving->file, ds->turns_left,
4515 "%s.turns_left", buf);
4517 "%s.has_reason_to_cancel", buf);
4519 "%s.contact_turns_left", buf);
4520 secfile_insert_bool(saving->file, player_has_real_embassy(plr, pplayer),
4521 "%s.embassy", buf);
4522 secfile_insert_bool(saving->file, gives_shared_vision(plr, pplayer),
4523 "%s.gives_shared_vision", buf);
4525
4526 players_iterate(aplayer) {
4527 i = player_index(aplayer);
4528 /* save ai data */
4529 secfile_insert_int(saving->file, plr->ai_common.love[i],
4530 "player%d.ai%d.love", plrno, i);
4531 CALL_FUNC_EACH_AI(player_save_relations, plr, aplayer, saving->file, plrno);
4533
4535 "player%d.adv.wonder_city", plrno);
4536
4537 CALL_FUNC_EACH_AI(player_save, plr, saving->file, plrno);
4538
4539 /* Multipliers (policies) */
4540 i = multiplier_count();
4541
4542 for (k = 0; k < i; k++) {
4543 secfile_insert_int(saving->file, plr->multipliers[k].value,
4544 "player%d.multiplier%d.val", plrno, k);
4545 secfile_insert_int(saving->file, plr->multipliers[k].target,
4546 "player%d.multiplier%d.target", plrno, k);
4547 secfile_insert_int(saving->file, plr->multipliers[k].changed,
4548 "player%d.multiplier%d.changed", plrno, k);
4549 }
4550
4551 secfile_insert_str(saving->file, ai_level_name(plr->ai_common.skill_level),
4552 "player%d.ai.level", plrno);
4553 secfile_insert_str(saving->file, barbarian_type_name(plr->ai_common.barbarian_type),
4554 "player%d.ai.barb_type", plrno);
4555 secfile_insert_int(saving->file, plr->economic.gold,
4556 "player%d.gold", plrno);
4557 secfile_insert_int(saving->file, plr->economic.tax,
4558 "player%d.rates.tax", plrno);
4560 "player%d.rates.science", plrno);
4561 secfile_insert_int(saving->file, plr->economic.luxury,
4562 "player%d.rates.luxury", plrno);
4564 "player%d.infrapts", plrno);
4566 "player%d.research.bulbs_last_turn", plrno);
4567
4568 /* Save traits */
4569 {
4570 enum trait tr;
4571 int j;
4572
4573 for (tr = trait_begin(), j = 0; tr != trait_end(); tr = trait_next(tr), j++) {
4574 secfile_insert_int(saving->file, plr->ai_common.traits[tr].val,
4575 "player%d.trait%d.val", plrno, j);
4576 secfile_insert_int(saving->file, plr->ai_common.traits[tr].mod,
4577 "player%d.trait%d.mod", plrno, j);
4578 }
4579 }
4580
4581 /* Save achievements */
4582 {
4583 int j = 0;
4584
4585 achievements_iterate(pach) {
4586 if (achievement_player_has(pach, plr)) {
4588 "player%d.achievement%d.name", plrno, j);
4589 if (pach->first == plr) {
4590 secfile_insert_bool(saving->file, TRUE,
4591 "player%d.achievement%d.first", plrno, j);
4592 } else {
4594 "player%d.achievement%d.first", plrno, j);
4595 }
4596
4597 j++;
4598 }
4600
4601 secfile_insert_int(saving->file, j,
4602 "player%d.achievement_count", plrno);
4603 }
4604
4606 "player%d.got_first_city", plrno);
4608 "player%d.revolution_finishes", plrno);
4609
4610 /* Player score */
4611 secfile_insert_int(saving->file, plr->score.happy,
4612 "score%d.happy", plrno);
4613 secfile_insert_int(saving->file, plr->score.content,
4614 "score%d.content", plrno);
4615 secfile_insert_int(saving->file, plr->score.unhappy,
4616 "score%d.unhappy", plrno);
4617 secfile_insert_int(saving->file, plr->score.angry,
4618 "score%d.angry", plrno);
4620 secfile_insert_int(saving->file, plr->score.specialists[sp],
4621 "score%d.specialists%d", plrno, sp);
4623 secfile_insert_int(saving->file, plr->score.wonders,
4624 "score%d.wonders", plrno);
4625 secfile_insert_int(saving->file, plr->score.techs,
4626 "score%d.techs", plrno);
4627 secfile_insert_int(saving->file, plr->score.techout,
4628 "score%d.techout", plrno);
4629 secfile_insert_int(saving->file, plr->score.landarea,
4630 "score%d.landarea", plrno);
4632 "score%d.settledarea", plrno);
4634 "score%d.population", plrno);
4635 secfile_insert_int(saving->file, plr->score.cities,
4636 "score%d.cities", plrno);
4637 secfile_insert_int(saving->file, plr->score.units,
4638 "score%d.units", plrno);
4639 secfile_insert_int(saving->file, plr->score.pollution,
4640 "score%d.pollution", plrno);
4641 secfile_insert_int(saving->file, plr->score.literacy,
4642 "score%d.literacy", plrno);
4643 secfile_insert_int(saving->file, plr->score.bnp,
4644 "score%d.bnp", plrno);
4645 secfile_insert_int(saving->file, plr->score.mfg,
4646 "score%d.mfg", plrno);
4647 secfile_insert_int(saving->file, plr->score.spaceship,
4648 "score%d.spaceship", plrno);
4650 "score%d.units_built", plrno);
4652 "score%d.units_killed", plrno);
4654 "score%d.units_lost", plrno);
4655 secfile_insert_int(saving->file, plr->score.culture,
4656 "score%d.culture", plrno);
4657 secfile_insert_int(saving->file, plr->score.game,
4658 "score%d.total", plrno);
4659
4660 /* Save space ship status. */
4661 secfile_insert_int(saving->file, ship->state, "player%d.spaceship.state",
4662 plrno);
4663 if (ship->state != SSHIP_NONE) {
4664 char buf[32];
4665 char st[NUM_SS_STRUCTURALS+1];
4666 int ssi;
4667
4668 fc_snprintf(buf, sizeof(buf), "player%d.spaceship", plrno);
4669
4670 secfile_insert_int(saving->file, ship->structurals,
4671 "%s.structurals", buf);
4672 secfile_insert_int(saving->file, ship->components,
4673 "%s.components", buf);
4674 secfile_insert_int(saving->file, ship->modules,
4675 "%s.modules", buf);
4676 secfile_insert_int(saving->file, ship->fuel, "%s.fuel", buf);
4677 secfile_insert_int(saving->file, ship->propulsion, "%s.propulsion", buf);
4678 secfile_insert_int(saving->file, ship->habitation, "%s.habitation", buf);
4679 secfile_insert_int(saving->file, ship->life_support,
4680 "%s.life_support", buf);
4681 secfile_insert_int(saving->file, ship->solar_panels,
4682 "%s.solar_panels", buf);
4683
4684 for (ssi = 0; ssi < NUM_SS_STRUCTURALS; ssi++) {
4685 st[ssi] = BV_ISSET(ship->structure, ssi) ? '1' : '0';
4686 }
4687 st[ssi] = '\0';
4688 secfile_insert_str(saving->file, st, "%s.structure", buf);
4689 if (ship->state >= SSHIP_LAUNCHED) {
4690 secfile_insert_int(saving->file, ship->launch_year,
4691 "%s.launch_year", buf);
4692 }
4693 }
4694
4695 /* Save lost wonders info. */
4696 {
4697 char lost[B_LAST+1];
4698
4699 improvement_iterate(pimprove) {
4700 if (is_wonder(pimprove) && wonder_is_lost(plr, pimprove)) {
4701 lost[improvement_index(pimprove)] = '1';
4702 } else {
4703 lost[improvement_index(pimprove)] = '0';
4704 }
4706 lost[improvement_count()] = '\0';
4707 secfile_insert_str(saving->file, lost,
4708 "player%d.lost_wonders", plrno);
4709 }
4710
4711 secfile_insert_int(saving->file, plr->history,
4712 "player%d.history", plrno);
4713 secfile_insert_int(saving->file, plr->server.huts,
4714 "player%d.hut_count", plrno);
4715
4717 "player%d.border_vision", plrno);
4718}
4719
4720/************************************************************************/
4723static void sg_load_player_cities(struct loaddata *loading,
4724 struct player *plr)
4725{
4726 int ncities, i, plrno = player_number(plr);
4727 bool tasks_handled;
4728 int wlist_max_length = 0;
4729
4730 /* Check status and return if not OK (sg_success FALSE). */
4731 sg_check_ret();
4732
4733 sg_failure_ret(secfile_lookup_int(loading->file, &ncities,
4734 "player%d.ncities", plrno),
4735 "%s", secfile_error());
4736
4737 if (!plr->is_alive && ncities > 0) {
4738 log_sg("'player%d.ncities' = %d for dead player!", plrno, ncities);
4739 ncities = 0;
4740 }
4741
4742 if (!plr->server.got_first_city && ncities > 0) {
4743 /* Probably barbarians in an old savegame; fix up */
4744 plr->server.got_first_city = TRUE;
4745 }
4746
4747 /* Find longest worklist */
4748 for (i = 0; i < ncities; i++) {
4749 int wl_length = secfile_lookup_int_default(loading->file, 0,
4750 "player%d.c%d.wl_length",
4751 plrno, i);
4752
4753 wlist_max_length = MAX(wlist_max_length, wl_length);
4754 }
4755
4756 /* Load all cities of the player. */
4757 for (i = 0; i < ncities; i++) {
4758 char buf[32];
4759 struct city *pcity;
4760
4761 fc_snprintf(buf, sizeof(buf), "player%d.c%d", plrno, i);
4762
4763 /* Create a dummy city. */
4764 pcity = create_city_virtual(plr, NULL, buf);
4765 adv_city_alloc(pcity);
4766 if (!sg_load_player_city(loading, plr, pcity, buf, wlist_max_length)) {
4767 adv_city_free(pcity);
4768 destroy_city_virtual(pcity);
4769 sg_failure_ret(FALSE, "Error loading city %d of player %d.", i, plrno);
4770 }
4771
4773 idex_register_city(&wld, pcity);
4774
4775 /* Load the information about the nationality of citizens. This is done
4776 * here because the city sanity check called by citizens_update() requires
4777 * that the city is registered. */
4778 sg_load_player_city_citizens(loading, plr, pcity, buf);
4779
4780 /* After everything is loaded, but before vision. */
4781 map_claim_ownership(city_tile(pcity), plr, city_tile(pcity), TRUE);
4782
4783 /* adding the city contribution to fog-of-war */
4784 pcity->server.vision = vision_new(plr, city_tile(pcity));
4786 city_refresh_vision(pcity);
4787
4788 city_list_append(plr->cities, pcity);
4789 }
4790
4791 tasks_handled = FALSE;
4792 for (i = 0; !tasks_handled; i++) {
4793 int city_id;
4794 struct city *pcity = NULL;
4795
4796 city_id = secfile_lookup_int_default(loading->file, -1, "player%d.task%d.city",
4797 plrno, i);
4798
4799 if (city_id != -1) {
4800 pcity = player_city_by_number(plr, city_id);
4801 }
4802
4803 if (pcity != NULL) {
4804 const char *str;
4805 int nat_x, nat_y;
4806 struct worker_task *ptask = fc_malloc(sizeof(struct worker_task));
4807
4808 nat_x = secfile_lookup_int_default(loading->file, -1, "player%d.task%d.x", plrno, i);
4809 nat_y = secfile_lookup_int_default(loading->file, -1, "player%d.task%d.y", plrno, i);
4810
4811 ptask->ptile = native_pos_to_tile(&(wld.map), nat_x, nat_y);
4812
4813 str = secfile_lookup_str(loading->file, "player%d.task%d.activity", plrno, i);
4814 ptask->act = unit_activity_by_name(str, fc_strcasecmp);
4815
4816 sg_failure_ret(unit_activity_is_valid(ptask->act),
4817 "Unknown workertask activity %s", str);
4818
4819 str = secfile_lookup_str(loading->file, "player%d.task%d.target", plrno, i);
4820
4821 if (strcmp("-", str)) {
4823
4824 sg_failure_ret(ptask->tgt != NULL,
4825 "Unknown workertask target %s", str);
4826 } else {
4827 ptask->tgt = NULL;
4828
4829 if (ptask->act == ACTIVITY_IRRIGATE) {
4830 ptask->act = ACTIVITY_CULTIVATE;
4831 } else if (ptask->act == ACTIVITY_MINE) {
4832 ptask->act = ACTIVITY_MINE;
4833 }
4834 }
4835
4836 ptask->want = secfile_lookup_int_default(loading->file, 1,
4837 "player%d.task%d.want", plrno, i);
4838
4839 worker_task_list_append(pcity->task_reqs, ptask);
4840 } else {
4841 tasks_handled = TRUE;
4842 }
4843 }
4844}
4845
4846/************************************************************************/
4849static bool sg_load_player_city(struct loaddata *loading, struct player *plr,
4850 struct city *pcity, const char *citystr,
4851 int wlist_max_length)
4852{
4853 struct player *past;
4854 const char *kind, *name, *str;
4855 int id, i, repair, sp_count = 0, workers = 0, value;
4856 int nat_x, nat_y;
4857 citizens size;
4858 const char *stylename;
4859 int partner;
4860 int want;
4861 const struct civ_map *nmap = &(wld.map);
4862
4863 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_x, "%s.x", citystr),
4864 FALSE, "%s", secfile_error());
4865 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_y, "%s.y", citystr),
4866 FALSE, "%s", secfile_error());
4867 pcity->tile = native_pos_to_tile(&(wld.map), nat_x, nat_y);
4868 sg_warn_ret_val(NULL != pcity->tile, FALSE,
4869 "%s has invalid center tile (%d, %d)",
4870 citystr, nat_x, nat_y);
4871 sg_warn_ret_val(NULL == tile_city(pcity->tile), FALSE,
4872 "%s duplicates city (%d, %d)", citystr, nat_x, nat_y);
4873
4874 /* Instead of dying, use 'citystr' string for damaged name. */
4875 city_name_set(pcity, secfile_lookup_str_default(loading->file, citystr,
4876 "%s.name", citystr));
4877
4878 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->id, "%s.id",
4879 citystr), FALSE, "%s", secfile_error());
4880
4881 id = secfile_lookup_int_default(loading->file, player_number(plr),
4882 "%s.original", citystr);
4883 past = player_by_number(id);
4884 if (NULL != past) {
4885 pcity->original = past;
4886 }
4887
4888 sg_warn_ret_val(secfile_lookup_int(loading->file, &value, "%s.size",
4889 citystr), FALSE, "%s", secfile_error());
4890 size = (citizens)value; /* set the correct type */
4891 sg_warn_ret_val(value == (int)size, FALSE,
4892 "Invalid city size: %d, set to %d", value, size);
4893 city_size_set(pcity, size);
4894
4895 for (i = 0; i < loading->specialist.size; i++) {
4896 sg_warn_ret_val(secfile_lookup_int(loading->file, &value, "%s.nspe%d",
4897 citystr, i),
4898 FALSE, "%s", secfile_error());
4899 pcity->specialists[specialist_index(loading->specialist.order[i])]
4900 = (citizens)value;
4901 sp_count += value;
4902 }
4903
4904 partner = secfile_lookup_int_default(loading->file, 0, "%s.traderoute0", citystr);
4905 for (i = 0; partner != 0; i++) {
4906 struct trade_route *proute = fc_malloc(sizeof(struct trade_route));
4907 const char *dir;
4908 const char *good_str;
4909
4910 /* Append to routes list immediately, so the pointer can be found for freeing
4911 * even if we abort */
4912 trade_route_list_append(pcity->routes, proute);
4913
4914 proute->partner = partner;
4915 dir = secfile_lookup_str(loading->file, "%s.route_direction%d", citystr, i);
4916 sg_warn_ret_val(dir != NULL, FALSE,
4917 "No traderoute direction found for %s", citystr);
4918 proute->dir = route_direction_by_name(dir, fc_strcasecmp);
4919 sg_warn_ret_val(route_direction_is_valid(proute->dir), FALSE,
4920 "Illegal route direction %s", dir);
4921 good_str = secfile_lookup_str(loading->file, "%s.route_good%d", citystr, i);
4922 sg_warn_ret_val(dir != NULL, FALSE,
4923 "No good found for %s", citystr);
4924 proute->goods = goods_by_rule_name(good_str);
4925 sg_warn_ret_val(proute->goods != NULL, FALSE,
4926 "Illegal good %s", good_str);
4927
4928 /* Next one */
4930 "%s.traderoute%d", citystr, i + 1);
4931 }
4932
4933 for (; i < MAX_TRADE_ROUTES; i++) {
4934 (void) secfile_entry_lookup(loading->file, "%s.traderoute%d", citystr, i);
4935 (void) secfile_entry_lookup(loading->file, "%s.route_direction%d", citystr, i);
4936 (void) secfile_entry_lookup(loading->file, "%s.route_good%d", citystr, i);
4937 }
4938
4940 "%s.food_stock", citystr),
4941 FALSE, "%s", secfile_error());
4943 "%s.shield_stock", citystr),
4944 FALSE, "%s", secfile_error());
4945 pcity->history =
4946 secfile_lookup_int_default(loading->file, 0, "%s.history", citystr);
4947
4948 pcity->airlift =
4949 secfile_lookup_int_default(loading->file, 0, "%s.airlift", citystr);
4950 pcity->was_happy =
4951 secfile_lookup_bool_default(loading->file, FALSE, "%s.was_happy",
4952 citystr);
4953
4954 pcity->turn_plague =
4955 secfile_lookup_int_default(loading->file, 0, "%s.turn_plague", citystr);
4956
4958 "%s.anarchy", citystr),
4959 FALSE, "%s", secfile_error());
4960 pcity->rapture =
4961 secfile_lookup_int_default(loading->file, 0, "%s.rapture", citystr);
4962 pcity->steal =
4963 secfile_lookup_int_default(loading->file, 0, "%s.steal", citystr);
4964
4966 "%s.turn_founded", citystr),
4967 FALSE, "%s", secfile_error());
4968 sg_warn_ret_val(secfile_lookup_bool(loading->file, &pcity->did_buy, "%s.did_buy",
4969 citystr), FALSE, "%s", secfile_error());
4970 sg_warn_ret_val(secfile_lookup_bool(loading->file, &pcity->did_sell, "%s.did_sell",
4971 citystr), FALSE, "%s", secfile_error());
4972
4974 "%s.turn_last_built", citystr),
4975 FALSE, "%s", secfile_error());
4976
4977 kind = secfile_lookup_str(loading->file, "%s.currently_building_kind",
4978 citystr);
4979 name = secfile_lookup_str(loading->file, "%s.currently_building_name",
4980 citystr);
4981 pcity->production = universal_by_rule_name(kind, name);
4982 sg_warn_ret_val(pcity->production.kind != universals_n_invalid(), FALSE,
4983 "%s.currently_building: unknown \"%s\" \"%s\".",
4984 citystr, kind, name);
4985
4986 want = secfile_lookup_int_default(loading->file, 0,
4987 "%s.current_want", citystr);
4988 if (pcity->production.kind == VUT_IMPROVEMENT) {
4989 pcity->server.adv->
4990 building_want[improvement_index(pcity->production.value.building)]
4991 = want;
4992 }
4993
4994 kind = secfile_lookup_str(loading->file, "%s.changed_from_kind",
4995 citystr);
4996 name = secfile_lookup_str(loading->file, "%s.changed_from_name",
4997 citystr);
4999 sg_warn_ret_val(pcity->changed_from.kind != universals_n_invalid(), FALSE,
5000 "%s.changed_from: unknown \"%s\" \"%s\".",
5001 citystr, kind, name);
5002
5003 pcity->before_change_shields =
5005 "%s.before_change_shields", citystr);
5006 pcity->caravan_shields =
5007 secfile_lookup_int_default(loading->file, 0,
5008 "%s.caravan_shields", citystr);
5009 pcity->disbanded_shields =
5010 secfile_lookup_int_default(loading->file, 0,
5011 "%s.disbanded_shields", citystr);
5013 secfile_lookup_int_default(loading->file, 0,
5014 "%s.last_turns_shield_surplus",
5015 citystr);
5016
5017 stylename = secfile_lookup_str_default(loading->file, NULL,
5018 "%s.style", citystr);
5019 if (stylename != NULL) {
5020 pcity->style = city_style_by_rule_name(stylename);
5021 } else {
5022 pcity->style = 0;
5023 }
5024 if (pcity->style < 0) {
5025 pcity->style = city_style(pcity);
5026 }
5027
5028 pcity->server.synced = FALSE; /* must re-sync with clients */
5029
5030 /* Initialise list of city improvements. */
5031 for (i = 0; i < ARRAY_SIZE(pcity->built); i++) {
5032 pcity->built[i].turn = I_NEVER;
5033 }
5034
5035 /* Load city improvements. */
5036 str = secfile_lookup_str(loading->file, "%s.improvements", citystr);
5037 sg_warn_ret_val(str != NULL, FALSE, "%s", secfile_error());
5038 sg_warn_ret_val(strlen(str) == loading->improvement.size, FALSE,
5039 "Invalid length of '%s.improvements' ("
5040 SIZE_T_PRINTF " ~= " SIZE_T_PRINTF ").",
5041 citystr, strlen(str), loading->improvement.size);
5042 for (i = 0; i < loading->improvement.size; i++) {
5043 sg_warn_ret_val(str[i] == '1' || str[i] == '0', FALSE,
5044 "Undefined value '%c' within '%s.improvements'.",
5045 str[i], citystr)
5046
5047 if (str[i] == '1') {
5048 struct impr_type *pimprove =
5050
5051 if (pimprove) {
5052 city_add_improvement(pcity, pimprove);
5053 }
5054 }
5055 }
5056
5057 sg_failure_ret_val(loading->worked_tiles != NULL, FALSE,
5058 "No worked tiles map defined.");
5059
5060 city_freeze_workers(pcity);
5061
5062 /* Load new savegame with variable (squared) city radius and worked
5063 * tiles map */
5064
5065 int radius_sq
5066 = secfile_lookup_int_default(loading->file, -1, "%s.city_radius_sq",
5067 citystr);
5068 city_map_radius_sq_set(pcity, radius_sq);
5069
5070 city_tile_iterate(nmap, CITY_MAP_MAX_RADIUS_SQ, city_tile(pcity), ptile) {
5071 if (loading->worked_tiles[ptile->index] == pcity->id) {
5072 if (sq_map_distance(ptile, pcity->tile) > radius_sq) {
5073 log_sg("[%s] '%s' (%d, %d) has worker outside current radius "
5074 "at (%d, %d); repairing", citystr, city_name_get(pcity),
5075 TILE_XY(pcity->tile), TILE_XY(ptile));
5077 sp_count++;
5078 } else {
5079 tile_set_worked(ptile, pcity);
5080 workers++;
5081 }
5082
5083#ifdef FREECIV_DEBUG
5084 /* Set this tile to unused; a check for not reset tiles is
5085 * included in game_load_internal() */
5086 loading->worked_tiles[ptile->index] = -1;
5087#endif /* FREECIV_DEBUG */
5088 }
5090
5091 if (tile_worked(city_tile(pcity)) != pcity) {
5092 struct city *pwork = tile_worked(city_tile(pcity));
5093
5094 if (NULL != pwork) {
5095 log_sg("[%s] city center of '%s' (%d,%d) [%d] is worked by '%s' "
5096 "(%d,%d) [%d]; repairing", citystr, city_name_get(pcity),
5097 TILE_XY(city_tile(pcity)), city_size_get(pcity), city_name_get(pwork),
5098 TILE_XY(city_tile(pwork)), city_size_get(pwork));
5099
5100 tile_set_worked(city_tile(pcity), NULL); /* Remove tile from pwork */
5102 auto_arrange_workers(pwork);
5103 } else {
5104 log_sg("[%s] city center of '%s' (%d,%d) [%d] is empty; repairing",
5105 citystr, city_name_get(pcity), TILE_XY(city_tile(pcity)),
5106 city_size_get(pcity));
5107 }
5108
5109 /* Repair pcity */
5110 tile_set_worked(city_tile(pcity), pcity);
5111 city_repair_size(pcity, -1);
5112 }
5113
5114 repair = city_size_get(pcity) - sp_count - (workers - FREE_WORKED_TILES);
5115 if (0 != repair) {
5116 log_sg("[%s] size mismatch for '%s' (%d,%d): size [%d] != "
5117 "(workers [%d] - free worked tiles [%d]) + specialists [%d]",
5118 citystr, city_name_get(pcity), TILE_XY(city_tile(pcity)), city_size_get(pcity),
5119 workers, FREE_WORKED_TILES, sp_count);
5120
5121 /* Repair pcity */
5122 city_repair_size(pcity, repair);
5123 }
5124
5125 /* worklist_init() done in create_city_virtual() */
5126 worklist_load(loading->file, wlist_max_length, &pcity->worklist, "%s", citystr);
5127
5128 /* Load city options. */
5129 BV_CLR_ALL(pcity->city_options);
5130 for (i = 0; i < CITYO_LAST; i++) {
5131 if (secfile_lookup_bool_default(loading->file, FALSE, "%s.option%d",
5132 citystr, i)) {
5133 BV_SET(pcity->city_options, i);
5134 }
5135 }
5136
5137 /* Load the city rally point. */
5138 {
5139 int len = secfile_lookup_int_default(loading->file, 0,
5140 "%s.rally_point_length", citystr);
5141 int unconverted;
5142
5143 pcity->rally_point.length = len;
5144 if (len > 0) {
5145 const char *rally_orders, *rally_dirs, *rally_activities;
5146
5147 pcity->rally_point.orders
5148 = fc_malloc(len * sizeof(*(pcity->rally_point.orders)));
5149 pcity->rally_point.persistent
5151 "%s.rally_point_persistent", citystr);
5152 pcity->rally_point.vigilant
5154 "%s.rally_point_vigilant", citystr);
5155
5156 rally_orders
5157 = secfile_lookup_str_default(loading->file, "",
5158 "%s.rally_point_orders", citystr);
5159 rally_dirs
5160 = secfile_lookup_str_default(loading->file, "",
5161 "%s.rally_point_dirs", citystr);
5162 rally_activities
5163 = secfile_lookup_str_default(loading->file, "",
5164 "%s.rally_point_activities", citystr);
5165
5166 for (i = 0; i < len; i++) {
5167 struct unit_order *order = &pcity->rally_point.orders[i];
5168
5169 if (rally_orders[i] == '\0' || rally_dirs[i] == '\0'
5170 || rally_activities[i] == '\0') {
5171 log_sg("Invalid rally point.");
5172 free(pcity->rally_point.orders);
5173 pcity->rally_point.orders = NULL;
5174 pcity->rally_point.length = 0;
5175 break;
5176 }
5177 order->order = char2order(rally_orders[i]);
5178 order->dir = char2dir(rally_dirs[i]);
5179 order->activity = char2activity(rally_activities[i]);
5180
5181 unconverted = secfile_lookup_int_default(loading->file, ACTION_NONE,
5182 "%s.rally_point_action_vec,%d",
5183 citystr, i);
5184
5185 if (unconverted >= 0 && unconverted < loading->action.size) {
5186 /* Look up what action id the unconverted number represents. */
5187 order->action = loading->action.order[unconverted];
5188 } else {
5189 if (order->order == ORDER_PERFORM_ACTION) {
5190 log_sg("Invalid action id in order for city rally point %d",
5191 pcity->id);
5192 }
5193
5194 order->action = ACTION_NONE;
5195 }
5196
5197 order->target
5199 "%s.rally_point_tgt_vec,%d",
5200 citystr, i);
5201 order->sub_target
5202 = secfile_lookup_int_default(loading->file, -1,
5203 "%s.rally_point_sub_tgt_vec,%d",
5204 citystr, i);
5205 }
5206 } else {
5207 pcity->rally_point.orders = NULL;
5208
5209 (void) secfile_entry_lookup(loading->file, "%s.rally_point_persistent",
5210 citystr);
5211 (void) secfile_entry_lookup(loading->file, "%s.rally_point_vigilant",
5212 citystr);
5213 (void) secfile_entry_lookup(loading->file, "%s.rally_point_orders",
5214 citystr);
5215 (void) secfile_entry_lookup(loading->file, "%s.rally_point_dirs",
5216 citystr);
5217 (void) secfile_entry_lookup(loading->file, "%s.rally_point_activities",
5218 citystr);
5219 (void) secfile_entry_lookup(loading->file, "%s.rally_point_action_vec",
5220 citystr);
5221 (void) secfile_entry_lookup(loading->file,
5222 "%s.rally_point_tgt_vec", citystr);
5223 (void) secfile_entry_lookup(loading->file,
5224 "%s.rally_point_sub_tgt_vec", citystr);
5225 }
5226 }
5227
5228 /* Load the city manager parameters. */
5229 {
5230 bool enabled = secfile_lookup_bool_default(loading->file, FALSE,
5231 "%s.cma_enabled", citystr);
5232 if (enabled) {
5233 struct cm_parameter *param = fc_calloc(1, sizeof(struct cm_parameter));
5234
5235 for (i = 0; i < O_LAST; i++) {
5237 loading->file, 0, "%s.cma_minimal_surplus,%d", citystr, i);
5239 loading->file, 0, "%s.cma_factor,%d", citystr, i);
5240 }
5241
5243 loading->file, FALSE, "%s.max_growth", citystr);
5245 loading->file, FALSE, "%s.require_happy", citystr);
5247 loading->file, FALSE, "%s.allow_disorder", citystr);
5249 loading->file, FALSE, "%s.allow_specialists", citystr);
5251 loading->file, 0, "%s.happy_factor", citystr);
5252 pcity->cm_parameter = param;
5253 } else {
5254 pcity->cm_parameter = NULL;
5255
5256 for (i = 0; i < O_LAST; i++) {
5257 (void) secfile_entry_lookup(loading->file,
5258 "%s.cma_minimal_surplus,%d", citystr, i);
5259 (void) secfile_entry_lookup(loading->file,
5260 "%s.cma_factor,%d", citystr, i);
5261 }
5262
5263 (void) secfile_entry_lookup(loading->file, "%s.max_growth",
5264 citystr);
5265 (void) secfile_entry_lookup(loading->file, "%s.require_happy",
5266 citystr);
5267 (void) secfile_entry_lookup(loading->file, "%s.allow_disorder",
5268 citystr);
5269 (void) secfile_entry_lookup(loading->file, "%s.allow_specialists",
5270 citystr);
5271 (void) secfile_entry_lookup(loading->file, "%s.happy_factor",
5272 citystr);
5273 }
5274 }
5275
5276 CALL_FUNC_EACH_AI(city_load, loading->file, pcity, citystr);
5277
5278 return TRUE;
5279}
5280
5281/************************************************************************/
5284static void sg_load_player_city_citizens(struct loaddata *loading,
5285 struct player *plr,
5286 struct city *pcity,
5287 const char *citystr)
5288{
5290 citizens size;
5291
5292 citizens_init(pcity);
5293 player_slots_iterate(pslot) {
5294 int nationality;
5295
5296 nationality = secfile_lookup_int_default(loading->file, -1,
5297 "%s.citizen%d", citystr,
5298 player_slot_index(pslot));
5299 if (nationality > 0 && !player_slot_is_used(pslot)) {
5300 log_sg("Citizens of an invalid nation for %s (player slot %d)!",
5301 city_name_get(pcity), player_slot_index(pslot));
5302 continue;
5303 }
5304
5305 if (nationality != -1 && player_slot_is_used(pslot)) {
5306 sg_warn(nationality >= 0 && nationality <= MAX_CITY_SIZE,
5307 "Invalid value for citizens of player %d in %s: %d.",
5308 player_slot_index(pslot), city_name_get(pcity), nationality);
5309 citizens_nation_set(pcity, pslot, nationality);
5310 }
5312 /* Sanity check. */
5313 size = citizens_count(pcity);
5314 if (size != city_size_get(pcity)) {
5315 if (size != 0) {
5316 /* size == 0 can be result from the fact that ruleset had no
5317 * nationality enabled at saving time, so no citizens at all
5318 * were saved. But something more serious must be going on if
5319 * citizens have been saved partially - if some of them are there. */
5320 log_sg("City size and number of citizens does not match in %s "
5321 "(%d != %d)! Repairing ...", city_name_get(pcity),
5322 city_size_get(pcity), size);
5323 }
5324 citizens_update(pcity, NULL);
5325 }
5326 }
5327}
5328
5329/************************************************************************/
5332static void sg_save_player_cities(struct savedata *saving,
5333 struct player *plr)
5334{
5335 int wlist_max_length = 0, rally_point_max_length = 0, routes_max = 0;
5336 int i = 0;
5337 int plrno = player_number(plr);
5339
5340 /* Check status and return if not OK (sg_success FALSE). */
5341 sg_check_ret();
5342
5343 secfile_insert_int(saving->file, city_list_size(plr->cities),
5344 "player%d.ncities", plrno);
5345
5347 /* Initialise the nation list for the citizens information. */
5348 player_slots_iterate(pslot) {
5351 }
5352
5353 /* First determine length of longest worklist, rally point order, and the
5354 * nationalities we have. */
5355 city_list_iterate(plr->cities, pcity) {
5356 int routes;
5357
5358 /* Check the sanity of the city. */
5359 city_refresh(pcity);
5360 sanity_check_city(pcity);
5361
5362 if (pcity->worklist.length > wlist_max_length) {
5363 wlist_max_length = pcity->worklist.length;
5364 }
5365
5366 if (pcity->rally_point.length > rally_point_max_length) {
5367 rally_point_max_length = pcity->rally_point.length;
5368 }
5369
5370 routes = city_num_trade_routes(pcity);
5371 if (routes > routes_max) {
5372 routes_max = routes;
5373 }
5374
5376 /* Find all nations of the citizens,*/
5377 players_iterate(pplayer) {
5378 if (!nations[player_index(pplayer)]
5379 && citizens_nation_get(pcity, pplayer->slot) != 0) {
5380 nations[player_index(pplayer)] = TRUE;
5381 }
5383 }
5385
5386 city_list_iterate(plr->cities, pcity) {
5387 struct tile *pcenter = city_tile(pcity);
5388 char impr_buf[B_LAST + 1];
5389 char buf[32];
5390 int j, nat_x, nat_y;
5391
5392 fc_snprintf(buf, sizeof(buf), "player%d.c%d", plrno, i);
5393
5394
5396 secfile_insert_int(saving->file, nat_y, "%s.y", buf);
5397 secfile_insert_int(saving->file, nat_x, "%s.x", buf);
5398
5399 secfile_insert_int(saving->file, pcity->id, "%s.id", buf);
5400
5401 if (pcity->original != NULL) {
5402 secfile_insert_int(saving->file, player_number(pcity->original),
5403 "%s.original", buf);
5404 } else {
5405 secfile_insert_int(saving->file, -1, "%s.original", buf);
5406 }
5407 secfile_insert_int(saving->file, city_size_get(pcity), "%s.size", buf);
5408
5409 j = 0;
5411 secfile_insert_int(saving->file, pcity->specialists[sp], "%s.nspe%d",
5412 buf, j++);
5414
5415 j = 0;
5416 trade_routes_iterate(pcity, proute) {
5417 secfile_insert_int(saving->file, proute->partner, "%s.traderoute%d",
5418 buf, j);
5419 secfile_insert_str(saving->file, route_direction_name(proute->dir),
5420 "%s.route_direction%d", buf, j);
5421 secfile_insert_str(saving->file, goods_rule_name(proute->goods),
5422 "%s.route_good%d", buf, j);
5423 j++;
5425
5426 /* Save dummy values to keep tabular format happy */
5427 for (; j < routes_max; j++) {
5428 secfile_insert_int(saving->file, 0, "%s.traderoute%d", buf, j);
5429 secfile_insert_str(saving->file, route_direction_name(RDIR_BIDIRECTIONAL),
5430 "%s.route_direction%d", buf, j);
5432 "%s.route_good%d", buf, j);
5433 }
5434
5435 secfile_insert_int(saving->file, pcity->food_stock, "%s.food_stock",
5436 buf);
5437 secfile_insert_int(saving->file, pcity->shield_stock, "%s.shield_stock",
5438 buf);
5439 secfile_insert_int(saving->file, pcity->history, "%s.history",
5440 buf);
5441
5442 secfile_insert_int(saving->file, pcity->airlift, "%s.airlift",
5443 buf);
5444 secfile_insert_bool(saving->file, pcity->was_happy, "%s.was_happy",
5445 buf);
5446 secfile_insert_int(saving->file, pcity->turn_plague, "%s.turn_plague",
5447 buf);
5448
5449 secfile_insert_int(saving->file, pcity->anarchy, "%s.anarchy", buf);
5450 secfile_insert_int(saving->file, pcity->rapture, "%s.rapture", buf);
5451 secfile_insert_int(saving->file, pcity->steal, "%s.steal", buf);
5452 secfile_insert_int(saving->file, pcity->turn_founded, "%s.turn_founded",
5453 buf);
5454 secfile_insert_bool(saving->file, pcity->did_buy, "%s.did_buy", buf);
5455 secfile_insert_bool(saving->file, pcity->did_sell, "%s.did_sell", buf);
5456 secfile_insert_int(saving->file, pcity->turn_last_built,
5457 "%s.turn_last_built", buf);
5458
5459 /* for visual debugging, variable length strings together here */
5460 secfile_insert_str(saving->file, city_name_get(pcity), "%s.name", buf);
5461
5462 secfile_insert_str(saving->file, universal_type_rule_name(&pcity->production),
5463 "%s.currently_building_kind", buf);
5464 secfile_insert_str(saving->file, universal_rule_name(&pcity->production),
5465 "%s.currently_building_name", buf);
5466
5467 if (pcity->production.kind == VUT_IMPROVEMENT) {
5468 secfile_insert_int(saving->file,
5469 pcity->server.adv->
5470 building_want[improvement_index(pcity->production.value.building)],
5471 "%s.current_want", buf);
5472 } else {
5473 secfile_insert_int(saving->file, 0,
5474 "%s.current_want", buf);
5475 }
5476
5477 secfile_insert_str(saving->file, universal_type_rule_name(&pcity->changed_from),
5478 "%s.changed_from_kind", buf);
5479 secfile_insert_str(saving->file, universal_rule_name(&pcity->changed_from),
5480 "%s.changed_from_name", buf);
5481
5482 secfile_insert_int(saving->file, pcity->before_change_shields,
5483 "%s.before_change_shields", buf);
5484 secfile_insert_int(saving->file, pcity->caravan_shields,
5485 "%s.caravan_shields", buf);
5486 secfile_insert_int(saving->file, pcity->disbanded_shields,
5487 "%s.disbanded_shields", buf);
5488 secfile_insert_int(saving->file, pcity->last_turns_shield_surplus,
5489 "%s.last_turns_shield_surplus", buf);
5490
5491 secfile_insert_str(saving->file, city_style_rule_name(pcity->style),
5492 "%s.style", buf);
5493
5494 /* Save the squared city radius and all tiles within the corresponding
5495 * city map. */
5496 secfile_insert_int(saving->file, pcity->city_radius_sq,
5497 "player%d.c%d.city_radius_sq", plrno, i);
5498 /* The tiles worked by the city are saved using the main map.
5499 * See also sg_save_map_worked(). */
5500
5501 /* Save improvement list as bytevector. Note that improvement order
5502 * is saved in savefile.improvement_order. */
5503 improvement_iterate(pimprove) {
5504 impr_buf[improvement_index(pimprove)]
5505 = (pcity->built[improvement_index(pimprove)].turn <= I_NEVER) ? '0'
5506 : '1';
5508 impr_buf[improvement_count()] = '\0';
5509
5510 sg_failure_ret(strlen(impr_buf) < sizeof(impr_buf),
5511 "Invalid size of the improvement vector (%s.improvements: "
5512 SIZE_T_PRINTF " < " SIZE_T_PRINTF ").", buf,
5513 strlen(impr_buf), sizeof(impr_buf));
5514 secfile_insert_str(saving->file, impr_buf, "%s.improvements", buf);
5515
5516 worklist_save(saving->file, &pcity->worklist, wlist_max_length, "%s",
5517 buf);
5518
5519 for (j = 0; j < CITYO_LAST; j++) {
5520 secfile_insert_bool(saving->file, BV_ISSET(pcity->city_options, j),
5521 "%s.option%d", buf, j);
5522 }
5523
5524 CALL_FUNC_EACH_AI(city_save, saving->file, pcity, buf);
5525
5527 /* Save nationality of the citizens,*/
5528 players_iterate(pplayer) {
5529 if (nations[player_index(pplayer)]) {
5530 secfile_insert_int(saving->file,
5531 citizens_nation_get(pcity, pplayer->slot),
5532 "%s.citizen%d", buf, player_index(pplayer));
5533 }
5535 }
5536
5537 secfile_insert_int(saving->file, pcity->rally_point.length,
5538 "%s.rally_point_length", buf);
5539 if (pcity->rally_point.length) {
5540 int len = pcity->rally_point.length;
5541 char orders[len + 1], dirs[len + 1], activities[len + 1];
5542 int actions[len];
5543 int targets[len];
5544 int sub_targets[len];
5545
5546 secfile_insert_bool(saving->file, pcity->rally_point.persistent,
5547 "%s.rally_point_persistent", buf);
5548 secfile_insert_bool(saving->file, pcity->rally_point.vigilant,
5549 "%s.rally_point_vigilant", buf);
5550
5551 for (j = 0; j < len; j++) {
5552 orders[j] = order2char(pcity->rally_point.orders[j].order);
5553 dirs[j] = '?';
5554 activities[j] = '?';
5555 targets[j] = NO_TARGET;
5556 sub_targets[j] = NO_TARGET;
5557 actions[j] = -1;
5558 switch (pcity->rally_point.orders[j].order) {
5559 case ORDER_MOVE:
5560 case ORDER_ACTION_MOVE:
5561 dirs[j] = dir2char(pcity->rally_point.orders[j].dir);
5562 break;
5563 case ORDER_ACTIVITY:
5564 sub_targets[j] = pcity->rally_point.orders[j].sub_target;
5565 activities[j]
5566 = activity2char(pcity->rally_point.orders[j].activity);
5567 break;
5569 actions[j] = pcity->rally_point.orders[j].action;
5570 targets[j] = pcity->rally_point.orders[j].target;
5571 sub_targets[j] = pcity->rally_point.orders[j].sub_target;
5572 break;
5573 case ORDER_FULL_MP:
5574 case ORDER_LAST:
5575 break;
5576 }
5577 }
5578 orders[len] = dirs[len] = activities[len] = '\0';
5579
5580 secfile_insert_str(saving->file, orders, "%s.rally_point_orders", buf);
5581 secfile_insert_str(saving->file, dirs, "%s.rally_point_dirs", buf);
5582 secfile_insert_str(saving->file, activities,
5583 "%s.rally_point_activities", buf);
5584
5586 "%s.rally_point_action_vec", buf);
5587 /* Fill in dummy values for order targets so the registry will save
5588 * the unit table in a tabular format. */
5589 for (j = len; j < rally_point_max_length; j++) {
5590 secfile_insert_int(saving->file, -1, "%s.rally_point_action_vec,%d",
5591 buf, j);
5592 }
5593
5594 secfile_insert_int_vec(saving->file, targets, len,
5595 "%s.rally_point_tgt_vec", buf);
5596 /* Fill in dummy values for order targets so the registry will save
5597 * the unit table in a tabular format. */
5598 for (j = len; j < rally_point_max_length; j++) {
5600 "%s.rally_point_tgt_vec,%d", buf, j);
5601 }
5602
5603 secfile_insert_int_vec(saving->file, sub_targets, len,
5604 "%s.rally_point_sub_tgt_vec", buf);
5605 /* Fill in dummy values for order targets so the registry will save
5606 * the unit table in a tabular format. */
5607 for (j = len; j < rally_point_max_length; j++) {
5608 secfile_insert_int(saving->file, -1, "%s.rally_point_sub_tgt_vec,%d",
5609 buf, j);
5610 }
5611 } else {
5612 /* Put all the same fields into the savegame - otherwise the
5613 * registry code can't correctly use a tabular format and the
5614 * savegame will be bigger. */
5615 secfile_insert_bool(saving->file, FALSE, "%s.rally_point_persistent",
5616 buf);
5617 secfile_insert_bool(saving->file, FALSE, "%s.rally_point_vigilant",
5618 buf);
5619 secfile_insert_str(saving->file, "-", "%s.rally_point_orders", buf);
5620 secfile_insert_str(saving->file, "-", "%s.rally_point_dirs", buf);
5621 secfile_insert_str(saving->file, "-", "%s.rally_point_activities",
5622 buf);
5623
5624 /* Fill in dummy values for order targets so the registry will save
5625 * the unit table in a tabular format. */
5626
5627 /* The start of a vector has no number. */
5628 secfile_insert_int(saving->file, -1, "%s.rally_point_action_vec",
5629 buf);
5630 for (j = 1; j < rally_point_max_length; j++) {
5631 secfile_insert_int(saving->file, -1, "%s.rally_point_action_vec,%d",
5632 buf, j);
5633 }
5634
5635 /* The start of a vector has no number. */
5636 secfile_insert_int(saving->file, NO_TARGET, "%s.rally_point_tgt_vec",
5637 buf);
5638 for (j = 1; j < rally_point_max_length; j++) {
5640 "%s.rally_point_tgt_vec,%d", buf, j);
5641 }
5642
5643 /* The start of a vector has no number. */
5644 secfile_insert_int(saving->file, -1, "%s.rally_point_sub_tgt_vec",
5645 buf);
5646 for (j = 1; j < rally_point_max_length; j++) {
5647 secfile_insert_int(saving->file, -1, "%s.rally_point_sub_tgt_vec,%d",
5648 buf, j);
5649 }
5650 }
5651
5652 secfile_insert_bool(saving->file, pcity->cm_parameter != NULL,
5653 "%s.cma_enabled", buf);
5654 if (pcity->cm_parameter) {
5656 pcity->cm_parameter->minimal_surplus, O_LAST,
5657 "%s.cma_minimal_surplus", buf);
5659 pcity->cm_parameter->factor, O_LAST,
5660 "%s.cma_factor", buf);
5661 secfile_insert_bool(saving->file, pcity->cm_parameter->max_growth,
5662 "%s.max_growth", buf);
5663 secfile_insert_bool(saving->file, pcity->cm_parameter->require_happy,
5664 "%s.require_happy", buf);
5665 secfile_insert_bool(saving->file, pcity->cm_parameter->allow_disorder,
5666 "%s.allow_disorder", buf);
5667 secfile_insert_bool(saving->file,
5668 pcity->cm_parameter->allow_specialists,
5669 "%s.allow_specialists", buf);
5670 secfile_insert_int(saving->file, pcity->cm_parameter->happy_factor,
5671 "%s.happy_factor", buf);
5672 } else {
5673 int zeros[O_LAST];
5674
5675 memset(zeros, 0, sizeof(zeros));
5676 secfile_insert_int_vec(saving->file, zeros, O_LAST,
5677 "%s.cma_minimal_surplus", buf);
5678 secfile_insert_int_vec(saving->file, zeros, O_LAST,
5679 "%s.cma_factor", buf);
5680 secfile_insert_bool(saving->file, FALSE, "%s.max_growth", buf);
5681 secfile_insert_bool(saving->file, FALSE, "%s.require_happy", buf);
5682 secfile_insert_bool(saving->file, FALSE, "%s.allow_disorder", buf);
5683 secfile_insert_bool(saving->file, FALSE, "%s.allow_specialists", buf);
5684 secfile_insert_int(saving->file, 0, "%s.happy_factor", buf);
5685 }
5686
5687 i++;
5689
5690 i = 0;
5691 city_list_iterate(plr->cities, pcity) {
5692 worker_task_list_iterate(pcity->task_reqs, ptask) {
5693 int nat_x, nat_y;
5694
5695 index_to_native_pos(&nat_x, &nat_y, tile_index(ptask->ptile));
5696 secfile_insert_int(saving->file, pcity->id, "player%d.task%d.city",
5697 plrno, i);
5698 secfile_insert_int(saving->file, nat_y, "player%d.task%d.y", plrno, i);
5699 secfile_insert_int(saving->file, nat_x, "player%d.task%d.x", plrno, i);
5700 secfile_insert_str(saving->file, unit_activity_name(ptask->act),
5701 "player%d.task%d.activity",
5702 plrno, i);
5703 if (ptask->tgt != NULL) {
5704 secfile_insert_str(saving->file, extra_rule_name(ptask->tgt),
5705 "player%d.task%d.target",
5706 plrno, i);
5707 } else {
5708 secfile_insert_str(saving->file, "-",
5709 "player%d.task%d.target",
5710 plrno, i);
5711 }
5712 secfile_insert_int(saving->file, ptask->want, "player%d.task%d.want", plrno, i);
5713
5714 i++;
5717}
5718
5719/************************************************************************/
5722static void sg_load_player_units(struct loaddata *loading,
5723 struct player *plr)
5724{
5725 int nunits, i, plrno = player_number(plr);
5726 size_t orders_max_length;
5727
5728 /* Check status and return if not OK (sg_success FALSE). */
5729 sg_check_ret();
5730
5731 sg_failure_ret(secfile_lookup_int(loading->file, &nunits,
5732 "player%d.nunits", plrno),
5733 "%s", secfile_error());
5734 if (!plr->is_alive && nunits > 0) {
5735 log_sg("'player%d.nunits' = %d for dead player!", plrno, nunits);
5736 nunits = 0; /* Some old savegames may be buggy. */
5737 }
5738
5739 orders_max_length = 0;
5740
5741 for (i = 0; i < nunits; i++) {
5742 int ol_length = secfile_lookup_int_default(loading->file, 0,
5743 "player%d.u%d.orders_length",
5744 plrno, i);
5745
5746 orders_max_length = MAX(orders_max_length, ol_length);
5747 }
5748
5749 for (i = 0; i < nunits; i++) {
5750 struct unit *punit;
5751 struct city *pcity;
5752 const char *name;
5753 char buf[32];
5754 struct unit_type *type;
5755 struct tile *ptile;
5756
5757 fc_snprintf(buf, sizeof(buf), "player%d.u%d", plrno, i);
5758
5759 name = secfile_lookup_str(loading->file, "%s.type_by_name", buf);
5761 sg_failure_ret(type != NULL, "%s: unknown unit type \"%s\".", buf, name);
5762
5763 /* Create a dummy unit. */
5764 punit = unit_virtual_create(plr, NULL, type, 0);
5765 if (!sg_load_player_unit(loading, plr, punit, orders_max_length, buf)) {
5767 sg_failure_ret(FALSE, "Error loading unit %d of player %d.", i, plrno);
5768 }
5769
5772
5773 if ((pcity = game_city_by_number(punit->homecity))) {
5774 unit_list_prepend(pcity->units_supported, punit);
5775 } else if (punit->homecity > IDENTITY_NUMBER_ZERO) {
5776 log_sg("%s: bad home city %d.", buf, punit->homecity);
5778 }
5779
5780 ptile = unit_tile(punit);
5781
5782 /* allocate the unit's contribution to fog of war */
5785 /* NOTE: There used to be some map_set_known calls here. These were
5786 * unneeded since unfogging the tile when the unit sees it will
5787 * automatically reveal that tile. */
5788
5789 unit_list_append(plr->units, punit);
5790 unit_list_prepend(unit_tile(punit)->units, punit);
5791 }
5792}
5793
5794/************************************************************************/
5797static bool sg_load_player_unit(struct loaddata *loading,
5798 struct player *plr, struct unit *punit,
5799 int orders_max_length,
5800 const char *unitstr)
5801{
5802 enum unit_activity activity;
5803 int nat_x, nat_y;
5804 struct extra_type *pextra = NULL;
5805 struct tile *ptile;
5806 int extra_id;
5807 int ei;
5808 const char *facing_str;
5809 int natnbr;
5810 int unconverted;
5811 const char *str;
5812
5813 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->id, "%s.id",
5814 unitstr), FALSE, "%s", secfile_error());
5815 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_x, "%s.x", unitstr),
5816 FALSE, "%s", secfile_error());
5817 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_y, "%s.y", unitstr),
5818 FALSE, "%s", secfile_error());
5819
5820 ptile = native_pos_to_tile(&(wld.map), nat_x, nat_y);
5821 sg_warn_ret_val(NULL != ptile, FALSE, "%s invalid tile (%d, %d)",
5822 unitstr, nat_x, nat_y);
5823 unit_tile_set(punit, ptile);
5824
5825 facing_str
5826 = secfile_lookup_str_default(loading->file, "x",
5827 "%s.facing", unitstr);
5828 if (facing_str[0] != 'x') {
5829 /* We don't touch punit->facing if savegame does not contain that
5830 * information. Initial orientation set by unit_virtual_create()
5831 * is as good as any. */
5832 enum direction8 facing = char2dir(facing_str[0]);
5833
5834 if (direction8_is_valid(facing)) {
5835 punit->facing = facing;
5836 } else {
5837 log_error("Illegal unit orientation '%s'", facing_str);
5838 }
5839 }
5840
5841 /* If savegame has unit nationality, it doesn't hurt to
5842 * internally set it even if nationality rules are disabled. */
5843 natnbr = secfile_lookup_int_default(loading->file,
5844 player_number(plr),
5845 "%s.nationality", unitstr);
5846
5848 if (punit->nationality == NULL) {
5849 punit->nationality = plr;
5850 }
5851
5853 "%s.homecity", unitstr), FALSE,
5854 "%s", secfile_error());
5856 "%s.moves", unitstr), FALSE,
5857 "%s", secfile_error());
5859 "%s.fuel", unitstr), FALSE,
5860 "%s", secfile_error());
5862 "%s.activity", unitstr), FALSE,
5863 "%s", secfile_error());
5864 activity = unit_activity_by_name(loading->activities.order[ei],
5866
5869 "%s.born", unitstr);
5870
5871 extra_id = secfile_lookup_int_default(loading->file, -2,
5872 "%s.activity_tgt", unitstr);
5873
5874 if (extra_id != -2) {
5875 if (extra_id >= 0 && extra_id < loading->extra.size) {
5876 pextra = loading->extra.order[extra_id];
5877 set_unit_activity_targeted(punit, activity, pextra);
5878 } else if (activity == ACTIVITY_IRRIGATE) {
5880 EC_IRRIGATION,
5882 punit);
5883 if (tgt != NULL) {
5884 set_unit_activity_targeted(punit, ACTIVITY_IRRIGATE, tgt);
5885 } else {
5886 set_unit_activity(punit, ACTIVITY_CULTIVATE);
5887 }
5888 } else if (activity == ACTIVITY_MINE) {
5890 EC_MINE,
5892 punit);
5893 if (tgt != NULL) {
5894 set_unit_activity_targeted(punit, ACTIVITY_MINE, tgt);
5895 } else {
5896 set_unit_activity(punit, ACTIVITY_PLANT);
5897 }
5898 } else {
5899 set_unit_activity(punit, activity);
5900 }
5901 } else {
5902 set_unit_activity_targeted(punit, activity, NULL);
5903 } /* activity_tgt == NULL */
5904
5906 "%s.activity_count", unitstr), FALSE,
5907 "%s", secfile_error());
5908
5910 secfile_lookup_int_default(loading->file, ACTIVITY_IDLE,
5911 "%s.changed_from", unitstr);
5912
5913 sg_warn_ret_val(secfile_lookup_int(loading->file, &extra_id,
5914 "%s.changed_from_tgt", unitstr), FALSE,
5915 "%s", secfile_error());
5916
5917 if (extra_id >= 0 && extra_id < loading->extra.size) {
5918 punit->changed_from_target = loading->extra.order[extra_id];
5919 } else {
5920 punit->changed_from_target = NULL;
5921 }
5922
5924 secfile_lookup_int_default(loading->file, 0,
5925 "%s.changed_from_count", unitstr);
5926
5927 /* Special case: for a long time, we accidentally incremented
5928 * activity_count while a unit was sentried, so it could increase
5929 * without bound (bug #20641) and be saved in old savefiles.
5930 * We zero it to prevent potential trouble overflowing the range
5931 * in network packets, etc. */
5932 if (activity == ACTIVITY_SENTRY) {
5933 punit->activity_count = 0;
5934 }
5935 if (punit->changed_from == ACTIVITY_SENTRY) {
5937 }
5938
5939 punit->veteran
5940 = secfile_lookup_int_default(loading->file, 0, "%s.veteran", unitstr);
5941 {
5942 /* Protect against change in veteran system in ruleset */
5943 const int levels = utype_veteran_levels(unit_type_get(punit));
5944
5945 if (punit->veteran >= levels) {
5946 fc_assert(levels >= 1);
5947 punit->veteran = levels - 1;
5948 }
5949 }
5952 "%s.done_moving", unitstr);
5955 "%s.battlegroup", unitstr);
5956
5958 "%s.go", unitstr)) {
5959 int gnat_x, gnat_y;
5960
5961 sg_warn_ret_val(secfile_lookup_int(loading->file, &gnat_x,
5962 "%s.goto_x", unitstr), FALSE,
5963 "%s", secfile_error());
5964 sg_warn_ret_val(secfile_lookup_int(loading->file, &gnat_y,
5965 "%s.goto_y", unitstr), FALSE,
5966 "%s", secfile_error());
5967
5968 punit->goto_tile = native_pos_to_tile(&(wld.map), gnat_x, gnat_y);
5969 } else {
5970 punit->goto_tile = NULL;
5971
5972 /* These variables are not used but needed for saving the unit table.
5973 * Load them to prevent unused variables errors. */
5974 (void) secfile_entry_lookup(loading->file, "%s.goto_x", unitstr);
5975 (void) secfile_entry_lookup(loading->file, "%s.goto_y", unitstr);
5976 }
5977
5978 /* Load AI data of the unit. */
5979 CALL_FUNC_EACH_AI(unit_load, loading->file, punit, unitstr);
5980
5981 unconverted
5982 = secfile_lookup_int_default(loading->file, 0,
5983 "%s.server_side_agent",
5984 unitstr);
5985 if (unconverted >= 0 && unconverted < loading->ssa.size) {
5986 /* Look up what server side agent the unconverted number represents. */
5987 punit->ssa_controller = loading->ssa.order[unconverted];
5988 } else {
5989 log_sg("Invalid server side agent %d for unit %d",
5990 unconverted, punit->id);
5991
5992 punit->ssa_controller = SSA_NONE;
5993 }
5994
5996 "%s.hp", unitstr), FALSE,
5997 "%s", secfile_error());
5998
6000 = secfile_lookup_int_default(loading->file, 0, "%s.ord_map", unitstr);
6002 = secfile_lookup_int_default(loading->file, 0, "%s.ord_city", unitstr);
6003 punit->moved
6004 = secfile_lookup_bool_default(loading->file, FALSE, "%s.moved", unitstr);
6007 "%s.paradropped", unitstr);
6008 str = secfile_lookup_str_default(loading->file, "", "%s.carrying", unitstr);
6009 if (str[0] != '\0') {
6011 }
6012
6013 /* The transport status (punit->transported_by) is loaded in
6014 * sg_player_units_transport(). */
6015
6016 /* Initialize upkeep values: these are hopefully initialized
6017 * elsewhere before use (specifically, in city_support(); but
6018 * fixme: check whether always correctly initialized?).
6019 * Below is mainly for units which don't have homecity --
6020 * otherwise these don't get initialized (and AI calculations
6021 * etc may use junk values). */
6025
6026 sg_warn_ret_val(secfile_lookup_int(loading->file, &unconverted,
6027 "%s.action_decision", unitstr),
6028 FALSE, "%s", secfile_error());
6029
6030 if (unconverted >= 0 && unconverted < loading->act_dec.size) {
6031 /* Look up what action decision want the unconverted number
6032 * represents. */
6033 punit->action_decision_want = loading->act_dec.order[unconverted];
6034 } else {
6035 log_sg("Invalid action decision want for unit %d", punit->id);
6036
6037 punit->action_decision_want = ACT_DEC_NOTHING;
6038 }
6039
6040 if (punit->action_decision_want != ACT_DEC_NOTHING) {
6041 /* Load the tile to act against. */
6042 int adwt_x, adwt_y;
6043
6044 if (secfile_lookup_int(loading->file, &adwt_x,
6045 "%s.action_decision_tile_x", unitstr)
6046 && secfile_lookup_int(loading->file, &adwt_y,
6047 "%s.action_decision_tile_y", unitstr)) {
6049 adwt_x, adwt_y);
6050 } else {
6051 punit->action_decision_want = ACT_DEC_NOTHING;
6053 log_sg("Bad action_decision_tile for unit %d", punit->id);
6054 }
6055 } else {
6056 (void) secfile_entry_lookup(loading->file, "%s.action_decision_tile_x", unitstr);
6057 (void) secfile_entry_lookup(loading->file, "%s.action_decision_tile_y", unitstr);
6059 }
6060
6061 punit->stay = secfile_lookup_bool_default(loading->file, FALSE, "%s.stay", unitstr);
6062
6063 /* Load the unit orders */
6064 {
6065 int len = secfile_lookup_int_default(loading->file, 0,
6066 "%s.orders_length", unitstr);
6067
6068 if (len > 0) {
6069 const char *orders_unitstr, *dir_unitstr, *act_unitstr;
6070 int j;
6071
6072 punit->orders.list = fc_malloc(len * sizeof(*(punit->orders.list)));
6075 = secfile_lookup_int_default(loading->file, 0,
6076 "%s.orders_index", unitstr);
6079 "%s.orders_repeat", unitstr);
6082 "%s.orders_vigilant", unitstr);
6083
6084 orders_unitstr
6085 = secfile_lookup_str_default(loading->file, "",
6086 "%s.orders_list", unitstr);
6087 dir_unitstr
6088 = secfile_lookup_str_default(loading->file, "",
6089 "%s.dir_list", unitstr);
6090 act_unitstr
6091 = secfile_lookup_str_default(loading->file, "",
6092 "%s.activity_list", unitstr);
6093
6095
6096 for (j = 0; j < len; j++) {
6097 struct unit_order *order = &punit->orders.list[j];
6098 bool action_wants_extra = FALSE;
6099 int order_sub_tgt;
6100
6101 if (orders_unitstr[j] == '\0' || dir_unitstr[j] == '\0'
6102 || act_unitstr[j] == '\0') {
6103 log_sg("Invalid unit orders.");
6105 break;
6106 }
6107 order->order = char2order(orders_unitstr[j]);
6108 order->dir = char2dir(dir_unitstr[j]);
6109 order->activity = char2activity(act_unitstr[j]);
6110
6111 unconverted = secfile_lookup_int_default(loading->file, ACTION_NONE,
6112 "%s.action_vec,%d",
6113 unitstr, j);
6114
6115 if (unconverted >= 0 && unconverted < loading->action.size) {
6116 /* Look up what action id the unconverted number represents. */
6117 order->action = loading->action.order[unconverted];
6118 } else {
6119 if (order->order == ORDER_PERFORM_ACTION) {
6120 log_sg("Invalid action id in order for unit %d", punit->id);
6121 }
6122
6123 order->action = ACTION_NONE;
6124 }
6125
6126 if (order->order == ORDER_LAST
6127 || (order->order == ORDER_MOVE && !direction8_is_valid(order->dir))
6128 || (order->order == ORDER_ACTION_MOVE
6129 && !direction8_is_valid(order->dir))
6130 || (order->order == ORDER_PERFORM_ACTION
6131 && !action_id_exists(order->action))
6132 || (order->order == ORDER_ACTIVITY
6133 && order->activity == ACTIVITY_LAST)) {
6134 /* An invalid order. Just drop the orders for this unit. */
6135 free(punit->orders.list);
6136 punit->orders.list = NULL;
6138 break;
6139 }
6140
6141 order->target = secfile_lookup_int_default(loading->file, NO_TARGET,
6142 "%s.tgt_vec,%d",
6143 unitstr, j);
6144 order_sub_tgt = secfile_lookup_int_default(loading->file, -1,
6145 "%s.sub_tgt_vec,%d",
6146 unitstr, j);
6147
6148 if (order->order == ORDER_PERFORM_ACTION) {
6149 /* Validate sub target */
6150 switch (action_id_get_sub_target_kind(order->action)) {
6151 case ASTK_BUILDING:
6152 /* Sub target is a building. */
6153 if (!improvement_by_number(order_sub_tgt)) {
6154 /* Sub target is invalid. */
6155 log_sg("Cannot find building %d for %s to %s",
6156 order_sub_tgt, unit_rule_name(punit),
6158 order->sub_target = B_LAST;
6159 } else {
6160 order->sub_target = order_sub_tgt;
6161 }
6162 break;
6163 case ASTK_TECH:
6164 /* Sub target is a technology. */
6165 if (order_sub_tgt == A_NONE
6166 || (!valid_advance_by_number(order_sub_tgt)
6167 && order_sub_tgt != A_FUTURE)) {
6168 /* Target tech is invalid. */
6169 log_sg("Cannot find tech %d for %s to steal",
6170 order_sub_tgt, unit_rule_name(punit));
6171 order->sub_target = A_NONE;
6172 } else {
6173 order->sub_target = order_sub_tgt;
6174 }
6175 break;
6176 case ASTK_EXTRA:
6177 case ASTK_EXTRA_NOT_THERE:
6178 /* These take an extra. */
6179 action_wants_extra = TRUE;
6180 break;
6181 case ASTK_NONE:
6182 /* None of these can take a sub target. */
6183 fc_assert_msg(order_sub_tgt == -1,
6184 "Specified sub target for action %d unsupported.",
6185 order->action);
6186 order->sub_target = NO_TARGET;
6187 break;
6188 case ASTK_COUNT:
6189 fc_assert_msg(order_sub_tgt == -1,
6190 "Bad action action %d.",
6191 order->action);
6192 order->sub_target = NO_TARGET;
6193 break;
6194 }
6195 }
6196
6197 if (order->order == ORDER_ACTIVITY || action_wants_extra) {
6198 enum unit_activity act;
6199
6200 if (order_sub_tgt < 0 || order_sub_tgt >= loading->extra.size) {
6201 if (order_sub_tgt != EXTRA_NONE) {
6202 log_sg("Cannot find extra %d for %s to build",
6203 order_sub_tgt, unit_rule_name(punit));
6204 }
6205
6206 order->sub_target = EXTRA_NONE;
6207 } else {
6208 order->sub_target = order_sub_tgt;
6209 }
6210
6211 /* An action or an activity may require an extra target. */
6212 if (action_wants_extra) {
6213 act = action_id_get_activity(order->action);
6214 } else {
6215 act = order->activity;
6216 }
6217
6218 if (unit_activity_is_valid(act)
6220 && order->sub_target == EXTRA_NONE) {
6221 /* Missing required action extra target. */
6222 free(punit->orders.list);
6223 punit->orders.list = NULL;
6225 break;
6226 }
6227 } else if (order->order != ORDER_PERFORM_ACTION) {
6228 if (order_sub_tgt != -1) {
6229 log_sg("Unexpected sub_target %d (expected %d) for order type %d",
6230 order_sub_tgt, -1, order->order);
6231 }
6232 order->sub_target = NO_TARGET;
6233 }
6234 }
6235
6236 for (; j < orders_max_length; j++) {
6237 (void) secfile_entry_lookup(loading->file,
6238 "%s.action_vec,%d", unitstr, j);
6239 (void) secfile_entry_lookup(loading->file,
6240 "%s.tgt_vec,%d", unitstr, j);
6241 (void) secfile_entry_lookup(loading->file,
6242 "%s.sub_tgt_vec,%d", unitstr, j);
6243 }
6244 } else {
6245 int j;
6246
6248 punit->orders.list = NULL;
6249
6250 (void) secfile_entry_lookup(loading->file, "%s.orders_index", unitstr);
6251 (void) secfile_entry_lookup(loading->file, "%s.orders_repeat", unitstr);
6252 (void) secfile_entry_lookup(loading->file, "%s.orders_vigilant", unitstr);
6253 (void) secfile_entry_lookup(loading->file, "%s.orders_list", unitstr);
6254 (void) secfile_entry_lookup(loading->file, "%s.dir_list", unitstr);
6255 (void) secfile_entry_lookup(loading->file, "%s.activity_list", unitstr);
6256 (void) secfile_entry_lookup(loading->file, "%s.action_vec", unitstr);
6257 (void) secfile_entry_lookup(loading->file, "%s.tgt_vec", unitstr);
6258 (void) secfile_entry_lookup(loading->file, "%s.sub_tgt_vec", unitstr);
6259
6260 for (j = 1; j < orders_max_length; j++) {
6261 (void) secfile_entry_lookup(loading->file,
6262 "%s.action_vec,%d", unitstr, j);
6263 (void) secfile_entry_lookup(loading->file,
6264 "%s.tgt_vec,%d", unitstr, j);
6265 (void) secfile_entry_lookup(loading->file,
6266 "%s.sub_tgt_vec,%d", unitstr, j);
6267 }
6268 }
6269 }
6270
6271 return TRUE;
6272}
6273
6274/************************************************************************/
6278static void sg_load_player_units_transport(struct loaddata *loading,
6279 struct player *plr)
6280{
6281 int nunits, i, plrno = player_number(plr);
6282
6283 /* Check status and return if not OK (sg_success FALSE). */
6284 sg_check_ret();
6285
6286 /* Recheck the number of units for the player. This is a copied from
6287 * sg_load_player_units(). */
6288 sg_failure_ret(secfile_lookup_int(loading->file, &nunits,
6289 "player%d.nunits", plrno),
6290 "%s", secfile_error());
6291 if (!plr->is_alive && nunits > 0) {
6292 log_sg("'player%d.nunits' = %d for dead player!", plrno, nunits);
6293 nunits = 0; /* Some old savegames may be buggy. */
6294 }
6295
6296 for (i = 0; i < nunits; i++) {
6297 int id_unit, id_trans;
6298 struct unit *punit, *ptrans;
6299
6300 id_unit = secfile_lookup_int_default(loading->file, -1,
6301 "player%d.u%d.id",
6302 plrno, i);
6303 punit = player_unit_by_number(plr, id_unit);
6304 fc_assert_action(punit != NULL, continue);
6305
6306 id_trans = secfile_lookup_int_default(loading->file, -1,
6307 "player%d.u%d.transported_by",
6308 plrno, i);
6309 if (id_trans == -1) {
6310 /* Not transported. */
6311 continue;
6312 }
6313
6314 ptrans = game_unit_by_number(id_trans);
6315 fc_assert_action(id_trans == -1 || ptrans != NULL, continue);
6316
6317 if (ptrans) {
6318#ifndef FREECIV_NDEBUG
6319 bool load_success =
6320#endif
6321 unit_transport_load(punit, ptrans, TRUE);
6322
6323 fc_assert_action(load_success, continue);
6324 }
6325 }
6326}
6327
6328/************************************************************************/
6331static void sg_save_player_units(struct savedata *saving,
6332 struct player *plr)
6333{
6334 int i = 0;
6335 int longest_order = 0;
6336 int plrno = player_number(plr);
6337
6338 /* Check status and return if not OK (sg_success FALSE). */
6339 sg_check_ret();
6340
6341 secfile_insert_int(saving->file, unit_list_size(plr->units),
6342 "player%d.nunits", plrno);
6343
6344 /* Find the longest unit order so different order length won't break
6345 * storing units in the tabular format. */
6347 if (punit->has_orders) {
6348 if (longest_order < punit->orders.length) {
6349 longest_order = punit->orders.length;
6350 }
6351 }
6353
6355 char buf[32];
6356 char dirbuf[2] = " ";
6357 int nat_x, nat_y;
6358 int last_order, j;
6359
6360 fc_snprintf(buf, sizeof(buf), "player%d.u%d", plrno, i);
6361 dirbuf[0] = dir2char(punit->facing);
6362 secfile_insert_int(saving->file, punit->id, "%s.id", buf);
6363
6365 secfile_insert_int(saving->file, nat_x, "%s.x", buf);
6366 secfile_insert_int(saving->file, nat_y, "%s.y", buf);
6367
6368 secfile_insert_str(saving->file, dirbuf, "%s.facing", buf);
6371 "%s.nationality", buf);
6372 }
6373 secfile_insert_int(saving->file, punit->veteran, "%s.veteran", buf);
6374 secfile_insert_int(saving->file, punit->hp, "%s.hp", buf);
6375 secfile_insert_int(saving->file, punit->homecity, "%s.homecity", buf);
6377 "%s.type_by_name", buf);
6378
6379 secfile_insert_int(saving->file, punit->activity, "%s.activity", buf);
6381 "%s.activity_count", buf);
6382 if (punit->activity_target == NULL) {
6383 secfile_insert_int(saving->file, -1, "%s.activity_tgt", buf);
6384 } else {
6386 "%s.activity_tgt", buf);
6387 }
6388
6390 "%s.changed_from", buf);
6392 "%s.changed_from_count", buf);
6393 if (punit->changed_from_target == NULL) {
6394 secfile_insert_int(saving->file, -1, "%s.changed_from_tgt", buf);
6395 } else {
6397 "%s.changed_from_tgt", buf);
6398 }
6399
6401 "%s.done_moving", buf);
6402 secfile_insert_int(saving->file, punit->moves_left, "%s.moves", buf);
6403 secfile_insert_int(saving->file, punit->fuel, "%s.fuel", buf);
6405 "%s.born", buf);
6407 "%s.battlegroup", buf);
6408
6409 if (punit->goto_tile) {
6411 secfile_insert_bool(saving->file, TRUE, "%s.go", buf);
6412 secfile_insert_int(saving->file, nat_x, "%s.goto_x", buf);
6413 secfile_insert_int(saving->file, nat_y, "%s.goto_y", buf);
6414 } else {
6415 secfile_insert_bool(saving->file, FALSE, "%s.go", buf);
6416 /* Set this values to allow saving it as table. */
6417 secfile_insert_int(saving->file, 0, "%s.goto_x", buf);
6418 secfile_insert_int(saving->file, 0, "%s.goto_y", buf);
6419 }
6420
6422 "%s.server_side_agent", buf);
6423
6424 /* Save AI data of the unit. */
6425 CALL_FUNC_EACH_AI(unit_save, saving->file, punit, buf);
6426
6428 "%s.ord_map", buf);
6430 "%s.ord_city", buf);
6431 secfile_insert_bool(saving->file, punit->moved, "%s.moved", buf);
6433 "%s.paradropped", buf);
6435 ? unit_transport_get(punit)->id : -1,
6436 "%s.transported_by", buf);
6437 if (punit->carrying != NULL) {
6439 "%s.carrying", buf);
6440 } else {
6441 secfile_insert_str(saving->file, "", "%s.carrying", buf);
6442 }
6443
6445 "%s.action_decision", buf);
6446
6447 /* Stored as tile rather than direction to make sure the target tile is
6448 * sane. */
6452 secfile_insert_int(saving->file, nat_x,
6453 "%s.action_decision_tile_x", buf);
6454 secfile_insert_int(saving->file, nat_y,
6455 "%s.action_decision_tile_y", buf);
6456 } else {
6457 /* Dummy values to get tabular format. */
6458 secfile_insert_int(saving->file, -1,
6459 "%s.action_decision_tile_x", buf);
6460 secfile_insert_int(saving->file, -1,
6461 "%s.action_decision_tile_y", buf);
6462 }
6463
6465 "%s.stay", buf);
6466
6467 if (punit->has_orders) {
6468 int len = punit->orders.length;
6469 char orders_buf[len + 1], dir_buf[len + 1];
6470 char act_buf[len + 1];
6471 int action_buf[len];
6472 int tgt_vec[len];
6473 int sub_tgt_vec[len];
6474
6475 last_order = len;
6476
6477 secfile_insert_int(saving->file, len, "%s.orders_length", buf);
6479 "%s.orders_index", buf);
6481 "%s.orders_repeat", buf);
6483 "%s.orders_vigilant", buf);
6484
6485 for (j = 0; j < len; j++) {
6486 orders_buf[j] = order2char(punit->orders.list[j].order);
6487 dir_buf[j] = '?';
6488 act_buf[j] = '?';
6489 tgt_vec[j] = NO_TARGET;
6490 sub_tgt_vec[j] = -1;
6491 action_buf[j] = -1;
6492 switch (punit->orders.list[j].order) {
6493 case ORDER_MOVE:
6494 case ORDER_ACTION_MOVE:
6495 dir_buf[j] = dir2char(punit->orders.list[j].dir);
6496 break;
6497 case ORDER_ACTIVITY:
6498 sub_tgt_vec[j] = punit->orders.list[j].sub_target;
6499 act_buf[j] = activity2char(punit->orders.list[j].activity);
6500 break;
6502 action_buf[j] = punit->orders.list[j].action;
6503 tgt_vec[j] = punit->orders.list[j].target;
6504 sub_tgt_vec[j] = punit->orders.list[j].sub_target;
6505 break;
6506 case ORDER_FULL_MP:
6507 case ORDER_LAST:
6508 break;
6509 }
6510 }
6511 orders_buf[len] = dir_buf[len] = act_buf[len] = '\0';
6512
6513 secfile_insert_str(saving->file, orders_buf, "%s.orders_list", buf);
6514 secfile_insert_str(saving->file, dir_buf, "%s.dir_list", buf);
6515 secfile_insert_str(saving->file, act_buf, "%s.activity_list", buf);
6516
6517 secfile_insert_int_vec(saving->file, action_buf, len,
6518 "%s.action_vec", buf);
6519 /* Fill in dummy values for order targets so the registry will save
6520 * the unit table in a tabular format. */
6521 for (j = last_order; j < longest_order; j++) {
6522 secfile_insert_int(saving->file, -1, "%s.action_vec,%d", buf, j);
6523 }
6524
6525 secfile_insert_int_vec(saving->file, tgt_vec, len,
6526 "%s.tgt_vec", buf);
6527 /* Fill in dummy values for order targets so the registry will save
6528 * the unit table in a tabular format. */
6529 for (j = last_order; j < longest_order; j++) {
6530 secfile_insert_int(saving->file, NO_TARGET, "%s.tgt_vec,%d", buf, j);
6531 }
6532
6533 secfile_insert_int_vec(saving->file, sub_tgt_vec, len,
6534 "%s.sub_tgt_vec", buf);
6535 /* Fill in dummy values for order targets so the registry will save
6536 * the unit table in a tabular format. */
6537 for (j = last_order; j < longest_order; j++) {
6538 secfile_insert_int(saving->file, -1, "%s.sub_tgt_vec,%d", buf, j);
6539 }
6540 } else {
6541
6542 /* Put all the same fields into the savegame - otherwise the
6543 * registry code can't correctly use a tabular format and the
6544 * savegame will be bigger. */
6545 secfile_insert_int(saving->file, 0, "%s.orders_length", buf);
6546 secfile_insert_int(saving->file, 0, "%s.orders_index", buf);
6547 secfile_insert_bool(saving->file, FALSE, "%s.orders_repeat", buf);
6548 secfile_insert_bool(saving->file, FALSE, "%s.orders_vigilant", buf);
6549 secfile_insert_str(saving->file, "-", "%s.orders_list", buf);
6550 secfile_insert_str(saving->file, "-", "%s.dir_list", buf);
6551 secfile_insert_str(saving->file, "-", "%s.activity_list", buf);
6552
6553 /* Fill in dummy values for order targets so the registry will save
6554 * the unit table in a tabular format. */
6555
6556 /* The start of a vector has no number. */
6557 secfile_insert_int(saving->file, -1, "%s.action_vec", buf);
6558 for (j = 1; j < longest_order; j++) {
6559 secfile_insert_int(saving->file, -1, "%s.action_vec,%d", buf, j);
6560 }
6561
6562 /* The start of a vector has no number. */
6563 secfile_insert_int(saving->file, NO_TARGET, "%s.tgt_vec", buf);
6564 for (j = 1; j < longest_order; j++) {
6565 secfile_insert_int(saving->file, NO_TARGET, "%s.tgt_vec,%d", buf, j);
6566 }
6567
6568 /* The start of a vector has no number. */
6569 secfile_insert_int(saving->file, -1, "%s.sub_tgt_vec", buf);
6570 for (j = 1; j < longest_order; j++) {
6571 secfile_insert_int(saving->file, -1, "%s.sub_tgt_vec,%d", buf, j);
6572 }
6573 }
6574
6575 i++;
6577}
6578
6579/************************************************************************/
6582static void sg_load_player_attributes(struct loaddata *loading,
6583 struct player *plr)
6584{
6585 int plrno = player_number(plr);
6586
6587 /* Check status and return if not OK (sg_success FALSE). */
6588 sg_check_ret();
6589
6590 /* Toss any existing attribute_block (should not exist) */
6591 if (plr->attribute_block.data) {
6592 free(plr->attribute_block.data);
6593 plr->attribute_block.data = NULL;
6594 }
6595
6596 /* This is a big heap of opaque data for the client, check everything! */
6598 loading->file, 0, "player%d.attribute_v2_block_length", plrno);
6599
6600 if (0 > plr->attribute_block.length) {
6601 log_sg("player%d.attribute_v2_block_length=%d too small", plrno,
6602 plr->attribute_block.length);
6603 plr->attribute_block.length = 0;
6604 } else if (MAX_ATTRIBUTE_BLOCK < plr->attribute_block.length) {
6605 log_sg("player%d.attribute_v2_block_length=%d too big (max %d)",
6607 plr->attribute_block.length = 0;
6608 } else if (0 < plr->attribute_block.length) {
6609 int part_nr, parts;
6610 int quoted_length;
6611 char *quoted;
6612#ifndef FREECIV_NDEBUG
6613 size_t actual_length;
6614#endif
6615
6617 secfile_lookup_int(loading->file, &quoted_length,
6618 "player%d.attribute_v2_block_length_quoted",
6619 plrno), "%s", secfile_error());
6621 secfile_lookup_int(loading->file, &parts,
6622 "player%d.attribute_v2_block_parts", plrno),
6623 "%s", secfile_error());
6624
6625 quoted = fc_malloc(quoted_length + 1);
6626 quoted[0] = '\0';
6628 for (part_nr = 0; part_nr < parts; part_nr++) {
6629 const char *current =
6630 secfile_lookup_str(loading->file,
6631 "player%d.attribute_v2_block_data.part%d",
6632 plrno, part_nr);
6633 if (!current) {
6634 log_sg("attribute_v2_block_parts=%d actual=%d", parts, part_nr);
6635 break;
6636 }
6637 log_debug("attribute_v2_block_length_quoted=%d"
6638 " have=" SIZE_T_PRINTF " part=" SIZE_T_PRINTF,
6639 quoted_length, strlen(quoted), strlen(current));
6640 fc_assert(strlen(quoted) + strlen(current) <= quoted_length);
6641 strcat(quoted, current);
6642 }
6643 fc_assert_msg(quoted_length == strlen(quoted),
6644 "attribute_v2_block_length_quoted=%d"
6645 " actual=" SIZE_T_PRINTF,
6646 quoted_length, strlen(quoted));
6647
6648#ifndef FREECIV_NDEBUG
6649 actual_length =
6650#endif
6651 unquote_block(quoted,
6652 plr->attribute_block.data,
6653 plr->attribute_block.length);
6654 fc_assert(actual_length == plr->attribute_block.length);
6655 free(quoted);
6656 }
6657}
6658
6659/************************************************************************/
6662static void sg_save_player_attributes(struct savedata *saving,
6663 struct player *plr)
6664{
6665 int plrno = player_number(plr);
6666
6667 /* Check status and return if not OK (sg_success FALSE). */
6668 sg_check_ret();
6669
6670 /* This is a big heap of opaque data from the client. Although the binary
6671 * format is not user editable, keep the lines short enough for debugging,
6672 * and hope that data compression will keep the file a reasonable size.
6673 * Note that the "quoted" format is a multiple of 3.
6674 */
6675#define PART_SIZE (3*256)
6676#define PART_ADJUST (3)
6677 if (plr->attribute_block.data) {
6678 char part[PART_SIZE + PART_ADJUST];
6679 int parts;
6680 int current_part_nr;
6681 char *quoted = quote_block(plr->attribute_block.data,
6682 plr->attribute_block.length);
6683 char *quoted_at = strchr(quoted, ':');
6684 size_t bytes_left = strlen(quoted);
6685 size_t bytes_at_colon = 1 + (quoted_at - quoted);
6686 size_t bytes_adjust = bytes_at_colon % PART_ADJUST;
6687
6689 "player%d.attribute_v2_block_length", plrno);
6690 secfile_insert_int(saving->file, bytes_left,
6691 "player%d.attribute_v2_block_length_quoted", plrno);
6692
6693 /* Try to wring some compression efficiencies out of the "quoted" format.
6694 * The first line has a variable length decimal, mis-aligning triples.
6695 */
6696 if ((bytes_left - bytes_adjust) > PART_SIZE) {
6697 /* first line can be longer */
6698 parts = 1 + (bytes_left - bytes_adjust - 1) / PART_SIZE;
6699 } else {
6700 parts = 1;
6701 }
6702
6703 secfile_insert_int(saving->file, parts,
6704 "player%d.attribute_v2_block_parts", plrno);
6705
6706 if (parts > 1) {
6707 size_t size_of_current_part = PART_SIZE + bytes_adjust;
6708
6709 /* first line can be longer */
6710 memcpy(part, quoted, size_of_current_part);
6711 part[size_of_current_part] = '\0';
6712 secfile_insert_str(saving->file, part,
6713 "player%d.attribute_v2_block_data.part%d",
6714 plrno, 0);
6715 bytes_left -= size_of_current_part;
6716 quoted_at = &quoted[size_of_current_part];
6717 current_part_nr = 1;
6718 } else {
6719 quoted_at = quoted;
6720 current_part_nr = 0;
6721 }
6722
6723 for (; current_part_nr < parts; current_part_nr++) {
6724 size_t size_of_current_part = MIN(bytes_left, PART_SIZE);
6725
6726 memcpy(part, quoted_at, size_of_current_part);
6727 part[size_of_current_part] = '\0';
6728 secfile_insert_str(saving->file, part,
6729 "player%d.attribute_v2_block_data.part%d",
6730 plrno,
6731 current_part_nr);
6732 bytes_left -= size_of_current_part;
6733 quoted_at = &quoted_at[size_of_current_part];
6734 }
6735 fc_assert(bytes_left == 0);
6736 free(quoted);
6737 }
6738#undef PART_ADJUST
6739#undef PART_SIZE
6740}
6741
6742/************************************************************************/
6745static void sg_load_player_vision(struct loaddata *loading,
6746 struct player *plr)
6747{
6748 int plrno = player_number(plr);
6749 int total_ncities =
6750 secfile_lookup_int_default(loading->file, -1,
6751 "player%d.dc_total", plrno);
6752 int i;
6753 bool someone_alive = FALSE;
6754
6755 /* Check status and return if not OK (sg_success FALSE). */
6756 sg_check_ret();
6757
6758 if (game.server.revealmap & REVEAL_MAP_DEAD) {
6759 player_list_iterate(team_members(plr->team), pteam_member) {
6760 if (pteam_member->is_alive) {
6761 someone_alive = TRUE;
6762 break;
6763 }
6765
6766 if (!someone_alive) {
6767 /* Reveal all for completely dead teams. */
6769 }
6770 }
6771
6772 if (-1 == total_ncities
6773 || !game.info.fogofwar
6775 "game.save_private_map")) {
6776 /* We have:
6777 * - a dead player;
6778 * - fogged cities are not saved for any reason;
6779 * - a savegame with fog of war turned off;
6780 * - or game.save_private_map is not set to FALSE in the scenario /
6781 * savegame. The players private knowledge is set to be what they could
6782 * see without fog of war. */
6783 whole_map_iterate(&(wld.map), ptile) {
6784 if (map_is_known(ptile, plr)) {
6785 struct city *pcity = tile_city(ptile);
6786
6787 update_player_tile_last_seen(plr, ptile);
6788 update_player_tile_knowledge(plr, ptile);
6789
6790 if (NULL != pcity) {
6791 update_dumb_city(plr, pcity);
6792 }
6793 }
6795
6796 /* Nothing more to do; */
6797 return;
6798 }
6799
6800 /* Load player map (terrain). */
6801 LOAD_MAP_CHAR(ch, ptile,
6802 map_get_player_tile(ptile, plr)->terrain
6803 = char2terrain(ch), loading->file,
6804 "player%d.map_t%04d", plrno);
6805
6806 /* Load player map (extras). */
6807 halfbyte_iterate_extras(j, loading->extra.size) {
6808 LOAD_MAP_CHAR(ch, ptile,
6810 ch, loading->extra.order + 4 * j),
6811 loading->file, "player%d.map_e%02d_%04d", plrno, j);
6813
6814 whole_map_iterate(&(wld.map), ptile) {
6815 struct player_tile *plrtile = map_get_player_tile(ptile, plr);
6816
6817 extra_type_by_cause_iterate(EC_RESOURCE, pres) {
6818 if (BV_ISSET(plrtile->extras, extra_number(pres))) {
6819 plrtile->resource = pres;
6820 if (!terrain_has_resource(plrtile->terrain, pres)) {
6821 BV_CLR(plrtile->extras, extra_number(pres));
6822 }
6823 }
6826
6828 /* Load player map (border). */
6829 int x, y;
6830
6831 for (y = 0; y < wld.map.ysize; y++) {
6832 const char *buffer
6833 = secfile_lookup_str(loading->file, "player%d.map_owner%04d",
6834 plrno, y);
6835 const char *buffer2
6836 = secfile_lookup_str(loading->file, "player%d.extras_owner%04d",
6837 plrno, y);
6838 const char *ptr = buffer;
6839 const char *ptr2 = buffer2;
6840
6841 sg_failure_ret(NULL != buffer,
6842 "Savegame corrupt - map line %d not found.", y);
6843 for (x = 0; x < wld.map.xsize; x++) {
6844 char token[TOKEN_SIZE];
6845 char token2[TOKEN_SIZE];
6846 int number;
6847 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
6848
6849 scanin(&ptr, ",", token, sizeof(token));
6850 sg_failure_ret('\0' != token[0],
6851 "Savegame corrupt - map size not correct.");
6852 if (strcmp(token, "-") == 0) {
6853 map_get_player_tile(ptile, plr)->owner = NULL;
6854 } else {
6855 sg_failure_ret(str_to_int(token, &number),
6856 "Savegame corrupt - got tile owner=%s in (%d, %d).",
6857 token, x, y);
6858 map_get_player_tile(ptile, plr)->owner = player_by_number(number);
6859 }
6860
6861 scanin(&ptr2, ",", token2, sizeof(token2));
6862 sg_failure_ret('\0' != token2[0],
6863 "Savegame corrupt - map size not correct.");
6864 if (strcmp(token2, "-") == 0) {
6865 map_get_player_tile(ptile, plr)->extras_owner = NULL;
6866 } else {
6867 sg_failure_ret(str_to_int(token2, &number),
6868 "Savegame corrupt - got extras owner=%s in (%d, %d).",
6869 token, x, y);
6870 map_get_player_tile(ptile, plr)->extras_owner = player_by_number(number);
6871 }
6872 }
6873 }
6874 }
6875
6876 /* Load player map (update time). */
6877 for (i = 0; i < 4; i++) {
6878 /* put 4-bit segments of 16-bit "updated" field */
6879 if (i == 0) {
6880 LOAD_MAP_CHAR(ch, ptile,
6881 map_get_player_tile(ptile, plr)->last_updated
6882 = ascii_hex2bin(ch, i),
6883 loading->file, "player%d.map_u%02d_%04d", plrno, i);
6884 } else {
6885 LOAD_MAP_CHAR(ch, ptile,
6886 map_get_player_tile(ptile, plr)->last_updated
6887 |= ascii_hex2bin(ch, i),
6888 loading->file, "player%d.map_u%02d_%04d", plrno, i);
6889 }
6890 }
6891
6892 /* Load player map known cities. */
6893 for (i = 0; i < total_ncities; i++) {
6894 struct vision_site *pdcity;
6895 char buf[32];
6896 fc_snprintf(buf, sizeof(buf), "player%d.dc%d", plrno, i);
6897
6898 pdcity = vision_site_new(0, NULL, NULL);
6899 if (sg_load_player_vision_city(loading, plr, pdcity, buf)) {
6901 pdcity);
6903 } else {
6904 /* Error loading the data. */
6905 log_sg("Skipping seen city %d for player %d.", i, plrno);
6906 if (pdcity != NULL) {
6907 vision_site_destroy(pdcity);
6908 }
6909 }
6910 }
6911
6912 /* Repair inconsistent player maps. */
6913 whole_map_iterate(&(wld.map), ptile) {
6914 if (map_is_known_and_seen(ptile, plr, V_MAIN)) {
6915 struct city *pcity = tile_city(ptile);
6916
6917 update_player_tile_knowledge(plr, ptile);
6918 reality_check_city(plr, ptile);
6919
6920 if (NULL != pcity) {
6921 update_dumb_city(plr, pcity);
6922 }
6923 } else if (!game.server.foggedborders && map_is_known(ptile, plr)) {
6924 /* Non fogged borders aren't loaded. See hrm Bug #879084 */
6925 struct player_tile *plrtile = map_get_player_tile(ptile, plr);
6926
6927 plrtile->owner = tile_owner(ptile);
6928 }
6930}
6931
6932/************************************************************************/
6935static bool sg_load_player_vision_city(struct loaddata *loading,
6936 struct player *plr,
6937 struct vision_site *pdcity,
6938 const char *citystr)
6939{
6940 const char *str;
6941 int i, id, size;
6942 citizens city_size;
6943 int nat_x, nat_y;
6944 const char *stylename;
6945 enum capital_type cap;
6946 const char *vname;
6947
6948 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_x, "%s.x",
6949 citystr),
6950 FALSE, "%s", secfile_error());
6951 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_y, "%s.y",
6952 citystr),
6953 FALSE, "%s", secfile_error());
6954 pdcity->location = native_pos_to_tile(&(wld.map), nat_x, nat_y);
6955 sg_warn_ret_val(NULL != pdcity->location, FALSE,
6956 "%s invalid tile (%d,%d)", citystr, nat_x, nat_y);
6957
6958 sg_warn_ret_val(secfile_lookup_int(loading->file, &id, "%s.owner",
6959 citystr),
6960 FALSE, "%s", secfile_error());
6961 pdcity->owner = player_by_number(id);
6962 sg_warn_ret_val(NULL != pdcity->owner, FALSE,
6963 "%s has invalid owner (%d); skipping.", citystr, id);
6964
6966 "%s.id", citystr),
6967 FALSE, "%s", secfile_error());
6968 sg_warn_ret_val(IDENTITY_NUMBER_ZERO < pdcity->identity, FALSE,
6969 "%s has invalid id (%d); skipping.", citystr, id);
6970
6972 "%s.size", citystr),
6973 FALSE, "%s", secfile_error());
6974 city_size = (citizens)size; /* set the correct type */
6975 sg_warn_ret_val(size == (int)city_size, FALSE,
6976 "Invalid city size: %d; set to %d.", size, city_size);
6977 vision_site_size_set(pdcity, city_size);
6978
6979 /* Initialise list of improvements */
6980 BV_CLR_ALL(pdcity->improvements);
6981 str = secfile_lookup_str(loading->file, "%s.improvements", citystr);
6982 sg_warn_ret_val(str != NULL, FALSE, "%s", secfile_error());
6983 sg_warn_ret_val(strlen(str) == loading->improvement.size, FALSE,
6984 "Invalid length of '%s.improvements' ("
6985 SIZE_T_PRINTF " ~= " SIZE_T_PRINTF ").",
6986 citystr, strlen(str), loading->improvement.size);
6987 for (i = 0; i < loading->improvement.size; i++) {
6988 sg_warn_ret_val(str[i] == '1' || str[i] == '0', FALSE,
6989 "Undefined value '%c' within '%s.improvements'.",
6990 str[i], citystr)
6991
6992 if (str[i] == '1') {
6993 struct impr_type *pimprove =
6995 if (pimprove) {
6996 BV_SET(pdcity->improvements, improvement_index(pimprove));
6997 }
6998 }
6999 }
7000
7001 vname = secfile_lookup_str_default(loading->file, NULL,
7002 "%s.name", citystr);
7003
7004 if (vname != NULL) {
7005 pdcity->name = fc_strdup(vname);
7006 }
7007
7008 pdcity->occupied = secfile_lookup_bool_default(loading->file, FALSE,
7009 "%s.occupied", citystr);
7010 pdcity->walls = secfile_lookup_bool_default(loading->file, FALSE,
7011 "%s.walls", citystr);
7012 pdcity->happy = secfile_lookup_bool_default(loading->file, FALSE,
7013 "%s.happy", citystr);
7014 pdcity->unhappy = secfile_lookup_bool_default(loading->file, FALSE,
7015 "%s.unhappy", citystr);
7016 stylename = secfile_lookup_str_default(loading->file, NULL,
7017 "%s.style", citystr);
7018 if (stylename != NULL) {
7019 pdcity->style = city_style_by_rule_name(stylename);
7020 } else {
7021 pdcity->style = 0;
7022 }
7023 if (pdcity->style < 0) {
7024 pdcity->style = 0;
7025 }
7026
7027 pdcity->city_image = secfile_lookup_int_default(loading->file, -100,
7028 "%s.city_image", citystr);
7029
7030 cap = capital_type_by_name(secfile_lookup_str_default(loading->file, NULL,
7031 "%s.capital", citystr),
7033
7034 if (capital_type_is_valid(cap)) {
7035 pdcity->capital = cap;
7036 } else {
7037 pdcity->capital = CAPITAL_NOT;
7038 }
7039
7040 return TRUE;
7041}
7042
7043/************************************************************************/
7046static void sg_save_player_vision(struct savedata *saving,
7047 struct player *plr)
7048{
7049 int i, plrno = player_number(plr);
7050
7051 /* Check status and return if not OK (sg_success FALSE). */
7052 sg_check_ret();
7053
7055 /* The player can see all, there's no reason to save the private map. */
7056 return;
7057 }
7058
7059 /* Save the map (terrain). */
7060 SAVE_MAP_CHAR(ptile,
7062 saving->file, "player%d.map_t%04d", plrno);
7063
7065 /* Save the map (borders). */
7066 int x, y;
7067
7068 for (y = 0; y < wld.map.ysize; y++) {
7069 char line[wld.map.xsize * TOKEN_SIZE];
7070
7071 line[0] = '\0';
7072 for (x = 0; x < wld.map.xsize; x++) {
7073 char token[TOKEN_SIZE];
7074 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
7075 struct player_tile *plrtile = map_get_player_tile(ptile, plr);
7076
7077 if (plrtile == NULL || plrtile->owner == NULL) {
7078 strcpy(token, "-");
7079 } else {
7080 fc_snprintf(token, sizeof(token), "%d",
7081 player_number(plrtile->owner));
7082 }
7083 strcat(line, token);
7084 if (x < wld.map.xsize) {
7085 strcat(line, ",");
7086 }
7087 }
7088 secfile_insert_str(saving->file, line, "player%d.map_owner%04d",
7089 plrno, y);
7090 }
7091
7092 for (y = 0; y < wld.map.ysize; y++) {
7093 char line[wld.map.xsize * TOKEN_SIZE];
7094
7095 line[0] = '\0';
7096 for (x = 0; x < wld.map.xsize; x++) {
7097 char token[TOKEN_SIZE];
7098 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
7099 struct player_tile *plrtile = map_get_player_tile(ptile, plr);
7100
7101 if (plrtile == NULL || plrtile->extras_owner == NULL) {
7102 strcpy(token, "-");
7103 } else {
7104 fc_snprintf(token, sizeof(token), "%d",
7105 player_number(plrtile->extras_owner));
7106 }
7107 strcat(line, token);
7108 if (x < wld.map.xsize) {
7109 strcat(line, ",");
7110 }
7111 }
7112 secfile_insert_str(saving->file, line, "player%d.extras_owner%04d",
7113 plrno, y);
7114 }
7115 }
7116
7117 /* Save the map (extras). */
7119 int mod[4];
7120 int l;
7121
7122 for (l = 0; l < 4; l++) {
7123 if (4 * j + 1 > game.control.num_extra_types) {
7124 mod[l] = -1;
7125 } else {
7126 mod[l] = 4 * j + l;
7127 }
7128 }
7129
7130 SAVE_MAP_CHAR(ptile,
7132 map_get_player_tile(ptile, plr)->resource,
7133 mod),
7134 saving->file, "player%d.map_e%02d_%04d", plrno, j);
7136
7137 /* Save the map (update time). */
7138 for (i = 0; i < 4; i++) {
7139 /* put 4-bit segments of 16-bit "updated" field */
7140 SAVE_MAP_CHAR(ptile,
7142 map_get_player_tile(ptile, plr)->last_updated, i),
7143 saving->file, "player%d.map_u%02d_%04d", plrno, i);
7144 }
7145
7146 /* Save known cities. */
7147 i = 0;
7148 whole_map_iterate(&(wld.map), ptile) {
7149 struct vision_site *pdcity = map_get_player_city(ptile, plr);
7150 char impr_buf[B_LAST + 1];
7151 char buf[32];
7152
7153 fc_snprintf(buf, sizeof(buf), "player%d.dc%d", plrno, i);
7154
7155 if (NULL != pdcity && plr != vision_site_owner(pdcity)) {
7156 int nat_x, nat_y;
7157
7159 secfile_insert_int(saving->file, nat_y, "%s.y", buf);
7160 secfile_insert_int(saving->file, nat_x, "%s.x", buf);
7161
7162 secfile_insert_int(saving->file, pdcity->identity, "%s.id", buf);
7164 "%s.owner", buf);
7165
7167 "%s.size", buf);
7168 secfile_insert_bool(saving->file, pdcity->occupied,
7169 "%s.occupied", buf);
7170 secfile_insert_bool(saving->file, pdcity->walls, "%s.walls", buf);
7171 secfile_insert_bool(saving->file, pdcity->happy, "%s.happy", buf);
7172 secfile_insert_bool(saving->file, pdcity->unhappy, "%s.unhappy", buf);
7174 "%s.style", buf);
7175 secfile_insert_int(saving->file, pdcity->city_image, "%s.city_image", buf);
7176 secfile_insert_str(saving->file, capital_type_name(pdcity->capital),
7177 "%s.capital", buf);
7178
7179 /* Save improvement list as bitvector. Note that improvement order
7180 * is saved in savefile.improvement.order. */
7181 improvement_iterate(pimprove) {
7182 impr_buf[improvement_index(pimprove)]
7183 = BV_ISSET(pdcity->improvements, improvement_index(pimprove))
7184 ? '1' : '0';
7186 impr_buf[improvement_count()] = '\0';
7187 sg_failure_ret(strlen(impr_buf) < sizeof(impr_buf),
7188 "Invalid size of the improvement vector (%s.improvements: "
7189 SIZE_T_PRINTF " < " SIZE_T_PRINTF" ).",
7190 buf, strlen(impr_buf), sizeof(impr_buf));
7191 secfile_insert_str(saving->file, impr_buf, "%s.improvements", buf);
7192 if (pdcity->name != NULL) {
7193 secfile_insert_str(saving->file, pdcity->name, "%s.name", buf);
7194 }
7195
7196 i++;
7197 }
7199
7200 secfile_insert_int(saving->file, i, "player%d.dc_total", plrno);
7201}
7202
7203/* =======================================================================
7204 * Load / save the researches.
7205 * ======================================================================= */
7206
7207/************************************************************************/
7210static void sg_load_researches(struct loaddata *loading)
7211{
7212 struct research *presearch;
7213 int count;
7214 int number;
7215 const char *str;
7216 int i, j;
7217 int *vlist_research;
7218
7219 vlist_research = NULL;
7220 /* Check status and return if not OK (sg_success FALSE). */
7221 sg_check_ret();
7222
7223 /* Initialize all researches. */
7224 researches_iterate(pinitres) {
7225 init_tech(pinitres, FALSE);
7227
7228 /* May be unsaved (e.g. scenario case). */
7229 count = secfile_lookup_int_default(loading->file, 0, "research.count");
7230 for (i = 0; i < count; i++) {
7231 sg_failure_ret(secfile_lookup_int(loading->file, &number,
7232 "research.r%d.number", i),
7233 "%s", secfile_error());
7234 presearch = research_by_number(number);
7235 sg_failure_ret(presearch != NULL,
7236 "Invalid research number %d in 'research.r%d.number'",
7237 number, i);
7238
7239 presearch->tech_goal = technology_load(loading->file,
7240 "research.r%d.goal", i);
7242 &presearch->techs_researched,
7243 "research.r%d.techs", i),
7244 "%s", secfile_error());
7246 &presearch->future_tech,
7247 "research.r%d.futuretech", i),
7248 "%s", secfile_error());
7250 &presearch->bulbs_researched,
7251 "research.r%d.bulbs", i),
7252 "%s", secfile_error());
7254 &presearch->bulbs_researching_saved,
7255 "research.r%d.bulbs_before", i),
7256 "%s", secfile_error());
7257 presearch->researching_saved = technology_load(loading->file,
7258 "research.r%d.saved", i);
7259 presearch->researching = technology_load(loading->file,
7260 "research.r%d.now", i);
7262 &presearch->got_tech,
7263 "research.r%d.got_tech", i),
7264 "%s", secfile_error());
7265
7266 /* Older savegames (3.0 betas) had a bug that got_tech_multi was not saved.
7267 * Have to live with such savegames, so can't make it an error if value
7268 * is not found from the savegame. */
7270 "research.r%d.got_tech_multi",
7271 i);
7272
7273 str = secfile_lookup_str(loading->file, "research.r%d.done", i);
7274 sg_failure_ret(str != NULL, "%s", secfile_error());
7275 sg_failure_ret(strlen(str) == loading->technology.size,
7276 "Invalid length of 'research.r%d.done' ("
7277 SIZE_T_PRINTF " ~= " SIZE_T_PRINTF ").",
7278 i, strlen(str), loading->technology.size);
7279 for (j = 0; j < loading->technology.size; j++) {
7280 sg_failure_ret(str[j] == '1' || str[j] == '0',
7281 "Undefined value '%c' within 'research.r%d.done'.",
7282 str[j], i);
7283
7284 if (str[j] == '1') {
7285 struct advance *padvance =
7287
7288 if (padvance) {
7289 research_invention_set(presearch, advance_number(padvance),
7290 TECH_KNOWN);
7291 }
7292 }
7293 }
7294
7296 size_t count_res;
7297 int tn;
7298
7299 vlist_research = secfile_lookup_int_vec(loading->file, &count_res,
7300 "research.r%d.vbs", i);
7301
7302 for (tn = 0; tn < count_res; tn++) {
7303 struct advance *padvance = advance_by_rule_name(loading->technology.order[tn]);
7304
7305 if (padvance != NULL) {
7306 presearch->inventions[advance_index(padvance)].bulbs_researched_saved
7307 = vlist_research[tn];
7308 }
7309 }
7310 }
7311 }
7312
7313 /* In case of tech_leakage, we can update research only after all the
7314 * researches have been loaded */
7315 researches_iterate(pupres) {
7316 research_update(pupres);
7318}
7319
7320/************************************************************************/
7323static void sg_save_researches(struct savedata *saving)
7324{
7325 char invs[A_LAST];
7326 int i = 0;
7327 int *vlist_research;
7328
7329 vlist_research = NULL;
7330 /* Check status and return if not OK (sg_success FALSE). */
7331 sg_check_ret();
7332
7333 if (saving->save_players) {
7334 researches_iterate(presearch) {
7335 secfile_insert_int(saving->file, research_number(presearch),
7336 "research.r%d.number", i);
7337 technology_save(saving->file, "research.r%d.goal",
7338 i, presearch->tech_goal);
7339 secfile_insert_int(saving->file, presearch->techs_researched,
7340 "research.r%d.techs", i);
7341 secfile_insert_int(saving->file, presearch->future_tech,
7342 "research.r%d.futuretech", i);
7343 secfile_insert_int(saving->file, presearch->bulbs_researching_saved,
7344 "research.r%d.bulbs_before", i);
7346 vlist_research = fc_calloc(game.control.num_tech_types, sizeof(int));
7348 vlist_research[j] = presearch->inventions[j].bulbs_researched_saved;
7350 secfile_insert_int_vec(saving->file, vlist_research,
7352 "research.r%d.vbs", i);
7353 if (vlist_research) {
7354 free(vlist_research);
7355 }
7356 }
7357 technology_save(saving->file, "research.r%d.saved",
7358 i, presearch->researching_saved);
7359 secfile_insert_int(saving->file, presearch->bulbs_researched,
7360 "research.r%d.bulbs", i);
7361 technology_save(saving->file, "research.r%d.now",
7362 i, presearch->researching);
7363 secfile_insert_bool(saving->file, presearch->got_tech,
7364 "research.r%d.got_tech", i);
7365 secfile_insert_bool(saving->file, presearch->got_tech_multi,
7366 "research.r%d.got_tech_multi", i);
7367 /* Save technology lists as bytevector. Note that technology order is
7368 * saved in savefile.technology.order */
7369 advance_index_iterate(A_NONE, tech_id) {
7370 invs[tech_id] = (valid_advance_by_number(tech_id) != NULL
7371 && research_invention_state(presearch, tech_id)
7372 == TECH_KNOWN ? '1' : '0');
7374 invs[game.control.num_tech_types] = '\0';
7375 secfile_insert_str(saving->file, invs, "research.r%d.done", i);
7376 i++;
7378 secfile_insert_int(saving->file, i, "research.count");
7379 }
7380}
7381
7382/* =======================================================================
7383 * Load / save the event cache. Should be the last thing to do.
7384 * ======================================================================= */
7385
7386/************************************************************************/
7389static void sg_load_event_cache(struct loaddata *loading)
7390{
7391 /* Check status and return if not OK (sg_success FALSE). */
7392 sg_check_ret();
7393
7394 event_cache_load(loading->file, "event_cache");
7395}
7396
7397/************************************************************************/
7400static void sg_save_event_cache(struct savedata *saving)
7401{
7402 /* Check status and return if not OK (sg_success FALSE). */
7403 sg_check_ret();
7404
7405 if (saving->scenario) {
7406 /* Do _not_ save events in a scenario. */
7407 return;
7408 }
7409
7410 event_cache_save(saving->file, "event_cache");
7411}
7412
7413/* =======================================================================
7414 * Load / save the open treaties
7415 * ======================================================================= */
7416
7417/************************************************************************/
7420static void sg_load_treaties(struct loaddata *loading)
7421{
7422 int tidx;
7423 const char *plr0;
7424 struct treaty_list *treaties = get_all_treaties();
7425
7426 /* Check status and return if not OK (sg_success FALSE). */
7427 sg_check_ret();
7428
7429 for (tidx = 0; (plr0 = secfile_lookup_str_default(loading->file, NULL,
7430 "treaty%d.plr0", tidx)) != NULL ;
7431 tidx++) {
7432 const char *plr1;
7433 const char *ct;
7434 int cidx;
7435 struct player *p0, *p1;
7436
7437 plr1 = secfile_lookup_str(loading->file, "treaty%d.plr1", tidx);
7438
7439 p0 = player_by_name(plr0);
7440 p1 = player_by_name(plr1);
7441
7442 if (p0 == NULL || p1 == NULL) {
7443 log_error("Treaty between unknown players %s and %s", plr0, plr1);
7444 } else {
7445 struct Treaty *ptreaty = fc_malloc(sizeof(*ptreaty));
7446
7447 init_treaty(ptreaty, p0, p1);
7448 treaty_list_prepend(treaties, ptreaty);
7449
7450 for (cidx = 0; (ct = secfile_lookup_str_default(loading->file, NULL,
7451 "treaty%d.clause%d.type",
7452 tidx, cidx)) != NULL ;
7453 cidx++ ) {
7454 enum clause_type type = clause_type_by_name(ct, fc_strcasecmp);
7455 const char *plrx;
7456
7457 if (!clause_type_is_valid(type)) {
7458 log_error("Invalid clause type \"%s\"", ct);
7459 } else {
7460 struct player *pgiver = NULL;
7461
7462 plrx = secfile_lookup_str(loading->file, "treaty%d.clause%d.from",
7463 tidx, cidx);
7464
7465 if (!fc_strcasecmp(plrx, plr0)) {
7466 pgiver = p0;
7467 } else if (!fc_strcasecmp(plrx, plr1)) {
7468 pgiver = p1;
7469 } else {
7470 log_error("Clause giver %s is not participant of the treaty"
7471 "between %s and %s", plrx, plr0, plr1);
7472 }
7473
7474 if (pgiver != NULL) {
7475 int value;
7476
7477 value = secfile_lookup_int_default(loading->file, 0,
7478 "treaty%d.clause%d.value",
7479 tidx, cidx);
7480
7481 add_clause(ptreaty, pgiver, type, value, NULL);
7482 }
7483 }
7484 }
7485
7486 /* These must be after clauses have been added so that acceptance
7487 * does not get cleared by what seems like changes to the treaty. */
7488 ptreaty->accept0 = secfile_lookup_bool_default(loading->file, FALSE,
7489 "treaty%d.accept0", tidx);
7490 ptreaty->accept1 = secfile_lookup_bool_default(loading->file, FALSE,
7491 "treaty%d.accept1", tidx);
7492 }
7493 }
7494}
7495
7496/************************************************************************/
7499static void sg_save_treaties(struct savedata *saving)
7500{
7501 struct treaty_list *treaties = get_all_treaties();
7502 int tidx = 0;
7503
7505 char tpath[512];
7506 int cidx = 0;
7507
7508 fc_snprintf(tpath, sizeof(tpath), "treaty%d", tidx++);
7509
7510 secfile_insert_str(saving->file, player_name(ptr->plr0), "%s.plr0", tpath);
7511 secfile_insert_str(saving->file, player_name(ptr->plr1), "%s.plr1", tpath);
7512 secfile_insert_bool(saving->file, ptr->accept0, "%s.accept0", tpath);
7513 secfile_insert_bool(saving->file, ptr->accept1, "%s.accept1", tpath);
7514
7515 clause_list_iterate(ptr->clauses, pclaus) {
7516 char cpath[512];
7517
7518 fc_snprintf(cpath, sizeof(cpath), "%s.clause%d", tpath, cidx++);
7519
7520 secfile_insert_str(saving->file, clause_type_name(pclaus->type), "%s.type", cpath);
7521 secfile_insert_str(saving->file, player_name(pclaus->from), "%s.from", cpath);
7522 secfile_insert_int(saving->file, pclaus->value, "%s.value", cpath);
7525}
7526
7527/* =======================================================================
7528 * Load / save the history report
7529 * ======================================================================= */
7530
7531/************************************************************************/
7534static void sg_load_history(struct loaddata *loading)
7535{
7536 struct history_report *hist = history_report_get();
7537 int turn;
7538
7539 /* Check status and return if not OK (sg_success FALSE). */
7540 sg_check_ret();
7541
7542 turn = secfile_lookup_int_default(loading->file, -2, "history.turn");
7543
7544 if (turn != -2) {
7545 hist->turn = turn;
7546 }
7547
7548 if (turn + 1 >= game.info.turn) {
7549 const char *str;
7550
7551 str = secfile_lookup_str(loading->file, "history.title");
7552 sg_failure_ret(str != NULL, "%s", secfile_error());
7553 sz_strlcpy(hist->title, str);
7554 str = secfile_lookup_str(loading->file, "history.body");
7555 sg_failure_ret(str != NULL, "%s", secfile_error());
7556 sz_strlcpy(hist->body, str);
7557 }
7558}
7559
7560/************************************************************************/
7563static void sg_save_history(struct savedata *saving)
7564{
7565 struct history_report *hist = history_report_get();
7566
7567 secfile_insert_int(saving->file, hist->turn, "history.turn");
7568
7569 if (hist->turn + 1 >= game.info.turn) {
7570 secfile_insert_str(saving->file, hist->title, "history.title");
7571 secfile_insert_str(saving->file, hist->body, "history.body");
7572 }
7573}
7574
7575/* =======================================================================
7576 * Load / save the mapimg definitions.
7577 * ======================================================================= */
7578
7579/************************************************************************/
7582static void sg_load_mapimg(struct loaddata *loading)
7583{
7584 int mapdef_count, i;
7585
7586 /* Check status and return if not OK (sg_success FALSE). */
7587 sg_check_ret();
7588
7589 /* Clear all defined map images. */
7590 while (mapimg_count() > 0) {
7591 mapimg_delete(0);
7592 }
7593
7594 mapdef_count = secfile_lookup_int_default(loading->file, 0,
7595 "mapimg.count");
7596 log_verbose("Saved map image definitions: %d.", mapdef_count);
7597
7598 if (0 >= mapdef_count) {
7599 return;
7600 }
7601
7602 for (i = 0; i < mapdef_count; i++) {
7603 const char *p;
7604
7605 p = secfile_lookup_str(loading->file, "mapimg.mapdef%d", i);
7606 if (NULL == p) {
7607 log_verbose("[Mapimg %4d] Missing definition.", i);
7608 continue;
7609 }
7610
7611 if (!mapimg_define(p, FALSE)) {
7612 log_error("Invalid map image definition %4d: %s.", i, p);
7613 }
7614
7615 log_verbose("Mapimg %4d loaded.", i);
7616 }
7617}
7618
7619/************************************************************************/
7622static void sg_save_mapimg(struct savedata *saving)
7623{
7624 /* Check status and return if not OK (sg_success FALSE). */
7625 sg_check_ret();
7626
7627 secfile_insert_int(saving->file, mapimg_count(), "mapimg.count");
7628 if (mapimg_count() > 0) {
7629 int i;
7630
7631 for (i = 0; i < mapimg_count(); i++) {
7632 char buf[MAX_LEN_MAPDEF];
7633
7634 mapimg_id2str(i, buf, sizeof(buf));
7635 secfile_insert_str(saving->file, buf, "mapimg.mapdef%d", i);
7636 }
7637 }
7638}
7639
7640/* =======================================================================
7641 * Sanity checks for loading / saving a game.
7642 * ======================================================================= */
7643
7644/************************************************************************/
7647static void sg_load_sanitycheck(struct loaddata *loading)
7648{
7649 int players;
7650
7651 /* Check status and return if not OK (sg_success FALSE). */
7652 sg_check_ret();
7653
7654 if (game.info.is_new_game) {
7655 /* Nothing to do for new games (or not started scenarios). */
7656 return;
7657 }
7658
7659 /* Old savegames may have maxplayers lower than current player count,
7660 * fix. */
7661 players = normal_player_count();
7662 if (game.server.max_players < players) {
7663 log_verbose("Max players lower than current players, fixing");
7664 game.server.max_players = players;
7665 }
7666
7667 /* Fix ferrying sanity */
7668 players_iterate(pplayer) {
7669 unit_list_iterate_safe(pplayer->units, punit) {
7672 log_sg("Removing %s unferried %s in %s at (%d, %d)",
7678 }
7681
7682 /* Fix stacking issues. We don't rely on the savegame preserving
7683 * alliance invariants (old savegames often did not) so if there are any
7684 * unallied units on the same tile we just bounce them. */
7685 players_iterate(pplayer) {
7686 players_iterate(aplayer) {
7687 resolve_unit_stacks(pplayer, aplayer, TRUE);
7690
7691 /* Recalculate the potential buildings for each city. Has caused some
7692 * problems with game random state.
7693 * This also changes the game state if you save the game directly after
7694 * loading it and compare the results. */
7695 players_iterate(pplayer) {
7696 /* Building advisor needs data phase open in order to work */
7697 adv_data_phase_init(pplayer, FALSE);
7698 building_advisor(pplayer);
7699 /* Close data phase again so it can be opened again when game starts. */
7700 adv_data_phase_done(pplayer);
7702
7703 /* Prevent a buggy or intentionally crafted save game from crashing
7704 * Freeciv. See hrm Bug #887748 */
7705 players_iterate(pplayer) {
7706 city_list_iterate(pplayer->cities, pcity) {
7707 worker_task_list_iterate(pcity->task_reqs, ptask) {
7708 if (!worker_task_is_sane(ptask)) {
7709 log_error("[city id: %d] Bad worker task %d.",
7710 pcity->id, ptask->act);
7711 worker_task_list_remove(pcity->task_reqs, ptask);
7712 free(ptask);
7713 ptask = NULL;
7714 }
7718
7719 /* Check worked tiles map */
7720#ifdef FREECIV_DEBUG
7721 if (loading->worked_tiles != NULL) {
7722 /* check the entire map for unused worked tiles */
7723 whole_map_iterate(&(wld.map), ptile) {
7724 if (loading->worked_tiles[ptile->index] != -1) {
7725 log_error("[city id: %d] Unused worked tile at (%d, %d).",
7726 loading->worked_tiles[ptile->index], TILE_XY(ptile));
7727 }
7729 }
7730#endif /* FREECIV_DEBUG */
7731
7732 /* Check researching technologies and goals. */
7733 researches_iterate(presearch) {
7734 int techs;
7735
7736 if (presearch->researching != A_UNSET
7737 && !is_future_tech(presearch->researching)
7738 && (valid_advance_by_number(presearch->researching) == NULL
7739 || (research_invention_state(presearch, presearch->researching)
7740 != TECH_PREREQS_KNOWN))) {
7741 log_sg(_("%s had invalid researching technology."),
7742 research_name_translation(presearch));
7743 presearch->researching = A_UNSET;
7744 }
7745 if (presearch->tech_goal != A_UNSET
7746 && !is_future_tech(presearch->tech_goal)
7747 && (valid_advance_by_number(presearch->tech_goal) == NULL
7748 || !research_invention_reachable(presearch, presearch->tech_goal)
7749 || (research_invention_state(presearch, presearch->tech_goal)
7750 == TECH_KNOWN))) {
7751 log_sg(_("%s had invalid technology goal."),
7752 research_name_translation(presearch));
7753 presearch->tech_goal = A_UNSET;
7754 }
7755
7757
7758 if (presearch->techs_researched != techs) {
7759 sg_regr(3000300,
7760 _("%s had finished researches count wrong."),
7761 research_name_translation(presearch));
7762 presearch->techs_researched = techs;
7763 }
7765
7766 /* Check if some player has more than one of some UTYF_UNIQUE unit type */
7767 players_iterate(pplayer) {
7768 int unique_count[U_LAST];
7769
7770 memset(unique_count, 0, sizeof(unique_count));
7771
7772 unit_list_iterate(pplayer->units, punit) {
7773 unique_count[utype_index(unit_type_get(punit))]++;
7775
7776 unit_type_iterate(ut) {
7777 if (unique_count[utype_index(ut)] > 1 && utype_has_flag(ut, UTYF_UNIQUE)) {
7778 log_sg(_("%s has multiple units of type %s though it should be possible "
7779 "to have only one."),
7780 player_name(pplayer), utype_name_translation(ut));
7781 }
7784
7785 players_iterate(pplayer) {
7786 unit_list_iterate_safe(pplayer->units, punit) {
7788 punit->orders.list)) {
7789 log_sg("Invalid unit orders for unit %d.", punit->id);
7791 }
7794
7795 /* Check max rates (rules may have changed since saving) */
7796 players_iterate(pplayer) {
7799
7800 if (0 == strlen(server.game_identifier)
7801 || !is_base64url(server.game_identifier)) {
7802 /* This uses fc_rand(), so random state has to be initialized before. */
7803 randomize_base64url_string(server.game_identifier,
7804 sizeof(server.game_identifier));
7805 }
7806
7807 /* Restore game random state, just in case various initialization code
7808 * inexplicably altered the previously existing state. */
7809 if (!game.info.is_new_game) {
7810 fc_rand_set_state(loading->rstate);
7811 }
7812
7813 /* At the end do the default sanity checks. */
7814 sanity_check();
7815}
7816
7817/************************************************************************/
7820static void sg_save_sanitycheck(struct savedata *saving)
7821{
7822 /* Check status and return if not OK (sg_success FALSE). */
7823 sg_check_ret();
7824}
bool achievement_player_has(const struct achievement *pach, const struct player *pplayer)
const char * achievement_rule_name(struct achievement *pach)
struct achievement * achievement_by_rule_name(const char *name)
#define achievements_iterate_end
#define achievements_iterate(_ach_)
static struct action * actions[MAX_NUM_ACTIONS]
Definition actions.c:96
const char * action_id_name_translation(action_id act_id)
Definition actions.c:1910
struct action * action_by_rule_name(const char *name)
Definition actions.c:1708
const char * action_id_rule_name(action_id act_id)
Definition actions.c:1899
bool action_id_exists(const action_id act_id)
Definition actions.c:1697
#define action_id_get_sub_target_kind(act_id)
Definition actions.h:659
#define NUM_ACTIONS
Definition actions.h:297
#define action_id_get_activity(act_id)
Definition actions.h:712
#define ACTION_NONE
Definition actions.h:293
void building_advisor(struct player *pplayer)
bool adv_data_phase_init(struct player *pplayer, bool is_new_phase)
Definition advdata.c:262
void adv_data_phase_done(struct player *pplayer)
Definition advdata.c:553
const char * ai_name(const struct ai_type *ai)
Definition ai.c:329
int ai_type_get_count(void)
Definition ai.c:321
#define CALL_FUNC_EACH_AI(_func,...)
Definition ai.h:384
#define CALL_PLR_AI_FUNC(_func, _player,...)
Definition ai.h:374
#define ai_type_iterate_end
Definition ai.h:369
#define ai_type_iterate(NAME_ai)
Definition ai.h:362
void ai_traits_init(struct player *pplayer)
Definition aitraits.c:32
#define str
Definition astring.c:76
void dbv_clr_all(struct dbv *pdbv)
Definition bitvector.c:179
#define BV_CLR_ALL(bv)
Definition bitvector.h:95
#define BV_SET(bv, bit)
Definition bitvector.h:81
#define BV_ISSET(bv, bit)
Definition bitvector.h:78
#define BV_CLR(bv, bit)
Definition bitvector.h:86
bool has_capabilities(const char *us, const char *them)
Definition capability.c:86
citizens citizens_nation_get(const struct city *pcity, const struct player_slot *pslot)
Definition citizens.c:74
void citizens_nation_set(struct city *pcity, const struct player_slot *pslot, citizens count)
Definition citizens.c:145
citizens citizens_count(const struct city *pcity)
Definition citizens.c:162
void citizens_init(struct city *pcity)
Definition citizens.c:32
void citizens_update(struct city *pcity, struct player *plr)
void city_map_radius_sq_set(struct city *pcity, int radius_sq)
Definition city.c:143
void city_name_set(struct city *pcity, const char *new_name)
Definition city.c:1123
const char * city_name_get(const struct city *pcity)
Definition city.c:1115
const char * city_style_rule_name(const int style)
Definition city.c:1738
struct city * create_city_virtual(struct player *pplayer, struct tile *ptile, const char *name)
Definition city.c:3343
int city_illness_calc(const struct city *pcity, int *ill_base, int *ill_size, int *ill_trade, int *ill_pollution)
Definition city.c:2772
void city_size_set(struct city *pcity, citizens size)
Definition city.c:1158
void city_add_improvement(struct city *pcity, const struct impr_type *pimprove)
Definition city.c:3270
void destroy_city_virtual(struct city *pcity)
Definition city.c:3419
int city_style_by_rule_name(const char *s)
Definition city.c:1711
#define cities_iterate_end
Definition city.h:497
#define city_list_iterate(citylist, pcity)
Definition city.h:488
#define city_tile(_pcity_)
Definition city.h:544
#define cities_iterate(pcity)
Definition city.h:492
#define CITY_MAP_MAX_RADIUS_SQ
Definition city.h:78
static citizens city_size_get(const struct city *pcity)
Definition city.h:549
#define output_type_iterate(output)
Definition city.h:821
#define FREE_WORKED_TILES
Definition city.h:858
#define MAX_CITY_SIZE
Definition city.h:98
#define city_list_iterate_end
Definition city.h:490
#define I_NEVER
Definition city.h:239
#define city_tile_iterate(_nmap, _radius_sq, _city_tile, _tile)
Definition city.h:222
#define city_tile_iterate_end
Definition city.h:230
#define output_type_iterate_end
Definition city.h:827
bool update_dumb_city(struct player *pplayer, struct city *pcity)
Definition citytools.c:2683
bool send_city_suppression(bool now)
Definition citytools.c:2143
static void void city_freeze_workers(struct city *pcity)
Definition citytools.c:135
void city_thaw_workers(struct city *pcity)
Definition citytools.c:145
void reality_check_city(struct player *pplayer, struct tile *ptile)
Definition citytools.c:2751
void city_refresh_vision(struct city *pcity)
Definition citytools.c:3338
void auto_arrange_workers(struct city *pcity)
Definition cityturn.c:369
void city_repair_size(struct city *pcity, int change)
Definition cityturn.c:897
bool city_refresh(struct city *pcity)
Definition cityturn.c:161
static char * ruleset
Definition civmanual.c:206
char * techs
Definition comments.c:30
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit * punit
Definition dialogs_g.h:73
void set_ai_level_directer(struct player *pplayer, enum ai_level level)
Definition difficulty.c:39
static struct treaty_list * treaties
Definition diplhand.c:58
struct treaty_list * get_all_treaties(void)
Definition diplhand.c:986
#define treaty_list_iterate(list, p)
Definition diplhand.h:30
#define treaty_list_iterate_end
Definition diplhand.h:32
void init_treaty(struct Treaty *ptreaty, struct player *plr0, struct player *plr1)
Definition diptreaty.c:96
bool add_clause(struct Treaty *ptreaty, struct player *pfrom, enum clause_type type, int val, struct player *client_player)
Definition diptreaty.c:142
#define clause_list_iterate_end
Definition diptreaty.h:68
#define clause_list_iterate(clauselist, pclause)
Definition diptreaty.h:66
int int id
Definition editgui_g.h:28
struct extra_type * next_extra_for_tile(const struct tile *ptile, enum extra_cause cause, const struct player *pplayer, const struct unit *punit)
Definition extras.c:740
struct extra_type * extra_type_by_rule_name(const char *name)
Definition extras.c:204
struct player * extra_owner(const struct tile *ptile)
Definition extras.c:1068
int extra_number(const struct extra_type *pextra)
Definition extras.c:153
struct extra_type * extra_by_number(int id)
Definition extras.c:175
static struct extra_type extras[MAX_EXTRA_TYPES]
Definition extras.c:31
const char * extra_rule_name(const struct extra_type *pextra)
Definition extras.c:195
#define extra_type_iterate(_p)
Definition extras.h:291
#define extra_type_iterate_end
Definition extras.h:297
#define is_extra_caused_by(e, c)
Definition extras.h:196
#define extra_index(_e_)
Definition extras.h:177
#define EXTRA_NONE
Definition extras.h:82
#define extra_type_by_cause_iterate_end
Definition extras.h:315
#define extra_type_by_cause_iterate(_cause, _extra)
Definition extras.h:309
#define NO_TARGET
Definition fc_types.h:324
#define MAX_TRADE_ROUTES
Definition fc_types.h:1111
int Tech_type_id
Definition fc_types.h:347
unsigned char citizens
Definition fc_types.h:358
#define MAX_NUM_PLAYER_SLOTS
Definition fc_types.h:32
#define MAX_LEN_NAME
Definition fc_types.h:66
@ O_LAST
Definition fc_types.h:91
int Multiplier_type_id
Definition fc_types.h:356
#define IDENTITY_NUMBER_ZERO
Definition fc_types.h:82
#define _(String)
Definition fcintl.h:67
struct civ_game game
Definition game.c:57
struct world wld
Definition game.c:58
struct unit * game_unit_by_number(int id)
Definition game.c:111
void initialize_globals(void)
Definition game.c:663
struct city * game_city_by_number(int id)
Definition game.c:102
#define GAME_DEFAULT_TIMEOUTINTINC
Definition game.h:576
#define GAME_DEFAULT_SCORETURN
Definition game.h:560
#define GAME_DEFAULT_TIMEOUTINT
Definition game.h:575
#define GAME_DEFAULT_TIMEOUTINCMULT
Definition game.h:578
#define GAME_DEFAULT_TIMEOUTINC
Definition game.h:577
#define GAME_DEFAULT_RULESETDIR
Definition game.h:654
#define GAME_DEFAULT_TIMEOUTCOUNTER
Definition game.h:580
#define GAME_DEFAULT_PHASE_MODE
Definition game.h:595
#define GAME_HARDCODED_DEFAULT_SKILL_LEVEL
Definition game.h:676
struct government * government_of_player(const struct player *pplayer)
Definition government.c:113
const char * government_rule_name(const struct government *pgovern)
Definition government.c:132
struct government * government_by_rule_name(const char *name)
Definition government.c:54
#define governments_iterate(NAME_pgov)
Definition government.h:121
#define governments_iterate_end
Definition government.h:124
struct city * owner
Definition citydlg.c:219
GType type
Definition repodlgs.c:1312
void idex_register_unit(struct world *iworld, struct unit *punit)
Definition idex.c:81
void idex_register_city(struct world *iworld, struct city *pcity)
Definition idex.c:66
struct impr_type * improvement_by_number(const Impr_type_id id)
bool great_wonder_is_destroyed(const struct impr_type *pimprove)
bool wonder_is_lost(const struct player *pplayer, const struct impr_type *pimprove)
const char * improvement_rule_name(const struct impr_type *pimprove)
Impr_type_id improvement_index(const struct impr_type *pimprove)
bool is_wonder(const struct impr_type *pimprove)
bool is_great_wonder(const struct impr_type *pimprove)
struct impr_type * improvement_by_rule_name(const char *name)
Impr_type_id improvement_count(void)
#define improvement_iterate_end
#define WONDER_DESTROYED
#define improvement_iterate(_p)
#define WONDER_LOST
#define B_LAST
Definition improvement.h:42
void adv_city_free(struct city *pcity)
Definition infracache.c:501
void adv_city_alloc(struct city *pcity)
Definition infracache.c:488
const char * name
Definition inputfile.c:127
#define fc_assert_msg(condition, message,...)
Definition log.h:181
#define fc_assert_ret(condition)
Definition log.h:191
#define log_verbose(message,...)
Definition log.h:109
#define fc_assert(condition)
Definition log.h:176
#define log_fatal(message,...)
Definition log.h:100
#define fc_assert_action(condition, action)
Definition log.h:187
#define log_debug(message,...)
Definition log.h:115
#define log_normal(message,...)
Definition log.h:107
#define log_error(message,...)
Definition log.h:103
bool startpos_disallow(struct startpos *psp, struct nation_type *pnation)
Definition map.c:1463
#define nat_x
#define nat_y
int sq_map_distance(const struct tile *tile0, const struct tile *tile1)
Definition map.c:639
struct startpos * map_startpos_new(struct tile *ptile)
Definition map.c:1669
struct tile * startpos_tile(const struct startpos *psp)
Definition map.c:1479
bool startpos_allows_all(const struct startpos *psp)
Definition map.c:1499
const struct nation_hash * startpos_raw_nations(const struct startpos *psp)
Definition map.c:1568
void map_init_topology(struct civ_map *nmap)
Definition map.c:301
void main_map_allocate(void)
Definition map.c:517
struct tile * index_to_tile(const struct civ_map *imap, int mindex)
Definition map.c:454
int map_startpos_count(void)
Definition map.c:1656
struct tile * native_pos_to_tile(const struct civ_map *nmap, int nat_x, int nat_y)
Definition map.c:441
bool startpos_is_excluding(const struct startpos *psp)
Definition map.c:1556
bool map_is_empty(void)
Definition map.c:149
bool startpos_allow(struct startpos *psp, struct nation_type *pnation)
Definition map.c:1446
#define map_startpos_iterate(NAME_psp)
Definition map.h:124
#define MAP_INDEX_SIZE
Definition map.h:131
#define map_startpos_iterate_end
Definition map.h:127
#define whole_map_iterate(_map, _tile)
Definition map.h:539
#define index_to_native_pos(pnat_x, pnat_y, mindex)
Definition map.h:151
#define whole_map_iterate_end
Definition map.h:548
map_generator
Definition map_types.h:46
@ MAPGEN_SCENARIO
Definition map_types.h:47
void assign_continent_numbers(void)
void player_map_init(struct player *pplayer)
Definition maphand.c:1202
void update_player_tile_last_seen(struct player *pplayer, struct tile *ptile)
Definition maphand.c:1455
void map_claim_ownership(struct tile *ptile, struct player *powner, struct tile *psource, bool claim_bases)
Definition maphand.c:2191
bool map_is_known(const struct tile *ptile, const struct player *pplayer)
Definition maphand.c:886
bool send_tile_suppression(bool now)
Definition maphand.c:472
bool really_gives_vision(struct player *me, struct player *them)
Definition maphand.c:342
void map_know_and_see_all(struct player *pplayer)
Definition maphand.c:1177
bool update_player_tile_knowledge(struct player *pplayer, struct tile *ptile)
Definition maphand.c:1386
struct vision_site * map_get_player_city(const struct tile *ptile, const struct player *pplayer)
Definition maphand.c:1346
void tile_claim_bases(struct tile *ptile, struct player *powner)
Definition maphand.c:2204
void map_set_known(struct tile *ptile, struct player *pplayer)
Definition maphand.c:1159
bool map_is_known_and_seen(const struct tile *ptile, const struct player *pplayer, enum vision_layer vlayer)
Definition maphand.c:900
void change_playertile_site(struct player_tile *ptile, struct vision_site *new_site)
Definition maphand.c:1140
void map_calculate_borders(void)
Definition maphand.c:2357
void give_shared_vision(struct player *pfrom, struct player *pto)
Definition maphand.c:1620
struct player_tile * map_get_player_tile(const struct tile *ptile, const struct player *pplayer)
Definition maphand.c:1370
bool mapimg_id2str(int id, char *str, size_t str_len)
Definition mapimg.c:1310
bool mapimg_define(const char *maparg, bool check)
Definition mapimg.c:768
bool mapimg_delete(int id)
Definition mapimg.c:1203
int mapimg_count(void)
Definition mapimg.c:572
#define MAX_LEN_MAPDEF
Definition mapimg.h:65
#define fc_calloc(n, esz)
Definition mem.h:38
#define FC_FREE(ptr)
Definition mem.h:41
#define fc_strdup(str)
Definition mem.h:43
#define fc_malloc(sz)
Definition mem.h:34
void set_meta_patches_string(const char *string)
Definition meta.c:171
char * meta_addr_port(void)
Definition meta.c:202
const char * default_meta_patches_string(void)
Definition meta.c:82
const char * get_meta_patches_string(void)
Definition meta.c:106
#define DEFAULT_META_SERVER_ADDR
Definition meta.h:21
bool can_unit_exist_at_tile(const struct civ_map *nmap, const struct unit *punit, const struct tile *ptile)
Definition movement.c:304
const char * multiplier_rule_name(const struct multiplier *pmul)
Multiplier_type_id multiplier_count(void)
Definition multipliers.c:88
struct multiplier * multiplier_by_rule_name(const char *name)
Multiplier_type_id multiplier_index(const struct multiplier *pmul)
Definition multipliers.c:80
#define multipliers_iterate(_mul_)
Definition multipliers.h:61
#define multipliers_iterate_end
Definition multipliers.h:67
const char * nation_rule_name(const struct nation_type *pnation)
Definition nation.c:137
struct nation_type * nation_of_player(const struct player *pplayer)
Definition nation.c:443
struct nation_type * nation_by_rule_name(const char *name)
Definition nation.c:120
static struct nation_type * nations
Definition nation.c:45
const char * nation_plural_for_player(const struct player *pplayer)
Definition nation.c:177
#define nation_hash_iterate(nationhash, pnation)
Definition nation.h:92
#define nation_hash_iterate_end
Definition nation.h:94
#define NO_NATION_SELECTED
Definition nation.h:29
void event_cache_load(struct section_file *file, const char *section)
Definition notify.c:783
void event_cache_save(struct section_file *file, const char *section)
Definition notify.c:903
int parts
Definition packhand.c:130
char * lines
Definition packhand.c:129
int len
Definition packhand.c:125
bool player_slot_is_used(const struct player_slot *pslot)
Definition player.c:441
struct unit * player_unit_by_number(const struct player *pplayer, int unit_id)
Definition player.c:1205
struct player * player_by_number(const int player_id)
Definition player.c:840
bool players_on_same_team(const struct player *pplayer1, const struct player *pplayer2)
Definition player.c:1452
int player_count(void)
Definition player.c:808
int player_slot_count(void)
Definition player.c:411
struct player_slot * player_slot_by_number(int player_id)
Definition player.c:456
int player_number(const struct player *pplayer)
Definition player.c:828
enum dipl_reason pplayer_can_make_treaty(const struct player *p1, const struct player *p2, enum diplstate_type treaty)
Definition player.c:153
const char * player_name(const struct player *pplayer)
Definition player.c:886
int player_slot_max_used_number(void)
Definition player.c:469
int player_slot_index(const struct player_slot *pslot)
Definition player.c:419
struct player * player_by_name(const char *name)
Definition player.c:872
bool player_has_flag(const struct player *pplayer, enum plr_flag_id flag)
Definition player.c:1954
bool player_has_real_embassy(const struct player *pplayer, const struct player *pplayer2)
Definition player.c:234
struct city * player_city_by_number(const struct player *pplayer, int city_id)
Definition player.c:1179
int player_index(const struct player *pplayer)
Definition player.c:820
bool player_set_nation(struct player *pplayer, struct nation_type *pnation)
Definition player.c:852
struct player_diplstate * player_diplstate_get(const struct player *plr1, const struct player *plr2)
Definition player.c:317
bool pplayers_allied(const struct player *pplayer, const struct player *pplayer2)
Definition player.c:1381
struct player_slot * slots
Definition player.c:50
bool gives_shared_vision(const struct player *me, const struct player *them)
Definition player.c:1461
#define players_iterate_end
Definition player.h:535
dipl_reason
Definition player.h:194
@ DIPL_ALLIANCE_PROBLEM_THEM
Definition player.h:196
@ DIPL_ALLIANCE_PROBLEM_US
Definition player.h:196
#define players_iterate(_pplayer)
Definition player.h:530
#define MAX_ATTRIBUTE_BLOCK
Definition player.h:225
#define player_list_iterate(playerlist, pplayer)
Definition player.h:553
static bool is_barbarian(const struct player *pplayer)
Definition player.h:488
#define player_slots_iterate(_pslot)
Definition player.h:521
#define is_ai(plr)
Definition player.h:234
#define player_list_iterate_end
Definition player.h:555
#define players_iterate_alive_end
Definition player.h:545
#define player_slots_iterate_end
Definition player.h:525
#define players_iterate_alive(_pplayer)
Definition player.h:540
void server_player_set_name(struct player *pplayer, const char *name)
Definition plrhand.c:2097
struct player * server_create_player(int player_id, const char *ai_tname, struct rgbcolor *prgbcolor, bool allow_ai_type_fallbacking)
Definition plrhand.c:1723
int normal_player_count(void)
Definition plrhand.c:3034
void player_limit_to_max_rates(struct player *pplayer)
Definition plrhand.c:1886
struct nation_type * pick_a_nation(const struct nation_list *choices, bool ignore_conflicts, bool needs_startpos, enum barbarian_type barb_type)
Definition plrhand.c:2282
void set_shuffled_players(int *shuffled_players)
Definition plrhand.c:2232
void player_delegation_set(struct player *pplayer, const char *username)
Definition plrhand.c:3080
void shuffle_players(void)
Definition plrhand.c:2207
void server_remove_player(struct player *pplayer)
Definition plrhand.c:1772
void server_player_init(struct player *pplayer, bool initmap, bool needs_team)
Definition plrhand.c:1450
void assign_player_colors(void)
Definition plrhand.c:1563
const char * player_delegation_get(const struct player *pplayer)
Definition plrhand.c:3067
void fit_nationset_to_players(void)
Definition plrhand.c:2488
#define shuffled_players_iterate_end
Definition plrhand.h:106
#define shuffled_players_iterate(NAME_pplayer)
Definition plrhand.h:96
bool fc_rand_is_init(void)
Definition rand.c:167
RANDOM_STATE fc_rand_state(void)
Definition rand.c:175
void fc_rand_set_state(RANDOM_STATE state)
Definition rand.c:196
struct section_file * secfile_load(const char *filename, bool allow_duplicates)
Definition registry.c:50
const char * secfile_error(void)
bool secfile_lookup_int(const struct section_file *secfile, int *ival, const char *path,...)
const char ** secfile_lookup_str_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
struct entry * secfile_entry_lookup(const struct section_file *secfile, const char *path,...)
bool entry_str_set_gt_marking(struct entry *pentry, bool gt_marking)
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
int * secfile_lookup_int_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
bool secfile_lookup_bool_default(const struct section_file *secfile, bool def, const char *path,...)
int secfile_lookup_int_default(const struct section_file *secfile, int def, const char *path,...)
struct entry * secfile_entry_by_path(const struct section_file *secfile, const char *path)
struct section * secfile_section_lookup(const struct section_file *secfile, const char *path,...)
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
bool secfile_lookup_bool(const struct section_file *secfile, bool *bval, const char *path,...)
#define secfile_insert_int(secfile, value, path,...)
#define secfile_insert_enum(secfile, enumerator, specenum_type, path,...)
#define secfile_insert_int_vec(secfile, values, dim, path,...)
#define secfile_lookup_enum_default(secfile, defval, specenum_type, path,...)
#define secfile_insert_str_vec(secfile, strings, dim, path,...)
#define secfile_entry_ignore(_sfile_, _fmt_,...)
#define secfile_insert_str(secfile, string, path,...)
#define secfile_insert_bool(secfile, value, path,...)
#define secfile_replace_str(secfile, string, path,...)
struct history_report * history_report_get(void)
Definition report.c:1689
const char * universal_rule_name(const struct universal *psource)
const char * universal_type_rule_name(const struct universal *psource)
struct universal universal_by_rule_name(const char *kind, const char *value)
bool research_invention_reachable(const struct research *presearch, const Tech_type_id tech)
Definition research.c:665
const char * research_name_translation(const struct research *presearch)
Definition research.c:154
enum tech_state research_invention_set(struct research *presearch, Tech_type_id tech, enum tech_state value)
Definition research.c:634
struct research * research_by_number(int number)
Definition research.c:116
int research_number(const struct research *presearch)
Definition research.c:107
int recalculate_techs_researched(const struct research *presearch)
Definition research.c:1318
enum tech_state research_invention_state(const struct research *presearch, Tech_type_id tech)
Definition research.c:616
void research_update(struct research *presearch)
Definition research.c:499
#define researches_iterate(_presearch)
Definition research.h:157
#define researches_iterate_end
Definition research.h:160
void rgbcolor_destroy(struct rgbcolor *prgbcolor)
Definition rgbcolor.c:74
bool rgbcolor_load(struct section_file *file, struct rgbcolor **prgbcolor, char *path,...)
Definition rgbcolor.c:90
void rgbcolor_save(struct section_file *file, const struct rgbcolor *prgbcolor, char *path,...)
Definition rgbcolor.c:121
bool load_rulesets(const char *restore, const char *alt, bool compat_mode, rs_conversion_logger logger, bool act, bool buffer_script, bool load_luadata)
Definition ruleset.c:9227
#define sanity_check()
Definition sanitycheck.h:43
#define sanity_check_city(x)
Definition sanitycheck.h:41
int current_compat_ver(void)
Definition savecompat.c:199
char bin2ascii_hex(int value, int halfbyte_wanted)
Definition savecompat.c:209
void sg_load_compat(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:132
int ascii_hex2bin(char ch, int halfbyte)
Definition savecompat.c:221
void sg_load_post_load_compat(struct loaddata *loading, enum sgf_version format_class)
Definition savecompat.c:177
#define sg_check_ret(...)
Definition savecompat.h:141
#define sg_warn(condition, message,...)
Definition savecompat.h:151
#define hex_chars
Definition savecompat.h:196
#define sg_failure_ret_val(condition, _val, message,...)
Definition savecompat.h:175
#define sg_failure_ret(condition, message,...)
Definition savecompat.h:168
#define sg_regr(fixversion, message,...)
Definition savecompat.h:184
@ SAVEGAME_3
Definition savecompat.h:27
#define log_sg
Definition savecompat.h:137
#define sg_warn_ret_val(condition, _val, message,...)
Definition savecompat.h:162
void savegame3_save(struct section_file *sfile, const char *save_reason, bool scenario)
Definition savegame3.c:417
static void sg_save_history(struct savedata *saving)
Definition savegame3.c:7563
static void unit_ordering_apply(void)
Definition savegame3.c:1052
static void sg_load_players_basic(struct loaddata *loading)
Definition savegame3.c:3436
static struct loaddata * loaddata_new(struct section_file *file)
Definition savegame3.c:566
static void worklist_save(struct section_file *file, const struct worklist *pwl, int max_length, const char *path,...)
Definition savegame3.c:985
static void sg_load_map_known(struct loaddata *loading)
Definition savegame3.c:3316
static void sg_load_map_owner(struct loaddata *loading)
Definition savegame3.c:2986
static void sg_extras_set(bv_extras *extras, char ch, struct extra_type **idx)
Definition savegame3.c:1073
bool sg_success
Definition savecompat.c:32
static char * quote_block(const void *const data, int length)
Definition savegame3.c:870
#define halfbyte_iterate_extras_end
Definition savegame3.c:254
#define halfbyte_iterate_extras(e, num_extras_types)
Definition savegame3.c:249
static void sg_load_map(struct loaddata *loading)
Definition savegame3.c:2626
static enum unit_orders char2order(char order)
Definition savegame3.c:686
static int unquote_block(const char *const quoted_, void *dest, int dest_length)
Definition savegame3.c:891
static void sg_save_map_tiles_extras(struct savedata *saving)
Definition savegame3.c:2818
static void sg_save_map_worked(struct savedata *saving)
Definition savegame3.c:3277
static void sg_save_players(struct savedata *saving)
Definition savegame3.c:3881
#define LOAD_MAP_CHAR(ch, ptile, SET_XY_CHAR, secfile, secpath,...)
Definition savegame3.c:213
static void sg_save_player_cities(struct savedata *saving, struct player *plr)
Definition savegame3.c:5332
static void sg_load_player_city_citizens(struct loaddata *loading, struct player *plr, struct city *pcity, const char *citystr)
Definition savegame3.c:5284
static void sg_load_player_cities(struct loaddata *loading, struct player *plr)
Definition savegame3.c:4723
static void sg_load_map_tiles(struct loaddata *loading)
Definition savegame3.c:2719
static char activity2char(enum unit_activity activity)
Definition savegame3.c:795
static bool sg_load_player_unit(struct loaddata *loading, struct player *plr, struct unit *punit, int orders_max_length, const char *unitstr)
Definition savegame3.c:5797
static struct savedata * savedata_new(struct section_file *file, const char *save_reason, bool scenario)
Definition savegame3.c:655
static void sg_load_savefile(struct loaddata *loading)
Definition savegame3.c:1242
static enum unit_activity char2activity(char activity)
Definition savegame3.c:850
static void unit_ordering_calc(void)
Definition savegame3.c:1023
static bool sg_load_player_city(struct loaddata *loading, struct player *plr, struct city *pcity, const char *citystr, int wlist_max_length)
Definition savegame3.c:4849
static void sg_load_settings(struct loaddata *loading)
Definition savegame3.c:2585
static void sg_load_player_units(struct loaddata *loading, struct player *plr)
Definition savegame3.c:5722
static char terrain2char(const struct terrain *pterrain)
Definition savegame3.c:1156
static void sg_save_random(struct savedata *saving)
Definition savegame3.c:2356
static void sg_save_map_startpos(struct savedata *saving)
Definition savegame3.c:2931
static void sg_load_researches(struct loaddata *loading)
Definition savegame3.c:7210
static void sg_load_map_worked(struct loaddata *loading)
Definition savegame3.c:3233
#define SAVE_MAP_CHAR(ptile, GET_XY_CHAR, secfile, secpath,...)
Definition savegame3.c:166
static void sg_save_savefile_options(struct savedata *saving, const char *option)
Definition savegame3.c:1946
static void sg_load_random(struct loaddata *loading)
Definition savegame3.c:2315
static void sg_save_savefile(struct savedata *saving)
Definition savegame3.c:1667
static void sg_load_player_units_transport(struct loaddata *loading, struct player *plr)
Definition savegame3.c:6278
static void sg_load_history(struct loaddata *loading)
Definition savegame3.c:7534
static void sg_save_treaties(struct savedata *saving)
Definition savegame3.c:7499
static void sg_save_map_owner(struct savedata *saving)
Definition savegame3.c:3107
static void sg_save_researches(struct savedata *saving)
Definition savegame3.c:7323
static void savegame3_save_real(struct section_file *file, const char *save_reason, bool scenario)
Definition savegame3.c:511
#define TOKEN_SIZE
Definition savegame3.c:270
static void sg_load_script(struct loaddata *loading)
Definition savegame3.c:2394
static void sg_load_scenario(struct loaddata *loading)
Definition savegame3.c:2420
static void sg_load_game(struct loaddata *loading)
Definition savegame3.c:1993
static void savedata_destroy(struct savedata *saving)
Definition savegame3.c:674
static void sg_load_player_main(struct loaddata *loading, struct player *plr)
Definition savegame3.c:3942
static char order2char(enum unit_orders order)
Definition savegame3.c:713
static void sg_load_treaties(struct loaddata *loading)
Definition savegame3.c:7420
static void sg_save_scenario(struct savedata *saving)
Definition savegame3.c:2508
#define PART_SIZE
static void sg_save_player_units(struct savedata *saving, struct player *plr)
Definition savegame3.c:6331
static void sg_save_ruledata(struct savedata *saving)
Definition savegame3.c:2163
static Tech_type_id technology_load(struct section_file *file, const char *path, int plrno)
Definition savegame3.c:1169
static void sg_save_player_vision(struct savedata *saving, struct player *plr)
Definition savegame3.c:7046
static enum direction8 char2dir(char dir)
Definition savegame3.c:737
static struct terrain * char2terrain(char ch)
Definition savegame3.c:1133
static char sg_extras_get(bv_extras extras, struct extra_type *presource, const int *idx)
Definition savegame3.c:1104
static void sg_save_sanitycheck(struct savedata *saving)
Definition savegame3.c:7820
static void sg_load_mapimg(struct loaddata *loading)
Definition savegame3.c:7582
static void sg_load_player_attributes(struct loaddata *loading, struct player *plr)
Definition savegame3.c:6582
static void sg_save_player_attributes(struct savedata *saving, struct player *plr)
Definition savegame3.c:6662
static void sg_load_ruledata(struct loaddata *loading)
Definition savegame3.c:1969
static void sg_save_map(struct savedata *saving)
Definition savegame3.c:2679
static void sg_load_player_vision(struct loaddata *loading, struct player *plr)
Definition savegame3.c:6745
static void sg_save_map_tiles(struct savedata *saving)
Definition savegame3.c:2759
static void worklist_load(struct section_file *file, int wlist_max_length, struct worklist *pwl, const char *path,...)
Definition savegame3.c:939
static void sg_save_mapimg(struct savedata *saving)
Definition savegame3.c:7622
static const char savefile_options_default[]
Definition savegame3.c:272
static char dir2char(enum direction8 dir)
Definition savegame3.c:766
static bool sg_load_player_vision_city(struct loaddata *loading, struct player *plr, struct vision_site *pdcity, const char *citystr)
Definition savegame3.c:6935
static void sg_load_map_startpos(struct loaddata *loading)
Definition savegame3.c:2844
static void loaddata_destroy(struct loaddata *loading)
Definition savegame3.c:603
static void sg_load_players(struct loaddata *loading)
Definition savegame3.c:3692
#define PART_ADJUST
static void technology_save(struct section_file *file, const char *path, int plrno, Tech_type_id tech)
Definition savegame3.c:1205
static void sg_save_event_cache(struct savedata *saving)
Definition savegame3.c:7400
static void sg_load_map_tiles_extras(struct loaddata *loading)
Definition savegame3.c:2787
static void sg_load_sanitycheck(struct loaddata *loading)
Definition savegame3.c:7647
static void sg_load_event_cache(struct loaddata *loading)
Definition savegame3.c:7389
void savegame3_load(struct section_file *file)
Definition savegame3.c:444
static void sg_save_game(struct savedata *saving)
Definition savegame3.c:2183
static void sg_save_player_main(struct savedata *saving, struct player *plr)
Definition savegame3.c:4416
static void sg_save_script(struct savedata *saving)
Definition savegame3.c:2405
static void sg_save_settings(struct savedata *saving)
Definition savegame3.c:2601
static void sg_save_map_known(struct savedata *saving)
Definition savegame3.c:3373
void script_server_state_save(struct section_file *file)
void script_server_state_load(struct section_file *file)
void settings_game_load(struct section_file *file, const char *section)
Definition settings.c:4648
void settings_game_save(struct section_file *file, const char *section)
Definition settings.c:4561
struct setting_list * level[OLEVELS_NUM]
Definition settings.c:183
const char * fileinfoname(const struct strvec *dirs, const char *filename)
Definition shared.c:1094
bool str_to_int(const char *str, int *pint)
Definition shared.c:512
const struct strvec * get_scenario_dirs(void)
Definition shared.c:971
bool is_base64url(const char *s)
Definition shared.c:317
char scanin(const char **buf, char *delimiters, char *dest, int size)
Definition shared.c:1912
void randomize_base64url_string(char *s, size_t n)
Definition shared.c:338
#define CLIP(lower, current, upper)
Definition shared.h:57
#define ARRAY_SIZE(x)
Definition shared.h:85
#define MIN(x, y)
Definition shared.h:55
#define MAX(x, y)
Definition shared.h:54
#define MAX_LEN_PATH
Definition shared.h:32
void spaceship_calc_derived(struct player_spaceship *ship)
Definition spacerace.c:45
void spaceship_init(struct player_spaceship *ship)
Definition spaceship.c:96
#define NUM_SS_STRUCTURALS
Definition spaceship.h:87
@ SSHIP_LAUNCHED
Definition spaceship.h:85
@ SSHIP_NONE
Definition spaceship.h:84
struct specialist * specialist_by_rule_name(const char *name)
Definition specialist.c:112
struct specialist * specialist_by_number(const Specialist_type_id id)
Definition specialist.c:100
Specialist_type_id specialist_index(const struct specialist *sp)
Definition specialist.c:82
const char * specialist_rule_name(const struct specialist *sp)
Definition specialist.c:146
Specialist_type_id specialist_count(void)
Definition specialist.c:71
#define specialist_type_iterate_end
Definition specialist.h:79
#define specialist_type_iterate(sp)
Definition specialist.h:73
#define DEFAULT_SPECIALIST
Definition specialist.h:43
size_t size
Definition specvec.h:72
void server_game_init(bool keep_ruleset_value)
Definition srv_main.c:3382
const char * aifill(int amount)
Definition srv_main.c:2395
bool game_was_started(void)
Definition srv_main.c:339
void identity_number_reserve(int id)
Definition srv_main.c:1926
struct server_arguments srvarg
Definition srv_main.c:173
void init_game_seed(void)
Definition srv_main.c:200
void update_nations_with_startpos(void)
Definition srv_main.c:2200
enum server_states server_state(void)
Definition srv_main.c:323
void server_game_free(void)
Definition srv_main.c:3406
int x
Definition rand.h:30
RANDOM_TYPE v[56]
Definition rand.h:29
int k
Definition rand.h:30
bool is_init
Definition rand.h:31
int j
Definition rand.h:30
bool accept0
Definition diptreaty.h:78
bool accept1
Definition diptreaty.h:78
struct player * first
bv_player achievers
action_id id
Definition actions.h:380
int wonder_city
Definition advdata.h:50
int val
Definition traits.h:38
int mod
Definition traits.h:39
int turn
Definition city.h:238
Definition city.h:309
struct worker_task_list * task_reqs
Definition city.h:395
int turn_last_built
Definition city.h:373
int food_stock
Definition city.h:354
struct built_status built[B_LAST]
Definition city.h:380
struct player * original
Definition city.h:313
int history
Definition city.h:393
bool did_sell
Definition city.h:367
int id
Definition city.h:315
int last_turns_shield_surplus
Definition city.h:378
int disbanded_shields
Definition city.h:377
int turn_plague
Definition city.h:361
bv_city_options city_options
Definition city.h:389
bool was_happy
Definition city.h:368
int turn_founded
Definition city.h:372
int airlift
Definition city.h:365
int caravan_shields
Definition city.h:376
bool did_buy
Definition city.h:366
struct trade_route_list * routes
Definition city.h:332
int anarchy
Definition city.h:370
struct worklist worklist
Definition city.h:387
struct universal production
Definition city.h:382
struct unit_order * orders
Definition city.h:405
struct city::@16 rally_point
struct adv_city * adv
Definition city.h:435
bool vigilant
Definition city.h:404
int steal
Definition city.h:397
int before_change_shields
Definition city.h:375
int style
Definition city.h:316
size_t length
Definition city.h:400
bool synced
Definition city.h:431
citizens specialists[SP_MAX]
Definition city.h:324
struct tile * tile
Definition city.h:311
int shield_stock
Definition city.h:355
struct vision * vision
Definition city.h:438
struct city::@17::@19 server
struct cm_parameter * cm_parameter
Definition city.h:408
struct universal changed_from
Definition city.h:385
struct unit_list * units_supported
Definition city.h:391
bool persistent
Definition city.h:402
int rapture
Definition city.h:371
struct civ_game::@30::@34::@36 save_options
bool multiresearch
Definition game.h:162
bool last_updated_year
Definition game.h:234
struct civ_game::@30::@34 server
float turn_change_time
Definition game.h:217
bool vision_reveal_tiles
Definition game.h:199
struct packet_scenario_description scenario_desc
Definition game.h:88
bool save_private_map
Definition game.h:258
struct packet_ruleset_control control
Definition game.h:83
bool fogofwar_old
Definition game.h:232
struct packet_game_info info
Definition game.h:89
int timeoutcounter
Definition game.h:206
char rulesetdir[MAX_LEN_NAME]
Definition game.h:236
int additional_phase_seconds
Definition game.h:211
struct section_file * luadata
Definition game.h:244
int scoreturn
Definition game.h:223
randseed seed
Definition game.h:225
struct packet_scenario_info scenario
Definition game.h:87
int timeoutint
Definition game.h:202
struct timer * phase_timer
Definition game.h:210
unsigned revealmap
Definition game.h:176
bool save_known
Definition game.h:255
bool foggedborders
Definition game.h:146
char * ruleset_capabilities
Definition game.h:86
int timeoutincmult
Definition game.h:204
int timeoutinc
Definition game.h:203
int phase_mode_stored
Definition game.h:215
int max_players
Definition game.h:155
bool save_starts
Definition game.h:257
int timeoutintinc
Definition game.h:205
int xsize
Definition map_types.h:77
randseed seed
Definition map_types.h:89
int ysize
Definition map_types.h:77
bool have_resources
Definition map_types.h:107
struct civ_map::@41::@43 server
bool have_huts
Definition map_types.h:106
enum map_generator generator
Definition map_types.h:95
bool allow_disorder
Definition cm.h:44
int factor[O_LAST]
Definition cm.h:47
bool max_growth
Definition cm.h:42
bool allow_specialists
Definition cm.h:45
bool require_happy
Definition cm.h:43
int minimal_surplus[O_LAST]
Definition cm.h:41
int happy_factor
Definition cm.h:48
int changed_to_times
Definition government.h:61
char title[REPORT_TITLESIZE]
Definition report.h:27
char body[REPORT_BODYSIZE]
Definition report.h:28
const char * secfile_options
Definition savecompat.h:49
struct loaddata::@111 act_dec
RANDOM_STATE rstate
Definition savecompat.h:131
struct loaddata::@104 multiplier
int full_version
Definition savecompat.h:51
size_t size
Definition savecompat.h:56
struct loaddata::@110 action
struct loaddata::@112 ssa
enum server_states server_state
Definition savecompat.h:128
struct loaddata::@100 technology
struct loaddata::@108 specialist
const char ** order
Definition savecompat.h:55
struct loaddata::@101 activities
struct loaddata::@102 trait
struct loaddata::@99 improvement
int * worked_tiles
Definition savecompat.h:134
struct loaddata::@103 extra
struct section_file * file
Definition savecompat.h:48
int great_wonder_owners[B_LAST]
bool global_advances[A_LAST]
enum ai_level skill_level
enum phase_mode_type phase_mode
char version[MAX_LEN_NAME]
char alt_dir[MAX_LEN_NAME]
char description[MAX_LEN_CONTENT]
char datafile[MAX_LEN_NAME]
char authors[MAX_LEN_PACKET/3]
Definition goto.c:52
enum ai_level skill_level
Definition player.h:122
struct ai_trait * traits
Definition player.h:132
enum barbarian_type barbarian_type
Definition player.h:128
int science_cost
Definition player.h:125
int love[MAX_NUM_PLAYER_SLOTS]
Definition player.h:130
int expand
Definition player.h:124
int fuzzy
Definition player.h:123
char contact_turns_left
Definition player.h:206
int first_contact_turn
Definition player.h:203
enum diplstate_type max_state
Definition player.h:202
enum diplstate_type type
Definition player.h:201
char has_reason_to_cancel
Definition player.h:205
int infra_points
Definition player.h:74
int units_killed
Definition player.h:112
int landarea
Definition player.h:101
int population
Definition player.h:103
int pollution
Definition player.h:106
int wonders
Definition player.h:98
int settledarea
Definition player.h:102
int specialists[SP_MAX]
Definition player.h:97
int units_lost
Definition player.h:113
int angry
Definition player.h:96
int techout
Definition player.h:100
int units_built
Definition player.h:111
int content
Definition player.h:94
int happy
Definition player.h:93
int spaceship
Definition player.h:110
int culture
Definition player.h:115
int unhappy
Definition player.h:95
int literacy
Definition player.h:107
int techs
Definition player.h:99
bv_spaceship_structure structure
Definition spaceship.h:100
enum spaceship_state state
Definition spaceship.h:108
bv_extras extras
Definition maphand.h:36
struct player * extras_owner
Definition maphand.h:35
struct terrain * terrain
Definition maphand.h:33
short last_updated
Definition maphand.h:44
struct player * owner
Definition maphand.h:34
struct extra_type * resource
Definition maphand.h:32
struct city_list * cities
Definition player.h:281
int bulbs_last_turn
Definition player.h:351
struct player_ai ai_common
Definition player.h:288
bv_plr_flags flags
Definition player.h:292
bool is_male
Definition player.h:257
bool got_first_city
Definition player.h:320
int wonders[B_LAST]
Definition player.h:301
bool unassigned_ranked
Definition player.h:255
struct government * target_government
Definition player.h:259
char username[MAX_LEN_NAME]
Definition player.h:252
int revolution_finishes
Definition player.h:273
int nturns_idle
Definition player.h:265
struct government * government
Definition player.h:258
struct team * team
Definition player.h:261
int turns_alive
Definition player.h:266
const struct ai_type * ai
Definition player.h:289
struct unit_list * units
Definition player.h:282
char ranked_username[MAX_LEN_NAME]
Definition player.h:254
int huts
Definition player.h:349
bool is_alive
Definition player.h:268
bv_player real_embassy
Definition player.h:277
struct player_economic economic
Definition player.h:284
struct player_spaceship spaceship
Definition player.h:286
struct attribute_block_s attribute_block
Definition player.h:303
struct player_score score
Definition player.h:283
struct multiplier_value multipliers[MAX_NUM_MULTIPLIERS]
Definition player.h:310
struct nation_type * nation
Definition player.h:260
struct nation_style * style
Definition player.h:279
bool border_vision
Definition player.h:327
bool phase_done
Definition player.h:263
struct adv_data * adv
Definition player.h:334
struct player::@69::@71 server
int history
Definition player.h:312
char orig_username[MAX_LEN_NAME]
Definition player.h:347
int last_war_action
Definition player.h:270
struct rgbcolor * rgb
Definition player.h:308
bool unassigned_user
Definition player.h:253
Tech_type_id researching
Definition research.h:52
int future_tech
Definition research.h:42
Tech_type_id tech_goal
Definition research.h:85
int bulbs_researching_saved
Definition research.h:63
struct research::research_invention inventions[A_ARRAY_SIZE]
bool got_tech_multi
Definition research.h:69
Tech_type_id researching_saved
Definition research.h:62
bool got_tech
Definition research.h:67
int techs_researched
Definition research.h:42
int bulbs_researched
Definition research.h:53
const char * save_reason
Definition savegame3.c:263
struct section_file * file
Definition savegame3.c:259
bool scenario
Definition savegame3.c:264
bool save_players
Definition savegame3.c:267
char secfile_options[512]
Definition savegame3.c:260
char metaserver_addr[256]
Definition srv_main.h:29
char serverid[256]
Definition srv_main.h:49
Definition map.c:41
Definition team.c:40
char identifier_load
Definition terrain.h:185
char identifier
Definition terrain.h:184
Definition tile.h:49
int index
Definition tile.h:50
struct unit_list * units
Definition tile.h:57
int infra_turns
Definition tile.h:61
struct extra_type * placing
Definition tile.h:60
struct tile * claimer
Definition tile.h:63
Definition timing.c:81
enum route_direction dir
Definition traderoutes.h:86
struct goods_type * goods
Definition traderoutes.h:87
enum unit_activity activity
Definition unit.h:94
enum unit_orders order
Definition unit.h:93
int action
Definition unit.h:100
enum direction8 dir
Definition unit.h:102
int target
Definition unit.h:97
int sub_target
Definition unit.h:98
Definition unit.h:138
int length
Definition unit.h:195
int upkeep[O_LAST]
Definition unit.h:148
bool has_orders
Definition unit.h:193
enum action_decision action_decision_want
Definition unit.h:202
int battlegroup
Definition unit.h:191
enum unit_activity activity
Definition unit.h:157
int moves_left
Definition unit.h:150
int id
Definition unit.h:145
int ord_city
Definition unit.h:240
bool moved
Definition unit.h:173
int ord_map
Definition unit.h:239
int index
Definition unit.h:195
struct vision * vision
Definition unit.h:242
bool vigilant
Definition unit.h:197
int hp
Definition unit.h:151
struct unit::@79 orders
int fuel
Definition unit.h:153
struct extra_type * changed_from_target
Definition unit.h:170
bool stay
Definition unit.h:205
enum direction8 facing
Definition unit.h:142
struct extra_type * activity_target
Definition unit.h:164
int activity_count
Definition unit.h:162
struct unit_order * list
Definition unit.h:198
enum unit_activity changed_from
Definition unit.h:168
struct player * nationality
Definition unit.h:144
bool repeat
Definition unit.h:196
struct unit::@80::@83 server
int homecity
Definition unit.h:146
bool paradropped
Definition unit.h:174
bool done_moving
Definition unit.h:181
int birth_turn
Definition unit.h:235
struct goods_type * carrying
Definition unit.h:186
struct tile * goto_tile
Definition unit.h:155
struct tile * action_decision_tile
Definition unit.h:203
int veteran
Definition unit.h:152
int changed_from_count
Definition unit.h:169
enum server_side_agent ssa_controller
Definition unit.h:172
enum universals_n kind
Definition fc_types.h:758
universals_u value
Definition fc_types.h:757
char * name
Definition vision.h:110
bool happy
Definition vision.h:119
bv_imprs improvements
Definition vision.h:125
struct tile * location
Definition vision.h:111
int identity
Definition vision.h:114
int walls
Definition vision.h:118
int style
Definition vision.h:121
bool unhappy
Definition vision.h:120
struct player * owner
Definition vision.h:112
int city_image
Definition vision.h:122
bool occupied
Definition vision.h:117
enum capital_type capital
Definition vision.h:123
enum unit_activity act
Definition workertask.h:23
struct tile * ptile
Definition workertask.h:22
struct extra_type * tgt
Definition workertask.h:24
struct universal entries[MAX_LEN_WORKLIST]
Definition worklist.h:30
int length
Definition worklist.h:29
struct civ_map map
int city_style(struct city *pcity)
Definition style.c:241
struct nation_style * style_by_rule_name(const char *name)
Definition style.c:117
struct nation_style * style_by_number(int id)
Definition style.c:88
const char * style_rule_name(const struct nation_style *pstyle)
Definition style.c:108
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:787
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:189
int cat_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:995
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition support.c:896
#define sz_strlcpy(dest, src)
Definition support.h:167
#define RETURN_VALUE_AFTER_EXIT(_val_)
Definition support.h:121
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define sz_strlcat(dest, src)
Definition support.h:168
int team_index(const struct team *pteam)
Definition team.c:383
struct team_slot * team_slot_by_number(int team_id)
Definition team.c:175
bool team_add_player(struct player *pplayer, struct team *pteam)
Definition team.c:467
struct team * team_new(struct team_slot *tslot)
Definition team.c:317
const struct player_list * team_members(const struct team *pteam)
Definition team.c:456
struct advance * advance_by_number(const Tech_type_id atype)
Definition tech.c:107
bool is_future_tech(Tech_type_id tech)
Definition tech.c:281
struct advance * valid_advance_by_number(const Tech_type_id id)
Definition tech.c:176
const char * advance_rule_name(const struct advance *padvance)
Definition tech.c:299
Tech_type_id advance_index(const struct advance *padvance)
Definition tech.c:89
struct advance * advance_by_rule_name(const char *name)
Definition tech.c:200
Tech_type_id advance_number(const struct advance *padvance)
Definition tech.c:98
#define A_FUTURE
Definition tech.h:46
#define advance_index_iterate_end
Definition tech.h:248
#define advance_iterate(_start, _p)
Definition tech.h:264
#define A_FIRST
Definition tech.h:44
#define A_NONE
Definition tech.h:43
#define A_UNSET
Definition tech.h:48
#define advance_iterate_end
Definition tech.h:270
#define A_UNKNOWN
Definition tech.h:49
#define A_LAST
Definition tech.h:45
#define advance_index_iterate(_start, _index)
Definition tech.h:244
void init_tech(struct research *research, bool update)
Definition techtools.c:1070
struct terrain * terrain_by_rule_name(const char *name)
Definition terrain.c:174
char terrain_identifier(const struct terrain *pterrain)
Definition terrain.c:114
const char * terrain_rule_name(const struct terrain *pterrain)
Definition terrain.c:235
bool terrain_has_resource(const struct terrain *pterrain, const struct extra_type *presource)
Definition terrain.c:243
#define terrain_type_iterate(_p)
Definition terrain.h:358
#define T_UNKNOWN
Definition terrain.h:57
#define TERRAIN_UNKNOWN_IDENTIFIER
Definition terrain.h:188
#define terrain_type_iterate_end
Definition terrain.h:364
bool tile_set_label(struct tile *ptile, const char *label)
Definition tile.c:1080
void tile_set_resource(struct tile *ptile, struct extra_type *presource)
Definition tile.c:343
struct city * tile_city(const struct tile *ptile)
Definition tile.c:83
void tile_set_worked(struct tile *ptile, struct city *pcity)
Definition tile.c:106
#define tile_index(_pt_)
Definition tile.h:87
#define tile_worked(_tile)
Definition tile.h:113
#define tile_terrain(_tile)
Definition tile.h:109
#define TILE_XY(ptile)
Definition tile.h:42
#define tile_has_extra(ptile, pextra)
Definition tile.h:146
#define tile_owner(_tile)
Definition tile.h:95
struct timer * timer_new(enum timer_timetype type, enum timer_use use)
Definition timing.c:157
void timer_destroy(struct timer *t)
Definition timing.c:191
void timer_start(struct timer *t)
Definition timing.c:224
void timer_stop(struct timer *t)
Definition timing.c:268
double timer_read_seconds(struct timer *t)
Definition timing.c:344
#define TIMER_DEBUG
Definition timing.h:59
@ TIMER_CPU
Definition timing.h:40
int city_num_trade_routes(const struct city *pcity)
struct goods_type * goods_by_rule_name(const char *name)
const char * goods_rule_name(struct goods_type *pgood)
struct goods_type * goods_by_number(Goods_type_id id)
#define trade_routes_iterate_end
#define trade_routes_iterate(c, proute)
const struct impr_type * building
Definition fc_types.h:598
void free_unit_orders(struct unit *punit)
Definition unit.c:1753
bool unit_transport_load(struct unit *pcargo, struct unit *ptrans, bool force)
Definition unit.c:2354
void set_unit_activity(struct unit *punit, enum unit_activity new_activity)
Definition unit.c:1107
struct player * unit_nationality(const struct unit *punit)
Definition unit.c:1271
struct unit * unit_transport_get(const struct unit *pcargo)
Definition unit.c:2425
bool can_unit_continue_current_activity(const struct civ_map *nmap, struct unit *punit)
Definition unit.c:845
void set_unit_activity_targeted(struct unit *punit, enum unit_activity new_activity, struct extra_type *new_target)
Definition unit.c:1124
struct unit * unit_virtual_create(struct player *pplayer, struct city *pcity, const struct unit_type *punittype, int veteran_level)
Definition unit.c:1617
bool unit_order_list_is_sane(const struct civ_map *nmap, int length, const struct unit_order *orders)
Definition unit.c:2632
void unit_virtual_destroy(struct unit *punit)
Definition unit.c:1713
void unit_tile_set(struct unit *punit, struct tile *ptile)
Definition unit.c:1281
#define unit_tile(_pu)
Definition unit.h:395
#define BATTLEGROUP_NONE
Definition unit.h:190
unit_orders
Definition unit.h:37
@ ORDER_ACTION_MOVE
Definition unit.h:45
@ ORDER_ACTIVITY
Definition unit.h:41
@ ORDER_FULL_MP
Definition unit.h:43
@ ORDER_MOVE
Definition unit.h:39
@ ORDER_LAST
Definition unit.h:49
@ ORDER_PERFORM_ACTION
Definition unit.h:47
#define unit_owner(_pu)
Definition unit.h:394
void unit_list_sort_ord_map(struct unit_list *punitlist)
Definition unitlist.c:73
void unit_list_sort_ord_city(struct unit_list *punitlist)
Definition unitlist.c:85
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
#define unit_list_iterate_safe(unitlist, _unit)
Definition unitlist.h:39
#define unit_list_iterate_end
Definition unitlist.h:33
#define unit_list_iterate_safe_end
Definition unitlist.h:61
void resolve_unit_stacks(struct player *pplayer, struct player *aplayer, bool verbose)
Definition unittools.c:1414
void unit_refresh_vision(struct unit *punit)
Definition unittools.c:4852
void bounce_unit(struct unit *punit, bool verbose)
Definition unittools.c:1241
bool unit_activity_needs_target_from_client(enum unit_activity activity)
Definition unittools.c:1078
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:123
int utype_upkeep_cost(const struct unit_type *ut, struct player *pplayer, Output_type_id otype)
Definition unittype.c:132
struct unit_type * unit_type_by_rule_name(const char *name)
Definition unittype.c:1819
const char * unit_rule_name(const struct unit *punit)
Definition unittype.c:1639
int utype_veteran_levels(const struct unit_type *punittype)
Definition unittype.c:2673
Unit_type_id utype_index(const struct unit_type *punittype)
Definition unittype.c:91
const char * utype_name_translation(const struct unit_type *punittype)
Definition unittype.c:1612
static bool utype_has_flag(const struct unit_type *punittype, int flag)
Definition unittype.h:604
#define unit_type_iterate(_p)
Definition unittype.h:841
#define U_LAST
Definition unittype.h:40
#define unit_type_iterate_end
Definition unittype.h:848
const char * freeciv_datafile_version(void)
Definition version.c:186
void vision_site_size_set(struct vision_site *psite, citizens size)
Definition vision.c:165
citizens vision_site_size_get(const struct vision_site *psite)
Definition vision.c:155
struct vision * vision_new(struct player *pplayer, struct tile *ptile)
Definition vision.c:33
bool vision_reveal_tiles(struct vision *vision, bool reveal_tiles)
Definition vision.c:62
struct vision_site * vision_site_new(int identity, struct tile *location, struct player *owner)
Definition vision.c:86
void vision_site_destroy(struct vision_site *psite)
Definition vision.c:74
#define vision_site_owner(v)
Definition vision.h:128
bool worker_task_is_sane(struct worker_task *ptask)
Definition workertask.c:40
#define worker_task_list_iterate(tasklist, ptask)
Definition workertask.h:33
#define worker_task_list_iterate_end
Definition workertask.h:35
void worklist_init(struct worklist *pwl)
Definition worklist.c:38
#define MAX_LEN_WORKLIST
Definition worklist.h:24