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 store random_seed for documentation purposes only,
2127 * we don't need it. Just silence "unused entry" warning. */
2128 (void) secfile_entry_lookup(loading->file, "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 store random_seed for documentation purposes only,
2643 * we don't need it. Just silence "unused entry" warning. */
2644 (void) secfile_entry_lookup(loading->file, "map.random_seed");
2645
2646 if (S_S_INITIAL == loading->server_state
2648 /* Generator MAPGEN_SCENARIO is used;
2649 * this map was done with the map editor. */
2650
2651 /* Load tiles. */
2652 sg_load_map_tiles(loading);
2653 sg_load_map_startpos(loading);
2654 sg_load_map_tiles_extras(loading);
2655
2656 /* Nothing more needed for a scenario. */
2657 return;
2658 }
2659
2660 if (S_S_INITIAL == loading->server_state) {
2661 /* Nothing more to do if it is not a scenario but in initial state. */
2662 return;
2663 }
2664
2665 sg_load_map_tiles(loading);
2666 sg_load_map_startpos(loading);
2667 sg_load_map_tiles_extras(loading);
2668 sg_load_map_known(loading);
2669 sg_load_map_owner(loading);
2670 sg_load_map_worked(loading);
2671}
2672
2673/************************************************************************/
2676static void sg_save_map(struct savedata *saving)
2677{
2678 /* Check status and return if not OK (sg_success FALSE). */
2679 sg_check_ret();
2680
2681 if (map_is_empty()) {
2682 /* No map. */
2683 return;
2684 }
2685
2686 if (saving->scenario) {
2688 "map.have_huts");
2690 "map.have_resources");
2691 } else {
2692 secfile_insert_bool(saving->file, TRUE, "map.have_huts");
2693 secfile_insert_bool(saving->file, TRUE, "map.have_resources");
2694 }
2695
2696 /* For debugging purposes only.
2697 * Do not save it if it's 0 (not known);
2698 * this confuses people reading this 'document' less than
2699 * saving 0. */
2700 if (wld.map.server.seed) {
2702 "map.random_seed");
2703 }
2704
2705 sg_save_map_tiles(saving);
2706 sg_save_map_startpos(saving);
2708 sg_save_map_owner(saving);
2709 sg_save_map_worked(saving);
2710 sg_save_map_known(saving);
2711}
2712
2713/************************************************************************/
2716static void sg_load_map_tiles(struct loaddata *loading)
2717{
2718 /* Check status and return if not OK (sg_success FALSE). */
2719 sg_check_ret();
2720
2721 /* Initialize the map for the current topology. 'map.xsize' and
2722 * 'map.ysize' must be set. */
2724
2725 /* Allocate map. */
2727
2728 /* get the terrain type */
2729 LOAD_MAP_CHAR(ch, ptile, ptile->terrain = char2terrain(ch), loading->file,
2730 "map.t%04d");
2732
2733 /* Check for special tile sprites. */
2734 whole_map_iterate(&(wld.map), ptile) {
2735 const char *spec_sprite;
2736 const char *label;
2737 int nat_x, nat_y;
2738
2740 spec_sprite = secfile_lookup_str(loading->file, "map.spec_sprite_%d_%d",
2741 nat_x, nat_y);
2742 label = secfile_lookup_str_default(loading->file, NULL, "map.label_%d_%d",
2743 nat_x, nat_y);
2744 if (NULL != ptile->spec_sprite) {
2745 ptile->spec_sprite = fc_strdup(spec_sprite);
2746 }
2747 if (label != NULL) {
2748 tile_set_label(ptile, label);
2749 }
2751}
2752
2753/************************************************************************/
2756static void sg_save_map_tiles(struct savedata *saving)
2757{
2758 /* Check status and return if not OK (sg_success FALSE). */
2759 sg_check_ret();
2760
2761 /* Save the terrain type. */
2762 SAVE_MAP_CHAR(ptile, terrain2char(ptile->terrain), saving->file,
2763 "map.t%04d");
2764
2765 /* Save special tile sprites. */
2766 whole_map_iterate(&(wld.map), ptile) {
2767 int nat_x, nat_y;
2768
2770 if (ptile->spec_sprite) {
2771 secfile_insert_str(saving->file, ptile->spec_sprite,
2772 "map.spec_sprite_%d_%d", nat_x, nat_y);
2773 }
2774 if (ptile->label != NULL) {
2775 secfile_insert_str(saving->file, ptile->label,
2776 "map.label_%d_%d", nat_x, nat_y);
2777 }
2779}
2780
2781/************************************************************************/
2784static void sg_load_map_tiles_extras(struct loaddata *loading)
2785{
2786 /* Check status and return if not OK (sg_success FALSE). */
2787 sg_check_ret();
2788
2789 /* Load extras. */
2790 halfbyte_iterate_extras(j, loading->extra.size) {
2791 LOAD_MAP_CHAR(ch, ptile, sg_extras_set(&ptile->extras, ch, loading->extra.order + 4 * j),
2792 loading->file, "map.e%02d_%04d", j);
2794
2795 if (S_S_INITIAL != loading->server_state
2798 whole_map_iterate(&(wld.map), ptile) {
2799 extra_type_by_cause_iterate(EC_RESOURCE, pres) {
2800 if (tile_has_extra(ptile, pres)) {
2801 tile_set_resource(ptile, pres);
2802
2803 if (!terrain_has_resource(ptile->terrain, ptile->resource)) {
2804 BV_CLR(ptile->extras, extra_index(pres));
2805 }
2806 }
2809 }
2810}
2811
2812/************************************************************************/
2815static void sg_save_map_tiles_extras(struct savedata *saving)
2816{
2817 /* Check status and return if not OK (sg_success FALSE). */
2818 sg_check_ret();
2819
2820 /* Save extras. */
2822 int mod[4];
2823 int l;
2824
2825 for (l = 0; l < 4; l++) {
2826 if (4 * j + 1 > game.control.num_extra_types) {
2827 mod[l] = -1;
2828 } else {
2829 mod[l] = 4 * j + l;
2830 }
2831 }
2832 SAVE_MAP_CHAR(ptile, sg_extras_get(ptile->extras, ptile->resource, mod),
2833 saving->file, "map.e%02d_%04d", j);
2835}
2836
2837/************************************************************************/
2841static void sg_load_map_startpos(struct loaddata *loading)
2842{
2843 struct nation_type *pnation;
2844 struct startpos *psp;
2845 struct tile *ptile;
2846 const char SEPARATOR = '#';
2847 const char *nation_names;
2848 int nat_x, nat_y;
2849 bool exclude;
2850 int i, startpos_count;
2851
2852 /* Check status and return if not OK (sg_success FALSE). */
2853 sg_check_ret();
2854
2855 startpos_count
2856 = secfile_lookup_int_default(loading->file, 0, "map.startpos_count");
2857
2858 if (0 == startpos_count) {
2859 /* Nothing to do. */
2860 return;
2861 }
2862
2863 for (i = 0; i < startpos_count; i++) {
2864 if (!secfile_lookup_int(loading->file, &nat_x, "map.startpos%d.x", i)
2865 || !secfile_lookup_int(loading->file, &nat_y,
2866 "map.startpos%d.y", i)) {
2867 log_sg("Warning: Undefined coordinates for startpos %d", i);
2868 continue;
2869 }
2870
2871 ptile = native_pos_to_tile(&(wld.map), nat_x, nat_y);
2872 if (NULL == ptile) {
2873 log_error("Start position native coordinates (%d, %d) do not exist "
2874 "in this map. Skipping...", nat_x, nat_y);
2875 continue;
2876 }
2877
2878 exclude = secfile_lookup_bool_default(loading->file, FALSE,
2879 "map.startpos%d.exclude", i);
2880
2881 psp = map_startpos_new(ptile);
2882
2883 nation_names = secfile_lookup_str(loading->file,
2884 "map.startpos%d.nations", i);
2885 if (NULL != nation_names && '\0' != nation_names[0]) {
2886 const size_t size = strlen(nation_names) + 1;
2887 char buf[size], *start, *end;
2888
2889 memcpy(buf, nation_names, size);
2890 for (start = buf - 1; NULL != start; start = end) {
2891 start++;
2892 if ((end = strchr(start, SEPARATOR))) {
2893 *end = '\0';
2894 }
2895
2896 pnation = nation_by_rule_name(start);
2897 if (NO_NATION_SELECTED != pnation) {
2898 if (exclude) {
2899 startpos_disallow(psp, pnation);
2900 } else {
2901 startpos_allow(psp, pnation);
2902 }
2903 } else {
2904 log_verbose("Missing nation \"%s\".", start);
2905 }
2906 }
2907 }
2908 }
2909
2910 if (0 < map_startpos_count()
2911 && loading->server_state == S_S_INITIAL
2913 log_verbose("Number of starts (%d) are lower than rules.max_players "
2914 "(%d), lowering rules.max_players.",
2917 }
2918
2919 /* Re-initialize nation availability in light of start positions.
2920 * This has to be after loading [scenario] and [map].startpos and
2921 * before we seek nations for players. */
2923}
2924
2925/************************************************************************/
2928static void sg_save_map_startpos(struct savedata *saving)
2929{
2930 struct tile *ptile;
2931 const char SEPARATOR = '#';
2932 int i = 0;
2933
2934 /* Check status and return if not OK (sg_success FALSE). */
2935 sg_check_ret();
2936
2938 return;
2939 }
2940
2942 "map.startpos_count");
2943
2945 int nat_x, nat_y;
2946
2947 ptile = startpos_tile(psp);
2948
2950 secfile_insert_int(saving->file, nat_x, "map.startpos%d.x", i);
2951 secfile_insert_int(saving->file, nat_y, "map.startpos%d.y", i);
2952
2954 "map.startpos%d.exclude", i);
2955 if (startpos_allows_all(psp)) {
2956 secfile_insert_str(saving->file, "", "map.startpos%d.nations", i);
2957 } else {
2958 const struct nation_hash *nations = startpos_raw_nations(psp);
2959 char nation_names[MAX_LEN_NAME * nation_hash_size(nations)];
2960
2961 nation_names[0] = '\0';
2962 nation_hash_iterate(nations, pnation) {
2963 if ('\0' == nation_names[0]) {
2964 fc_strlcpy(nation_names, nation_rule_name(pnation),
2965 sizeof(nation_names));
2966 } else {
2967 cat_snprintf(nation_names, sizeof(nation_names),
2968 "%c%s", SEPARATOR, nation_rule_name(pnation));
2969 }
2971 secfile_insert_str(saving->file, nation_names,
2972 "map.startpos%d.nations", i);
2973 }
2974 i++;
2976
2978}
2979
2980/************************************************************************/
2983static void sg_load_map_owner(struct loaddata *loading)
2984{
2985 int x, y;
2986 struct tile *claimer = NULL;
2987 struct extra_type *placing = NULL;
2988
2989 /* Check status and return if not OK (sg_success FALSE). */
2990 sg_check_ret();
2991
2992 if (game.info.is_new_game) {
2993 /* No owner/source information for a new game / scenario. */
2994 return;
2995 }
2996
2997 /* Owner, ownership source, and infra turns are stored as plain numbers */
2998 for (y = 0; y < wld.map.ysize; y++) {
2999 const char *buffer1 = secfile_lookup_str(loading->file,
3000 "map.owner%04d", y);
3001 const char *buffer2 = secfile_lookup_str(loading->file,
3002 "map.source%04d", y);
3003 const char *buffer3 = secfile_lookup_str(loading->file,
3004 "map.eowner%04d", y);
3005 const char *buffer_placing = secfile_lookup_str_default(loading->file,
3006 NULL,
3007 "map.placing%04d", y);
3008 const char *buffer_turns = secfile_lookup_str_default(loading->file,
3009 NULL,
3010 "map.infra_turns%04d", y);
3011 const char *ptr1 = buffer1;
3012 const char *ptr2 = buffer2;
3013 const char *ptr3 = buffer3;
3014 const char *ptr_placing = buffer_placing;
3015 const char *ptr_turns = buffer_turns;
3016
3017 sg_failure_ret(buffer1 != NULL, "%s", secfile_error());
3018 sg_failure_ret(buffer2 != NULL, "%s", secfile_error());
3019 sg_failure_ret(buffer3 != NULL, "%s", secfile_error());
3020
3021 for (x = 0; x < wld.map.xsize; x++) {
3022 char token1[TOKEN_SIZE];
3023 char token2[TOKEN_SIZE];
3024 char token3[TOKEN_SIZE];
3025 char token_placing[TOKEN_SIZE];
3026 char token_turns[TOKEN_SIZE];
3027 struct player *owner = NULL;
3028 struct player *eowner = NULL;
3029 int turns;
3030 int number;
3031 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3032
3033 scanin(&ptr1, ",", token1, sizeof(token1));
3034 sg_failure_ret(token1[0] != '\0',
3035 "Map size not correct (map.owner%d).", y);
3036 if (strcmp(token1, "-") == 0) {
3037 owner = NULL;
3038 } else {
3039 sg_failure_ret(str_to_int(token1, &number),
3040 "Got map owner %s in (%d, %d).", token1, x, y);
3041 owner = player_by_number(number);
3042 }
3043
3044 scanin(&ptr2, ",", token2, sizeof(token2));
3045 sg_failure_ret(token2[0] != '\0',
3046 "Map size not correct (map.source%d).", y);
3047 if (strcmp(token2, "-") == 0) {
3048 claimer = NULL;
3049 } else {
3050 sg_failure_ret(str_to_int(token2, &number),
3051 "Got map source %s in (%d, %d).", token2, x, y);
3052 claimer = index_to_tile(&(wld.map), number);
3053 }
3054
3055 scanin(&ptr3, ",", token3, sizeof(token3));
3056 sg_failure_ret(token3[0] != '\0',
3057 "Map size not correct (map.eowner%d).", y);
3058 if (strcmp(token3, "-") == 0) {
3059 eowner = NULL;
3060 } else {
3061 sg_failure_ret(str_to_int(token3, &number),
3062 "Got base owner %s in (%d, %d).", token3, x, y);
3063 eowner = player_by_number(number);
3064 }
3065
3066 if (ptr_placing != NULL) {
3067 scanin(&ptr_placing, ",", token_placing, sizeof(token_placing));
3068 sg_failure_ret(token_placing[0] != '\0',
3069 "Map size not correct (map.placing%d).", y);
3070 if (strcmp(token_placing, "-") == 0) {
3071 placing = NULL;
3072 } else {
3073 sg_failure_ret(str_to_int(token_placing, &number),
3074 "Got placing extra %s in (%d, %d).", token_placing, x, y);
3075 placing = extra_by_number(number);
3076 }
3077 } else {
3078 placing = NULL;
3079 }
3080
3081 if (ptr_turns != NULL) {
3082 scanin(&ptr_turns, ",", token_turns, sizeof(token_turns));
3083 sg_failure_ret(token_turns[0] != '\0',
3084 "Map size not correct (map.infra_turns%d).", y);
3085 sg_failure_ret(str_to_int(token_turns, &number),
3086 "Got infra_turns %s in (%d, %d).", token_turns, x, y);
3087 turns = number;
3088 } else {
3089 turns = 1;
3090 }
3091
3093 tile_claim_bases(ptile, eowner);
3094 ptile->placing = placing;
3095 ptile->infra_turns = turns;
3096 log_debug("extras_owner(%d, %d) = %s", TILE_XY(ptile), player_name(eowner));
3097 }
3098 }
3099}
3100
3101/************************************************************************/
3104static void sg_save_map_owner(struct savedata *saving)
3105{
3106 int x, y;
3107
3108 /* Check status and return if not OK (sg_success FALSE). */
3109 sg_check_ret();
3110
3111 if (saving->scenario && !saving->save_players) {
3112 /* Nothing to do for a scenario without saved players. */
3113 return;
3114 }
3115
3116 /* Store owner and ownership source as plain numbers. */
3117 for (y = 0; y < wld.map.ysize; y++) {
3118 char line[wld.map.xsize * TOKEN_SIZE];
3119
3120 line[0] = '\0';
3121 for (x = 0; x < wld.map.xsize; x++) {
3122 char token[TOKEN_SIZE];
3123 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3124
3125 if (!saving->save_players || tile_owner(ptile) == NULL) {
3126 strcpy(token, "-");
3127 } else {
3128 fc_snprintf(token, sizeof(token), "%d",
3129 player_number(tile_owner(ptile)));
3130 }
3131 strcat(line, token);
3132 if (x + 1 < wld.map.xsize) {
3133 strcat(line, ",");
3134 }
3135 }
3136 secfile_insert_str(saving->file, line, "map.owner%04d", y);
3137 }
3138
3139 for (y = 0; y < wld.map.ysize; y++) {
3140 char line[wld.map.xsize * TOKEN_SIZE];
3141
3142 line[0] = '\0';
3143 for (x = 0; x < wld.map.xsize; x++) {
3144 char token[TOKEN_SIZE];
3145 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3146
3147 if (ptile->claimer == NULL) {
3148 strcpy(token, "-");
3149 } else {
3150 fc_snprintf(token, sizeof(token), "%d", tile_index(ptile->claimer));
3151 }
3152 strcat(line, token);
3153 if (x + 1 < wld.map.xsize) {
3154 strcat(line, ",");
3155 }
3156 }
3157 secfile_insert_str(saving->file, line, "map.source%04d", y);
3158 }
3159
3160 for (y = 0; y < wld.map.ysize; y++) {
3161 char line[wld.map.xsize * TOKEN_SIZE];
3162
3163 line[0] = '\0';
3164 for (x = 0; x < wld.map.xsize; x++) {
3165 char token[TOKEN_SIZE];
3166 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3167
3168 if (!saving->save_players || extra_owner(ptile) == NULL) {
3169 strcpy(token, "-");
3170 } else {
3171 fc_snprintf(token, sizeof(token), "%d",
3172 player_number(extra_owner(ptile)));
3173 }
3174 strcat(line, token);
3175 if (x + 1 < wld.map.xsize) {
3176 strcat(line, ",");
3177 }
3178 }
3179 secfile_insert_str(saving->file, line, "map.eowner%04d", y);
3180 }
3181
3182 for (y = 0; y < wld.map.ysize; y++) {
3183 char line[wld.map.xsize * TOKEN_SIZE];
3184
3185 line[0] = '\0';
3186 for (x = 0; x < wld.map.xsize; x++) {
3187 char token[TOKEN_SIZE];
3188 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3189
3190 if (ptile->placing == NULL) {
3191 strcpy(token, "-");
3192 } else {
3193 fc_snprintf(token, sizeof(token), "%d",
3194 extra_number(ptile->placing));
3195 }
3196 strcat(line, token);
3197 if (x + 1 < wld.map.xsize) {
3198 strcat(line, ",");
3199 }
3200 }
3201 secfile_insert_str(saving->file, line, "map.placing%04d", y);
3202 }
3203
3204 for (y = 0; y < wld.map.ysize; y++) {
3205 char line[wld.map.xsize * TOKEN_SIZE];
3206
3207 line[0] = '\0';
3208 for (x = 0; x < wld.map.xsize; x++) {
3209 char token[TOKEN_SIZE];
3210 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3211
3212 if (ptile->placing != NULL) {
3213 fc_snprintf(token, sizeof(token), "%d",
3214 ptile->infra_turns);
3215 } else {
3216 fc_snprintf(token, sizeof(token), "0");
3217 }
3218 strcat(line, token);
3219 if (x + 1 < wld.map.xsize) {
3220 strcat(line, ",");
3221 }
3222 }
3223 secfile_insert_str(saving->file, line, "map.infra_turns%04d", y);
3224 }
3225}
3226
3227/************************************************************************/
3230static void sg_load_map_worked(struct loaddata *loading)
3231{
3232 int x, y;
3233
3234 /* Check status and return if not OK (sg_success FALSE). */
3235 sg_check_ret();
3236
3237 sg_failure_ret(loading->worked_tiles == NULL,
3238 "City worked map not loaded!");
3239
3241 sizeof(*loading->worked_tiles));
3242
3243 for (y = 0; y < wld.map.ysize; y++) {
3244 const char *buffer = secfile_lookup_str(loading->file, "map.worked%04d",
3245 y);
3246 const char *ptr = buffer;
3247
3248 sg_failure_ret(NULL != buffer,
3249 "Savegame corrupt - map line %d not found.", y);
3250 for (x = 0; x < wld.map.xsize; x++) {
3251 char token[TOKEN_SIZE];
3252 int number;
3253 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3254
3255 scanin(&ptr, ",", token, sizeof(token));
3256 sg_failure_ret('\0' != token[0],
3257 "Savegame corrupt - map size not correct.");
3258 if (strcmp(token, "-") == 0) {
3259 number = -1;
3260 } else {
3261 sg_failure_ret(str_to_int(token, &number) && 0 < number,
3262 "Savegame corrupt - got tile worked by city "
3263 "id=%s in (%d, %d).", token, x, y);
3264 }
3265
3266 loading->worked_tiles[ptile->index] = number;
3267 }
3268 }
3269}
3270
3271/************************************************************************/
3274static void sg_save_map_worked(struct savedata *saving)
3275{
3276 int x, y;
3277
3278 /* Check status and return if not OK (sg_success FALSE). */
3279 sg_check_ret();
3280
3281 if (saving->scenario && !saving->save_players) {
3282 /* Nothing to do for a scenario without saved players. */
3283 return;
3284 }
3285
3286 /* additionally save the tiles worked by the cities */
3287 for (y = 0; y < wld.map.ysize; y++) {
3288 char line[wld.map.xsize * TOKEN_SIZE];
3289
3290 line[0] = '\0';
3291 for (x = 0; x < wld.map.xsize; x++) {
3292 char token[TOKEN_SIZE];
3293 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
3294 struct city *pcity = tile_worked(ptile);
3295
3296 if (pcity == NULL) {
3297 strcpy(token, "-");
3298 } else {
3299 fc_snprintf(token, sizeof(token), "%d", pcity->id);
3300 }
3301 strcat(line, token);
3302 if (x < wld.map.xsize) {
3303 strcat(line, ",");
3304 }
3305 }
3306 secfile_insert_str(saving->file, line, "map.worked%04d", y);
3307 }
3308}
3309
3310/************************************************************************/
3313static void sg_load_map_known(struct loaddata *loading)
3314{
3315 /* Check status and return if not OK (sg_success FALSE). */
3316 sg_check_ret();
3317
3318 players_iterate(pplayer) {
3319 /* Allocate player private map here; it is needed in different modules
3320 * besides this one ((i.e. sg_load_player_*()). */
3321 player_map_init(pplayer);
3323
3325 "game.save_known")) {
3326 int lines = player_slot_max_used_number()/32 + 1, j, p, l, i;
3327 unsigned int *known = fc_calloc(lines * MAP_INDEX_SIZE, sizeof(*known));
3328
3329 for (l = 0; l < lines; l++) {
3330 for (j = 0; j < 8; j++) {
3331 for (i = 0; i < 4; i++) {
3332 /* Only bother trying to load the map for this halfbyte if at least
3333 * one of the corresponding player slots is in use. */
3334 if (player_slot_is_used(player_slot_by_number(l*32 + j*4 + i))) {
3335 LOAD_MAP_CHAR(ch, ptile,
3336 known[l * MAP_INDEX_SIZE + tile_index(ptile)]
3337 |= ascii_hex2bin(ch, j),
3338 loading->file, "map.k%02d_%04d", l * 8 + j);
3339 break;
3340 }
3341 }
3342 }
3343 }
3344
3345 players_iterate(pplayer) {
3346 dbv_clr_all(&pplayer->tile_known);
3348
3349 /* HACK: we read the known data from hex into 32-bit integers, and
3350 * now we convert it to the known tile data of each player. */
3351 whole_map_iterate(&(wld.map), ptile) {
3352 players_iterate(pplayer) {
3353 p = player_index(pplayer);
3354 l = player_index(pplayer) / 32;
3355
3356 if (known[l * MAP_INDEX_SIZE + tile_index(ptile)] & (1u << (p % 32))) {
3357 map_set_known(ptile, pplayer);
3358 }
3361
3362 FC_FREE(known);
3363 }
3364}
3365
3366/************************************************************************/
3369static void sg_save_map_known(struct savedata *saving)
3370{
3371 /* Check status and return if not OK (sg_success FALSE). */
3372 sg_check_ret();
3373
3374 if (!saving->save_players) {
3375 secfile_insert_bool(saving->file, FALSE, "game.save_known");
3376 return;
3377 } else {
3378 int lines = player_slot_max_used_number()/32 + 1;
3379
3381 "game.save_known");
3383 int j, p, l, i;
3384 unsigned int *known = fc_calloc(lines * MAP_INDEX_SIZE, sizeof(*known));
3385
3386 /* HACK: we convert the data into a 32-bit integer, and then save it as
3387 * hex. */
3388
3389 whole_map_iterate(&(wld.map), ptile) {
3390 players_iterate(pplayer) {
3391 if (map_is_known(ptile, pplayer)) {
3392 p = player_index(pplayer);
3393 l = p / 32;
3394 known[l * MAP_INDEX_SIZE + tile_index(ptile)]
3395 |= (1u << (p % 32)); /* "p % 32" = "p - l * 32" */
3396 }
3399
3400 for (l = 0; l < lines; l++) {
3401 for (j = 0; j < 8; j++) {
3402 for (i = 0; i < 4; i++) {
3403 /* Only bother saving the map for this halfbyte if at least one
3404 * of the corresponding player slots is in use */
3405 if (player_slot_is_used(player_slot_by_number(l*32 + j*4 + i))) {
3406 /* put 4-bit segments of the 32-bit "known" field */
3408 + tile_index(ptile)], j),
3409 saving->file, "map.k%02d_%04d", l * 8 + j);
3410 break;
3411 }
3412 }
3413 }
3414 }
3415
3416 FC_FREE(known);
3417 }
3418 }
3419}
3420
3421/* =======================================================================
3422 * Load / save player data.
3423 *
3424 * This is splitted into two parts as some data can only be loaded if the
3425 * number of players is known and the corresponding player slots are
3426 * defined.
3427 * ======================================================================= */
3428
3429/************************************************************************/
3432static void sg_load_players_basic(struct loaddata *loading)
3433{
3434 int i, k, nplayers;
3435 const char *str;
3436 bool shuffle_loaded = TRUE;
3437
3438 /* Check status and return if not OK (sg_success FALSE). */
3439 sg_check_ret();
3440
3441 if (S_S_INITIAL == loading->server_state
3442 || game.info.is_new_game) {
3443 /* Nothing more to do. */
3444 return;
3445 }
3446
3447 /* Load destroyed wonders: */
3448 str = secfile_lookup_str(loading->file,
3449 "players.destroyed_wonders");
3450 sg_failure_ret(str != NULL, "%s", secfile_error());
3451 sg_failure_ret(strlen(str) == loading->improvement.size,
3452 "Invalid length for 'players.destroyed_wonders' ("
3453 SIZE_T_PRINTF " ~= " SIZE_T_PRINTF ")",
3454 strlen(str), loading->improvement.size);
3455 for (k = 0; k < loading->improvement.size; k++) {
3456 sg_failure_ret(str[k] == '1' || str[k] == '0',
3457 "Undefined value '%c' within "
3458 "'players.destroyed_wonders'.", str[k]);
3459
3460 if (str[k] == '1') {
3461 struct impr_type *pimprove =
3463 if (pimprove) {
3466 }
3467 }
3468 }
3469
3470 server.identity_number
3471 = secfile_lookup_int_default(loading->file, server.identity_number,
3472 "players.identity_number_used");
3473
3474 /* First remove all defined players. */
3475 players_iterate(pplayer) {
3476 server_remove_player(pplayer);
3478
3479 /* Now, load the players from the savefile. */
3480 player_slots_iterate(pslot) {
3481 struct player *pplayer;
3482 struct rgbcolor *prgbcolor = NULL;
3483 int pslot_id = player_slot_index(pslot);
3484
3485 if (NULL == secfile_section_lookup(loading->file, "player%d",
3486 pslot_id)) {
3487 continue;
3488 }
3489
3490 /* Get player AI type. */
3491 str = secfile_lookup_str(loading->file, "player%d.ai_type",
3492 player_slot_index(pslot));
3493 sg_failure_ret(str != NULL, "%s", secfile_error());
3494
3495 /* Get player color */
3496 if (!rgbcolor_load(loading->file, &prgbcolor, "player%d.color",
3497 pslot_id)) {
3498 if (game_was_started()) {
3499 log_sg("Game has started, yet player %d has no color defined.",
3500 pslot_id);
3501 /* This will be fixed up later */
3502 } else {
3503 log_verbose("No color defined for player %d.", pslot_id);
3504 /* Colors will be assigned on game start, or at end of savefile
3505 * loading if game has already started */
3506 }
3507 }
3508
3509 /* Create player. */
3510 pplayer = server_create_player(player_slot_index(pslot), str,
3511 prgbcolor,
3514 sg_failure_ret(pplayer != NULL, "Invalid AI type: '%s'!", str);
3515
3516 server_player_init(pplayer, FALSE, FALSE);
3517
3518 /* Free the color definition. */
3519 rgbcolor_destroy(prgbcolor);
3520
3521 /* Multipliers (policies) */
3522
3523 /* First initialise player values with ruleset defaults; this will
3524 * cover any in the ruleset not known when the savefile was created. */
3525 multipliers_iterate(pmul) {
3526 pplayer->multipliers[multiplier_index(pmul)].value
3527 = pplayer->multipliers[multiplier_index(pmul)].target = pmul->def;
3529
3530 /* Now override with any values from the savefile. */
3531 for (k = 0; k < loading->multiplier.size; k++) {
3532 const struct multiplier *pmul = loading->multiplier.order[k];
3533
3534 if (pmul) {
3536 int val =
3537 secfile_lookup_int_default(loading->file, pmul->def,
3538 "player%d.multiplier%d.val",
3539 player_slot_index(pslot), k);
3540 int rval = (((CLIP(pmul->start, val, pmul->stop)
3541 - pmul->start) / pmul->step) * pmul->step) + pmul->start;
3542
3543 if (rval != val) {
3544 log_verbose("Player %d had illegal value for multiplier \"%s\": "
3545 "was %d, clamped to %d", pslot_id,
3546 multiplier_rule_name(pmul), val, rval);
3547 }
3548 pplayer->multipliers[idx].value = rval;
3549
3550 val =
3552 pplayer->multipliers[idx].value,
3553 "player%d.multiplier%d.target",
3554 player_slot_index(pslot), k);
3555 rval = (((CLIP(pmul->start, val, pmul->stop)
3556 - pmul->start) / pmul->step) * pmul->step) + pmul->start;
3557
3558 if (rval != val) {
3559 log_verbose("Player %d had illegal value for multiplier_target "
3560 " \"%s\": was %d, clamped to %d", pslot_id,
3561 multiplier_rule_name(pmul), val, rval);
3562 }
3563 pplayer->multipliers[idx].target = rval;
3564
3565 pplayer->multipliers[idx].changed
3566 = secfile_lookup_int_default(loading->file, 0,
3567 "player%d.multiplier%d.changed",
3568 player_slot_index(pslot), k);
3569 } /* else silently discard multiplier not in current ruleset */
3570 }
3571
3572 /* Must be loaded before tile owner is set. */
3573 pplayer->server.border_vision =
3575 "player%d.border_vision",
3576 player_slot_index(pslot));
3578
3579 /* check number of players */
3580 nplayers = secfile_lookup_int_default(loading->file, 0, "players.nplayers");
3581 sg_failure_ret(player_count() == nplayers, "The value of players.nplayers "
3582 "(%d) from the loaded game does not match the number of "
3583 "players present (%d).", nplayers, player_count());
3584
3585 /* Load team informations. */
3586 players_iterate(pplayer) {
3587 int team;
3588 struct team_slot *tslot = NULL;
3589
3591 "player%d.team_no",
3592 player_number(pplayer))
3593 && (tslot = team_slot_by_number(team)),
3594 "Invalid team definition for player %s (nb %d).",
3595 player_name(pplayer), player_number(pplayer));
3596 /* Should never fail when slot given is not NULL */
3597 team_add_player(pplayer, team_new(tslot));
3599
3600 /* Loading the shuffle list is quite complex. At the time of saving the
3601 * shuffle data is saved as
3602 * shuffled_player_<number> = player_slot_id
3603 * where number is an increasing number and player_slot_id is a number
3604 * between 0 and the maximum number of player slots. Now we have to create
3605 * a list
3606 * shuffler_players[number] = player_slot_id
3607 * where all player slot IDs are used exactly one time. The code below
3608 * handles this ... */
3609 if (secfile_lookup_int_default(loading->file, -1,
3610 "players.shuffled_player_%d", 0) >= 0) {
3611 int slots = player_slot_count();
3612 int plrcount = player_count();
3613 int shuffled_players[slots];
3614 bool shuffled_player_set[slots];
3615
3616 for (i = 0; i < slots; i++) {
3617 /* Array to save used numbers. */
3618 shuffled_player_set[i] = FALSE;
3619 /* List of all player IDs (needed for set_shuffled_players()). It is
3620 * initialised with the value -1 to indicate that no value is set. */
3621 shuffled_players[i] = -1;
3622 }
3623
3624 /* Load shuffled player list. */
3625 for (i = 0; i < plrcount; i++) {
3626 int shuffle
3627 = secfile_lookup_int_default(loading->file, -1,
3628 "players.shuffled_player_%d", i);
3629
3630 if (shuffle == -1) {
3631 log_sg("Missing player shuffle information (index %d) "
3632 "- reshuffle player list!", i);
3633 shuffle_loaded = FALSE;
3634 break;
3635 } else if (shuffled_player_set[shuffle]) {
3636 log_sg("Player shuffle %d used two times "
3637 "- reshuffle player list!", shuffle);
3638 shuffle_loaded = FALSE;
3639 break;
3640 }
3641 /* Set this ID as used. */
3642 shuffled_player_set[shuffle] = TRUE;
3643
3644 /* Save the player ID in the shuffle list. */
3645 shuffled_players[i] = shuffle;
3646 }
3647
3648 if (shuffle_loaded) {
3649 /* Insert missing numbers. */
3650 int shuffle_index = plrcount;
3651
3652 for (i = 0; i < slots; i++) {
3653 if (!shuffled_player_set[i]) {
3654 shuffled_players[shuffle_index++] = i;
3655 }
3656
3657 /* shuffle_index must not grow higher than size of shuffled_players. */
3658 sg_failure_ret(shuffle_index <= slots,
3659 "Invalid player shuffle data!");
3660 }
3661
3662#ifdef FREECIV_DEBUG
3663 log_debug("[load shuffle] player_count() = %d", player_count());
3664 player_slots_iterate(pslot) {
3665 int plrid = player_slot_index(pslot);
3666
3667 log_debug("[load shuffle] id: %3d => slot: %3d | slot %3d: %s",
3668 plrid, shuffled_players[plrid], plrid,
3669 shuffled_player_set[plrid] ? "is used" : "-");
3671#endif /* FREECIV_DEBUG */
3672
3673 /* Set shuffle list from savegame. */
3674 set_shuffled_players(shuffled_players);
3675 }
3676 }
3677
3678 if (!shuffle_loaded) {
3679 /* No shuffled players included or error loading them, so shuffle them
3680 * (this may include scenarios). */
3682 }
3683}
3684
3685/************************************************************************/
3688static void sg_load_players(struct loaddata *loading)
3689{
3690 /* Check status and return if not OK (sg_success FALSE). */
3691 sg_check_ret();
3692
3693 if (game.info.is_new_game) {
3694 /* Nothing to do. */
3695 return;
3696 }
3697
3698 players_iterate(pplayer) {
3699 sg_load_player_main(loading, pplayer);
3700 sg_load_player_cities(loading, pplayer);
3701 sg_load_player_units(loading, pplayer);
3702 sg_load_player_attributes(loading, pplayer);
3703
3704 /* Check the success of the functions above. */
3705 sg_check_ret();
3706
3707 /* print out some informations */
3708 if (is_ai(pplayer)) {
3709 log_normal(_("%s has been added as %s level AI-controlled player "
3710 "(%s)."), player_name(pplayer),
3711 ai_level_translated_name(pplayer->ai_common.skill_level),
3712 ai_name(pplayer->ai));
3713 } else {
3714 log_normal(_("%s has been added as human player."),
3715 player_name(pplayer));
3716 }
3718
3719 /* Also load the transport status of the units here. It must be a special
3720 * case as all units must be known (unit on an allied transporter). */
3721 players_iterate(pplayer) {
3722 /* Load unit transport status. */
3723 sg_load_player_units_transport(loading, pplayer);
3725
3726 /* Savegame may contain nation assignments that are incompatible with the
3727 * current nationset. Ensure they are compatible, one way or another. */
3729
3730 /* Some players may have invalid nations in the ruleset. Once all players
3731 * are loaded, pick one of the remaining nations for them. */
3732 players_iterate(pplayer) {
3733 if (pplayer->nation == NO_NATION_SELECTED) {
3734 player_set_nation(pplayer, pick_a_nation(NULL, FALSE, TRUE,
3735 NOT_A_BARBARIAN));
3736 /* TRANS: Minor error message: <Leader> ... <Poles>. */
3737 log_sg(_("%s had invalid nation; changing to %s."),
3738 player_name(pplayer), nation_plural_for_player(pplayer));
3739
3740 ai_traits_init(pplayer);
3741 }
3743
3744 /* Sanity check alliances, prevent allied-with-ally-of-enemy. */
3746 players_iterate_alive(aplayer) {
3747 if (pplayers_allied(plr, aplayer)) {
3748 enum dipl_reason can_ally = pplayer_can_make_treaty(plr, aplayer,
3749 DS_ALLIANCE);
3750
3751 if (can_ally == DIPL_ALLIANCE_PROBLEM_US
3752 || can_ally == DIPL_ALLIANCE_PROBLEM_THEM) {
3753 log_sg("Illegal alliance structure detected: "
3754 "%s alliance to %s reduced to peace treaty.",
3757 player_diplstate_get(plr, aplayer)->type = DS_PEACE;
3758 player_diplstate_get(aplayer, plr)->type = DS_PEACE;
3759 }
3760 }
3763
3764 /* Update cached city illness. This can depend on trade routes,
3765 * so can't be calculated until all players have been loaded. */
3766 if (game.info.illness_on) {
3767 cities_iterate(pcity) {
3768 pcity->server.illness
3769 = city_illness_calc(pcity, NULL, NULL,
3770 &(pcity->illness_trade), NULL);
3772 }
3773
3774 /* Update all city information. This must come after all cities are
3775 * loaded (in player_load) but before player (dumb) cities are loaded
3776 * in player_load_vision(). */
3777 players_iterate(plr) {
3778 city_list_iterate(plr->cities, pcity) {
3779 city_refresh(pcity);
3780 sanity_check_city(pcity);
3781 CALL_PLR_AI_FUNC(city_got, plr, plr, pcity);
3784
3785 /* Since the cities must be placed on the map to put them on the
3786 player map we do this afterwards */
3787 players_iterate(pplayer) {
3788 sg_load_player_vision(loading, pplayer);
3789 /* Check the success of the function above. */
3790 sg_check_ret();
3792
3793 /* Check shared vision. */
3794 players_iterate(pplayer) {
3795 BV_CLR_ALL(pplayer->gives_shared_vision);
3796 BV_CLR_ALL(pplayer->server.really_gives_vision);
3798
3799 /* Set up shared vision... */
3800 players_iterate(pplayer) {
3801 int plr1 = player_index(pplayer);
3802
3803 players_iterate(pplayer2) {
3804 int plr2 = player_index(pplayer2);
3806 "player%d.diplstate%d.gives_shared_vision", plr1, plr2)) {
3807 give_shared_vision(pplayer, pplayer2);
3808 }
3811
3812 /* ...and check it */
3813 players_iterate(pplayer1) {
3814 players_iterate(pplayer2) {
3815 /* TODO: Is there a good reason player is not marked as
3816 * giving shared vision to themselves -> really_gives_vision()
3817 * returning FALSE when pplayer1 == pplayer2 */
3818 if (pplayer1 != pplayer2
3819 && players_on_same_team(pplayer1, pplayer2)) {
3820 if (!really_gives_vision(pplayer1, pplayer2)) {
3821 sg_regr(3000900,
3822 _("%s did not give shared vision to team member %s."),
3823 player_name(pplayer1), player_name(pplayer2));
3824 give_shared_vision(pplayer1, pplayer2);
3825 }
3826 if (!really_gives_vision(pplayer2, pplayer1)) {
3827 sg_regr(3000900,
3828 _("%s did not give shared vision to team member %s."),
3829 player_name(pplayer2), player_name(pplayer1));
3830 give_shared_vision(pplayer2, pplayer1);
3831 }
3832 }
3835
3838
3839 /* All vision is ready; this calls city_thaw_workers_queue(). */
3841
3842 /* Make sure everything is consistent. */
3843 players_iterate(pplayer) {
3844 unit_list_iterate(pplayer->units, punit) {
3846 struct tile *ptile = unit_tile(punit);
3847
3848 log_sg("%s doing illegal activity in savegame!",
3850 log_sg("Activity: %s, Target: %s, Tile: (%d, %d), Terrain: %s",
3851 unit_activity_name(punit->activity),
3854 : "missing",
3855 TILE_XY(ptile), terrain_rule_name(tile_terrain(ptile)));
3856 punit->activity = ACTIVITY_IDLE;
3857 }
3860
3861 cities_iterate(pcity) {
3862 city_refresh(pcity);
3863 city_thaw_workers(pcity); /* may auto_arrange_workers() */
3865
3866 /* Player colors are always needed once game has started. Pre-2.4 savegames
3867 * lack them. This cannot be in compatibility conversion layer as we need
3868 * all the player data available to be able to assign best colors. */
3869 if (game_was_started()) {
3871 }
3872}
3873
3874/************************************************************************/
3877static void sg_save_players(struct savedata *saving)
3878{
3879 /* Check status and return if not OK (sg_success FALSE). */
3880 sg_check_ret();
3881
3882 if ((saving->scenario && !saving->save_players)
3883 || !game_was_started()) {
3884 /* Nothing to do for a scenario without saved players or a game in
3885 * INITIAL state. */
3886 return;
3887 }
3888
3889 secfile_insert_int(saving->file, player_count(), "players.nplayers");
3890
3891 /* Save destroyed wonders as bitvector. Note that improvement order
3892 * is saved in 'savefile.improvement.order'. */
3893 {
3894 char destroyed[B_LAST+1];
3895
3896 improvement_iterate(pimprove) {
3897 if (is_great_wonder(pimprove)
3898 && great_wonder_is_destroyed(pimprove)) {
3899 destroyed[improvement_index(pimprove)] = '1';
3900 } else {
3901 destroyed[improvement_index(pimprove)] = '0';
3902 }
3904 destroyed[improvement_count()] = '\0';
3905 secfile_insert_str(saving->file, destroyed,
3906 "players.destroyed_wonders");
3907 }
3908
3909 secfile_insert_int(saving->file, server.identity_number,
3910 "players.identity_number_used");
3911
3912 /* Save player order. */
3913 {
3914 int i = 0;
3915 shuffled_players_iterate(pplayer) {
3916 secfile_insert_int(saving->file, player_number(pplayer),
3917 "players.shuffled_player_%d", i);
3918 i++;
3920 }
3921
3922 /* Sort units. */
3924
3925 /* Save players. */
3926 players_iterate(pplayer) {
3927 sg_save_player_main(saving, pplayer);
3928 sg_save_player_cities(saving, pplayer);
3929 sg_save_player_units(saving, pplayer);
3930 sg_save_player_attributes(saving, pplayer);
3931 sg_save_player_vision(saving, pplayer);
3933}
3934
3935/************************************************************************/
3938static void sg_load_player_main(struct loaddata *loading,
3939 struct player *plr)
3940{
3941 const char **slist;
3942 int i, plrno = player_number(plr);
3943 const char *str;
3944 struct government *gov;
3945 const char *level;
3946 const char *barb_str;
3947 size_t nval;
3948 const char *kind;
3949
3950 /* Check status and return if not OK (sg_success FALSE). */
3951 sg_check_ret();
3952
3953 /* Basic player data. */
3954 str = secfile_lookup_str(loading->file, "player%d.name", plrno);
3955 sg_failure_ret(str != NULL, "%s", secfile_error());
3957 sz_strlcpy(plr->username,
3958 secfile_lookup_str_default(loading->file, "",
3959 "player%d.username", plrno));
3961 "player%d.unassigned_user", plrno),
3962 "%s", secfile_error());
3964 secfile_lookup_str_default(loading->file, "",
3965 "player%d.orig_username", plrno));
3967 secfile_lookup_str_default(loading->file, "",
3968 "player%d.ranked_username",
3969 plrno));
3971 "player%d.unassigned_ranked", plrno),
3972 "%s", secfile_error());
3973 str = secfile_lookup_str_default(loading->file, "",
3974 "player%d.delegation_username",
3975 plrno);
3976 /* Defaults to no delegation. */
3977 if (strlen(str)) {
3979 }
3980
3981 /* Player flags */
3982 BV_CLR_ALL(plr->flags);
3983 slist = secfile_lookup_str_vec(loading->file, &nval, "player%d.flags", plrno);
3984 for (i = 0; i < nval; i++) {
3985 const char *sval = slist[i];
3986 enum plr_flag_id fid = plr_flag_id_by_name(sval, fc_strcasecmp);
3987
3988 sg_failure_ret(plr_flag_id_is_valid(fid), "Invalid player flag \"%s\".", sval);
3989
3990 BV_SET(plr->flags, fid);
3991 }
3992 free(slist);
3993
3994 /* Nation */
3995 str = secfile_lookup_str(loading->file, "player%d.nation", plrno);
3997 if (plr->nation != NULL) {
3998 ai_traits_init(plr);
3999 }
4000
4001 /* Government */
4002 str = secfile_lookup_str(loading->file, "player%d.government_name",
4003 plrno);
4005 sg_failure_ret(gov != NULL, "Player%d: unsupported government \"%s\".",
4006 plrno, str);
4007 plr->government = gov;
4008
4009 /* Target government */
4010 str = secfile_lookup_str(loading->file,
4011 "player%d.target_government_name", plrno);
4012 if (str != NULL) {
4014 } else {
4015 plr->target_government = NULL;
4016 }
4018 = secfile_lookup_int_default(loading->file, -1,
4019 "player%d.revolution_finishes", plrno);
4020
4022 &plr->server.got_first_city,
4023 "player%d.got_first_city", plrno),
4024 "%s", secfile_error());
4025
4026 /* Load diplomatic data (diplstate + embassy + vision).
4027 * Shared vision is loaded in sg_load_players(). */
4029 players_iterate(pplayer) {
4030 char buf[32];
4031 struct player_diplstate *ds = player_diplstate_get(plr, pplayer);
4032 i = player_index(pplayer);
4033
4034 /* load diplomatic status */
4035 fc_snprintf(buf, sizeof(buf), "player%d.diplstate%d", plrno, i);
4036
4037 ds->type =
4038 secfile_lookup_enum_default(loading->file, DS_WAR,
4039 diplstate_type, "%s.current", buf);
4040 ds->max_state =
4041 secfile_lookup_enum_default(loading->file, DS_WAR,
4042 diplstate_type, "%s.closest", buf);
4043 ds->first_contact_turn =
4044 secfile_lookup_int_default(loading->file, 0,
4045 "%s.first_contact_turn", buf);
4046 ds->turns_left =
4047 secfile_lookup_int_default(loading->file, -2, "%s.turns_left", buf);
4049 secfile_lookup_int_default(loading->file, 0,
4050 "%s.has_reason_to_cancel", buf);
4051 ds->contact_turns_left =
4052 secfile_lookup_int_default(loading->file, 0,
4053 "%s.contact_turns_left", buf);
4054
4055 if (secfile_lookup_bool_default(loading->file, FALSE, "%s.embassy",
4056 buf)) {
4057 BV_SET(plr->real_embassy, i);
4058 }
4059 /* 'gives_shared_vision' is loaded in sg_load_players() as all cities
4060 * must be known. */
4062
4063 /* load ai data */
4064 players_iterate(aplayer) {
4065 char buf[32];
4066
4067 fc_snprintf(buf, sizeof(buf), "player%d.ai%d", plrno,
4068 player_index(aplayer));
4069
4070 plr->ai_common.love[player_index(aplayer)] =
4071 secfile_lookup_int_default(loading->file, 1, "%s.love", buf);
4072 CALL_FUNC_EACH_AI(player_load_relations, plr, aplayer, loading->file, plrno);
4074
4076 "player%d.adv.wonder_city",
4077 plrno);
4078
4079 CALL_FUNC_EACH_AI(player_load, plr, loading->file, plrno);
4080
4081 /* Some sane defaults */
4082 plr->ai_common.fuzzy = 0;
4083 plr->ai_common.expand = 100;
4084 plr->ai_common.science_cost = 100;
4085
4086
4087 level = secfile_lookup_str_default(loading->file, NULL,
4088 "player%d.ai.level", plrno);
4089 if (level != NULL && !fc_strcasecmp("Handicapped", level)) {
4090 /* Up to freeciv-3.1 Restricted AI level was known as Handicapped */
4091 plr->ai_common.skill_level = AI_LEVEL_RESTRICTED;
4092 } else {
4093 plr->ai_common.skill_level = ai_level_by_name(level, fc_strcasecmp);
4094 }
4095
4096 if (!ai_level_is_valid(plr->ai_common.skill_level)) {
4097 log_sg("Player%d: Invalid AI level \"%s\". "
4098 "Changed to \"%s\".", plrno, level,
4099 ai_level_name(game.info.skill_level));
4101 }
4102
4103 barb_str = secfile_lookup_str_default(loading->file, "None",
4104 "player%d.ai.barb_type", plrno);
4105 plr->ai_common.barbarian_type = barbarian_type_by_name(barb_str, fc_strcasecmp);
4106
4107 if (!barbarian_type_is_valid(plr->ai_common.barbarian_type)) {
4108 log_sg("Player%d: Invalid barbarian type \"%s\". "
4109 "Changed to \"None\".", plrno, barb_str);
4110 plr->ai_common.barbarian_type = NOT_A_BARBARIAN;
4111 }
4112
4113 if (is_barbarian(plr)) {
4114 server.nbarbarians++;
4115 }
4116
4117 if (is_ai(plr)) {
4119 CALL_PLR_AI_FUNC(gained_control, plr, plr);
4120 }
4121
4122 /* Load nation style. */
4123 {
4124 struct nation_style *style;
4125
4126 str = secfile_lookup_str(loading->file, "player%d.style_by_name", plrno);
4127
4128 sg_failure_ret(str != NULL, "%s", secfile_error());
4129 style = style_by_rule_name(str);
4130 if (style == NULL) {
4131 style = style_by_number(0);
4132 log_sg("Player%d: unsupported city_style_name \"%s\". "
4133 "Changed to \"%s\".", plrno, str, style_rule_name(style));
4134 }
4135 plr->style = style;
4136 }
4137
4139 "player%d.idle_turns", plrno),
4140 "%s", secfile_error());
4141 kind = secfile_lookup_str(loading->file, "player%d.kind", plrno);
4142 if (!strcmp("male", kind)) {
4143 plr->is_male = TRUE;
4144 } else {
4145 plr->is_male = FALSE;
4146 }
4148 "player%d.is_alive", plrno),
4149 "%s", secfile_error());
4151 "player%d.turns_alive", plrno),
4152 "%s", secfile_error());
4154 "player%d.last_war", plrno),
4155 "%s", secfile_error());
4157 "player%d.phase_done", plrno);
4159 "player%d.gold", plrno),
4160 "%s", secfile_error());
4162 "player%d.rates.tax", plrno),
4163 "%s", secfile_error());
4165 "player%d.rates.science", plrno),
4166 "%s", secfile_error());
4168 "player%d.rates.luxury", plrno),
4169 "%s", secfile_error());
4171 "player%d.infrapts",
4172 plrno);
4173 plr->server.bulbs_last_turn =
4174 secfile_lookup_int_default(loading->file, 0,
4175 "player%d.research.bulbs_last_turn", plrno);
4176
4177 /* Traits */
4178 if (plr->nation) {
4179 for (i = 0; i < loading->trait.size; i++) {
4180 enum trait tr = trait_by_name(loading->trait.order[i], fc_strcasecmp);
4181
4182 if (trait_is_valid(tr)) {
4183 int val;
4184
4185 sg_failure_ret(secfile_lookup_int(loading->file, &val, "player%d.trait%d.val",
4186 plrno, i),
4187 "%s", secfile_error());
4188 plr->ai_common.traits[tr].val = val;
4189
4190 sg_failure_ret(secfile_lookup_int(loading->file, &val,
4191 "player%d.trait%d.mod", plrno, i),
4192 "%s", secfile_error());
4193 plr->ai_common.traits[tr].mod = val;
4194 }
4195 }
4196 }
4197
4198 /* Achievements */
4199 {
4200 int count;
4201
4202 count = secfile_lookup_int_default(loading->file, -1,
4203 "player%d.achievement_count", plrno);
4204
4205 if (count > 0) {
4206 for (i = 0; i < count; i++) {
4207 const char *name;
4208 struct achievement *pach;
4209 bool first;
4210
4211 name = secfile_lookup_str(loading->file,
4212 "player%d.achievement%d.name", plrno, i);
4214
4215 sg_failure_ret(pach != NULL,
4216 "Unknown achievement \"%s\".", name);
4217
4219 "player%d.achievement%d.first",
4220 plrno, i),
4221 "achievement error: %s", secfile_error());
4222
4223 sg_failure_ret(pach->first == NULL || !first,
4224 "Multiple players listed as first to get achievement \"%s\".",
4225 name);
4226
4227 BV_SET(pach->achievers, player_index(plr));
4228
4229 if (first) {
4230 pach->first = plr;
4231 }
4232 }
4233 }
4234 }
4235
4236 /* Player score. */
4237 plr->score.happy =
4238 secfile_lookup_int_default(loading->file, 0,
4239 "score%d.happy", plrno);
4240 plr->score.content =
4241 secfile_lookup_int_default(loading->file, 0,
4242 "score%d.content", plrno);
4243 plr->score.unhappy =
4244 secfile_lookup_int_default(loading->file, 0,
4245 "score%d.unhappy", plrno);
4246 plr->score.angry =
4247 secfile_lookup_int_default(loading->file, 0,
4248 "score%d.angry", plrno);
4249
4250 /* Make sure that the score about specialists in current ruleset that
4251 * were not present at saving time are set to zero. */
4253 plr->score.specialists[sp] = 0;
4255
4256 for (i = 0; i < loading->specialist.size; i++) {
4258 = secfile_lookup_int_default(loading->file, 0,
4259 "score%d.specialists%d", plrno, i);
4260 }
4261
4262 plr->score.wonders =
4263 secfile_lookup_int_default(loading->file, 0,
4264 "score%d.wonders", plrno);
4265 plr->score.techs =
4266 secfile_lookup_int_default(loading->file, 0,
4267 "score%d.techs", plrno);
4268 plr->score.techout =
4269 secfile_lookup_int_default(loading->file, 0,
4270 "score%d.techout", plrno);
4271 plr->score.landarea =
4272 secfile_lookup_int_default(loading->file, 0,
4273 "score%d.landarea", plrno);
4274 plr->score.settledarea =
4275 secfile_lookup_int_default(loading->file, 0,
4276 "score%d.settledarea", plrno);
4277 plr->score.population =
4278 secfile_lookup_int_default(loading->file, 0,
4279 "score%d.population", plrno);
4280 plr->score.cities =
4281 secfile_lookup_int_default(loading->file, 0,
4282 "score%d.cities", plrno);
4283 plr->score.units =
4284 secfile_lookup_int_default(loading->file, 0,
4285 "score%d.units", plrno);
4286 plr->score.pollution =
4287 secfile_lookup_int_default(loading->file, 0,
4288 "score%d.pollution", plrno);
4289 plr->score.literacy =
4290 secfile_lookup_int_default(loading->file, 0,
4291 "score%d.literacy", plrno);
4292 plr->score.bnp =
4293 secfile_lookup_int_default(loading->file, 0,
4294 "score%d.bnp", plrno);
4295 plr->score.mfg =
4296 secfile_lookup_int_default(loading->file, 0,
4297 "score%d.mfg", plrno);
4298 plr->score.spaceship =
4299 secfile_lookup_int_default(loading->file, 0,
4300 "score%d.spaceship", plrno);
4301 plr->score.units_built =
4302 secfile_lookup_int_default(loading->file, 0,
4303 "score%d.units_built", plrno);
4304 plr->score.units_killed =
4305 secfile_lookup_int_default(loading->file, 0,
4306 "score%d.units_killed", plrno);
4307 plr->score.units_lost =
4308 secfile_lookup_int_default(loading->file, 0,
4309 "score%d.units_lost", plrno);
4310 plr->score.culture =
4311 secfile_lookup_int_default(loading->file, 0,
4312 "score%d.culture", plrno);
4313 plr->score.game =
4314 secfile_lookup_int_default(loading->file, 0,
4315 "score%d.total", plrno);
4316
4317 /* Load space ship data. */
4318 {
4319 struct player_spaceship *ship = &plr->spaceship;
4320 char prefix[32];
4321 const char *st;
4322 int ei;
4323
4324 fc_snprintf(prefix, sizeof(prefix), "player%d.spaceship", plrno);
4325 spaceship_init(ship);
4327 &ei,
4328 "%s.state", prefix),
4329 "%s", secfile_error());
4330 ship->state = ei;
4331
4332 if (ship->state != SSHIP_NONE) {
4334 "%s.structurals", prefix),
4335 "%s", secfile_error());
4337 "%s.components", prefix),
4338 "%s", secfile_error());
4340 "%s.modules", prefix),
4341 "%s", secfile_error());
4342 sg_failure_ret(secfile_lookup_int(loading->file, &ship->fuel,
4343 "%s.fuel", prefix),
4344 "%s", secfile_error());
4346 "%s.propulsion", prefix),
4347 "%s", secfile_error());
4349 "%s.habitation", prefix),
4350 "%s", secfile_error());
4352 "%s.life_support", prefix),
4353 "%s", secfile_error());
4355 "%s.solar_panels", prefix),
4356 "%s", secfile_error());
4357
4358 st = secfile_lookup_str(loading->file, "%s.structure", prefix);
4359 sg_failure_ret(st != NULL, "%s", secfile_error())
4360 for (i = 0; i < NUM_SS_STRUCTURALS && st[i]; i++) {
4361 sg_failure_ret(st[i] == '1' || st[i] == '0',
4362 "Undefined value '%c' within '%s.structure'.", st[i],
4363 prefix)
4364
4365 if (!(st[i] == '0')) {
4366 BV_SET(ship->structure, i);
4367 }
4368 }
4369 if (ship->state >= SSHIP_LAUNCHED) {
4371 "%s.launch_year", prefix),
4372 "%s", secfile_error());
4373 }
4375 }
4376 }
4377
4378 /* Load lost wonder data. */
4379 str = secfile_lookup_str(loading->file, "player%d.lost_wonders", plrno);
4380 /* If not present, probably an old savegame; nothing to be done */
4381 if (str != NULL) {
4382 int k;
4383
4384 sg_failure_ret(strlen(str) == loading->improvement.size,
4385 "Invalid length for 'player%d.lost_wonders' ("
4386 SIZE_T_PRINTF " ~= " SIZE_T_PRINTF ")",
4387 plrno, strlen(str), loading->improvement.size);
4388 for (k = 0; k < loading->improvement.size; k++) {
4389 sg_failure_ret(str[k] == '1' || str[k] == '0',
4390 "Undefined value '%c' within "
4391 "'player%d.lost_wonders'.", plrno, str[k]);
4392
4393 if (str[k] == '1') {
4394 struct impr_type *pimprove =
4396 if (pimprove) {
4397 plr->wonders[improvement_index(pimprove)] = WONDER_LOST;
4398 }
4399 }
4400 }
4401 }
4402
4403 plr->history =
4404 secfile_lookup_int_default(loading->file, 0, "player%d.history", plrno);
4405 plr->server.huts =
4406 secfile_lookup_int_default(loading->file, 0, "player%d.hut_count", plrno);
4407}
4408
4409/************************************************************************/
4412static void sg_save_player_main(struct savedata *saving,
4413 struct player *plr)
4414{
4415 int i, k, plrno = player_number(plr);
4416 struct player_spaceship *ship = &plr->spaceship;
4417 const char *flag_names[PLRF_COUNT];
4418 int set_count;
4419
4420 /* Check status and return if not OK (sg_success FALSE). */
4421 sg_check_ret();
4422
4423 set_count = 0;
4424 for (i = 0; i < PLRF_COUNT; i++) {
4425 if (player_has_flag(plr, i)) {
4426 flag_names[set_count++] = plr_flag_id_name(i);
4427 }
4428 }
4429
4430 secfile_insert_str_vec(saving->file, flag_names, set_count,
4431 "player%d.flags", plrno);
4432
4433 secfile_insert_str(saving->file, ai_name(plr->ai),
4434 "player%d.ai_type", plrno);
4435 secfile_insert_str(saving->file, player_name(plr),
4436 "player%d.name", plrno);
4437 secfile_insert_str(saving->file, plr->username,
4438 "player%d.username", plrno);
4440 "player%d.unassigned_user", plrno);
4441 if (plr->rgb != NULL) {
4442 rgbcolor_save(saving->file, plr->rgb, "player%d.color", plrno);
4443 } else {
4444 /* Colorless players are ok in pregame */
4445 if (game_was_started()) {
4446 log_sg("Game has started, yet player %d has no color defined.", plrno);
4447 }
4448 }
4450 "player%d.ranked_username", plrno);
4452 "player%d.unassigned_ranked", plrno);
4454 "player%d.orig_username", plrno);
4455 secfile_insert_str(saving->file,
4457 : "",
4458 "player%d.delegation_username", plrno);
4460 "player%d.nation", plrno);
4461 secfile_insert_int(saving->file, plr->team ? team_index(plr->team) : -1,
4462 "player%d.team_no", plrno);
4463
4464 secfile_insert_str(saving->file,
4466 "player%d.government_name", plrno);
4467
4468 if (plr->target_government) {
4469 secfile_insert_str(saving->file,
4471 "player%d.target_government_name", plrno);
4472 }
4473
4475 "player%d.style_by_name", plrno);
4476
4477 secfile_insert_int(saving->file, plr->nturns_idle,
4478 "player%d.idle_turns", plrno);
4479 if (plr->is_male) {
4480 secfile_insert_str(saving->file, "male",
4481 "player%d.kind", plrno);
4482 } else {
4483 secfile_insert_str(saving->file, "female",
4484 "player%d.kind", plrno);
4485 }
4486 secfile_insert_bool(saving->file, plr->is_alive,
4487 "player%d.is_alive", plrno);
4488 secfile_insert_int(saving->file, plr->turns_alive,
4489 "player%d.turns_alive", plrno);
4491 "player%d.last_war", plrno);
4492 secfile_insert_bool(saving->file, plr->phase_done,
4493 "player%d.phase_done", plrno);
4494
4495 players_iterate(pplayer) {
4496 char buf[32];
4497 struct player_diplstate *ds = player_diplstate_get(plr, pplayer);
4498
4499 i = player_index(pplayer);
4500
4501 /* save diplomatic state */
4502 fc_snprintf(buf, sizeof(buf), "player%d.diplstate%d", plrno, i);
4503
4504 secfile_insert_enum(saving->file, ds->type,
4505 diplstate_type, "%s.current", buf);
4506 secfile_insert_enum(saving->file, ds->max_state,
4507 diplstate_type, "%s.closest", buf);
4509 "%s.first_contact_turn", buf);
4510 secfile_insert_int(saving->file, ds->turns_left,
4511 "%s.turns_left", buf);
4513 "%s.has_reason_to_cancel", buf);
4515 "%s.contact_turns_left", buf);
4516 secfile_insert_bool(saving->file, player_has_real_embassy(plr, pplayer),
4517 "%s.embassy", buf);
4518 secfile_insert_bool(saving->file, gives_shared_vision(plr, pplayer),
4519 "%s.gives_shared_vision", buf);
4521
4522 players_iterate(aplayer) {
4523 i = player_index(aplayer);
4524 /* save ai data */
4525 secfile_insert_int(saving->file, plr->ai_common.love[i],
4526 "player%d.ai%d.love", plrno, i);
4527 CALL_FUNC_EACH_AI(player_save_relations, plr, aplayer, saving->file, plrno);
4529
4531 "player%d.adv.wonder_city", plrno);
4532
4533 CALL_FUNC_EACH_AI(player_save, plr, saving->file, plrno);
4534
4535 /* Multipliers (policies) */
4536 i = multiplier_count();
4537
4538 for (k = 0; k < i; k++) {
4539 secfile_insert_int(saving->file, plr->multipliers[k].value,
4540 "player%d.multiplier%d.val", plrno, k);
4541 secfile_insert_int(saving->file, plr->multipliers[k].target,
4542 "player%d.multiplier%d.target", plrno, k);
4543 secfile_insert_int(saving->file, plr->multipliers[k].changed,
4544 "player%d.multiplier%d.changed", plrno, k);
4545 }
4546
4547 secfile_insert_str(saving->file, ai_level_name(plr->ai_common.skill_level),
4548 "player%d.ai.level", plrno);
4549 secfile_insert_str(saving->file, barbarian_type_name(plr->ai_common.barbarian_type),
4550 "player%d.ai.barb_type", plrno);
4551 secfile_insert_int(saving->file, plr->economic.gold,
4552 "player%d.gold", plrno);
4553 secfile_insert_int(saving->file, plr->economic.tax,
4554 "player%d.rates.tax", plrno);
4556 "player%d.rates.science", plrno);
4557 secfile_insert_int(saving->file, plr->economic.luxury,
4558 "player%d.rates.luxury", plrno);
4560 "player%d.infrapts", plrno);
4562 "player%d.research.bulbs_last_turn", plrno);
4563
4564 /* Save traits */
4565 {
4566 enum trait tr;
4567 int j;
4568
4569 for (tr = trait_begin(), j = 0; tr != trait_end(); tr = trait_next(tr), j++) {
4570 secfile_insert_int(saving->file, plr->ai_common.traits[tr].val,
4571 "player%d.trait%d.val", plrno, j);
4572 secfile_insert_int(saving->file, plr->ai_common.traits[tr].mod,
4573 "player%d.trait%d.mod", plrno, j);
4574 }
4575 }
4576
4577 /* Save achievements */
4578 {
4579 int j = 0;
4580
4581 achievements_iterate(pach) {
4582 if (achievement_player_has(pach, plr)) {
4584 "player%d.achievement%d.name", plrno, j);
4585 if (pach->first == plr) {
4586 secfile_insert_bool(saving->file, TRUE,
4587 "player%d.achievement%d.first", plrno, j);
4588 } else {
4590 "player%d.achievement%d.first", plrno, j);
4591 }
4592
4593 j++;
4594 }
4596
4597 secfile_insert_int(saving->file, j,
4598 "player%d.achievement_count", plrno);
4599 }
4600
4602 "player%d.got_first_city", plrno);
4604 "player%d.revolution_finishes", plrno);
4605
4606 /* Player score */
4607 secfile_insert_int(saving->file, plr->score.happy,
4608 "score%d.happy", plrno);
4609 secfile_insert_int(saving->file, plr->score.content,
4610 "score%d.content", plrno);
4611 secfile_insert_int(saving->file, plr->score.unhappy,
4612 "score%d.unhappy", plrno);
4613 secfile_insert_int(saving->file, plr->score.angry,
4614 "score%d.angry", plrno);
4616 secfile_insert_int(saving->file, plr->score.specialists[sp],
4617 "score%d.specialists%d", plrno, sp);
4619 secfile_insert_int(saving->file, plr->score.wonders,
4620 "score%d.wonders", plrno);
4621 secfile_insert_int(saving->file, plr->score.techs,
4622 "score%d.techs", plrno);
4623 secfile_insert_int(saving->file, plr->score.techout,
4624 "score%d.techout", plrno);
4625 secfile_insert_int(saving->file, plr->score.landarea,
4626 "score%d.landarea", plrno);
4628 "score%d.settledarea", plrno);
4630 "score%d.population", plrno);
4631 secfile_insert_int(saving->file, plr->score.cities,
4632 "score%d.cities", plrno);
4633 secfile_insert_int(saving->file, plr->score.units,
4634 "score%d.units", plrno);
4635 secfile_insert_int(saving->file, plr->score.pollution,
4636 "score%d.pollution", plrno);
4637 secfile_insert_int(saving->file, plr->score.literacy,
4638 "score%d.literacy", plrno);
4639 secfile_insert_int(saving->file, plr->score.bnp,
4640 "score%d.bnp", plrno);
4641 secfile_insert_int(saving->file, plr->score.mfg,
4642 "score%d.mfg", plrno);
4643 secfile_insert_int(saving->file, plr->score.spaceship,
4644 "score%d.spaceship", plrno);
4646 "score%d.units_built", plrno);
4648 "score%d.units_killed", plrno);
4650 "score%d.units_lost", plrno);
4651 secfile_insert_int(saving->file, plr->score.culture,
4652 "score%d.culture", plrno);
4653 secfile_insert_int(saving->file, plr->score.game,
4654 "score%d.total", plrno);
4655
4656 /* Save space ship status. */
4657 secfile_insert_int(saving->file, ship->state, "player%d.spaceship.state",
4658 plrno);
4659 if (ship->state != SSHIP_NONE) {
4660 char buf[32];
4661 char st[NUM_SS_STRUCTURALS+1];
4662 int ssi;
4663
4664 fc_snprintf(buf, sizeof(buf), "player%d.spaceship", plrno);
4665
4666 secfile_insert_int(saving->file, ship->structurals,
4667 "%s.structurals", buf);
4668 secfile_insert_int(saving->file, ship->components,
4669 "%s.components", buf);
4670 secfile_insert_int(saving->file, ship->modules,
4671 "%s.modules", buf);
4672 secfile_insert_int(saving->file, ship->fuel, "%s.fuel", buf);
4673 secfile_insert_int(saving->file, ship->propulsion, "%s.propulsion", buf);
4674 secfile_insert_int(saving->file, ship->habitation, "%s.habitation", buf);
4675 secfile_insert_int(saving->file, ship->life_support,
4676 "%s.life_support", buf);
4677 secfile_insert_int(saving->file, ship->solar_panels,
4678 "%s.solar_panels", buf);
4679
4680 for (ssi = 0; ssi < NUM_SS_STRUCTURALS; ssi++) {
4681 st[ssi] = BV_ISSET(ship->structure, ssi) ? '1' : '0';
4682 }
4683 st[ssi] = '\0';
4684 secfile_insert_str(saving->file, st, "%s.structure", buf);
4685 if (ship->state >= SSHIP_LAUNCHED) {
4686 secfile_insert_int(saving->file, ship->launch_year,
4687 "%s.launch_year", buf);
4688 }
4689 }
4690
4691 /* Save lost wonders info. */
4692 {
4693 char lost[B_LAST+1];
4694
4695 improvement_iterate(pimprove) {
4696 if (is_wonder(pimprove) && wonder_is_lost(plr, pimprove)) {
4697 lost[improvement_index(pimprove)] = '1';
4698 } else {
4699 lost[improvement_index(pimprove)] = '0';
4700 }
4702 lost[improvement_count()] = '\0';
4703 secfile_insert_str(saving->file, lost,
4704 "player%d.lost_wonders", plrno);
4705 }
4706
4707 secfile_insert_int(saving->file, plr->history,
4708 "player%d.history", plrno);
4709 secfile_insert_int(saving->file, plr->server.huts,
4710 "player%d.hut_count", plrno);
4711
4713 "player%d.border_vision", plrno);
4714}
4715
4716/************************************************************************/
4719static void sg_load_player_cities(struct loaddata *loading,
4720 struct player *plr)
4721{
4722 int ncities, i, plrno = player_number(plr);
4723 bool tasks_handled;
4724 int wlist_max_length = 0;
4725
4726 /* Check status and return if not OK (sg_success FALSE). */
4727 sg_check_ret();
4728
4729 sg_failure_ret(secfile_lookup_int(loading->file, &ncities,
4730 "player%d.ncities", plrno),
4731 "%s", secfile_error());
4732
4733 if (!plr->is_alive && ncities > 0) {
4734 log_sg("'player%d.ncities' = %d for dead player!", plrno, ncities);
4735 ncities = 0;
4736 }
4737
4738 if (!plr->server.got_first_city && ncities > 0) {
4739 /* Probably barbarians in an old savegame; fix up */
4740 plr->server.got_first_city = TRUE;
4741 }
4742
4743 /* Find longest worklist */
4744 for (i = 0; i < ncities; i++) {
4745 int wl_length = secfile_lookup_int_default(loading->file, 0,
4746 "player%d.c%d.wl_length",
4747 plrno, i);
4748
4749 wlist_max_length = MAX(wlist_max_length, wl_length);
4750 }
4751
4752 /* Load all cities of the player. */
4753 for (i = 0; i < ncities; i++) {
4754 char buf[32];
4755 struct city *pcity;
4756
4757 fc_snprintf(buf, sizeof(buf), "player%d.c%d", plrno, i);
4758
4759 /* Create a dummy city. */
4760 pcity = create_city_virtual(plr, NULL, buf);
4761 adv_city_alloc(pcity);
4762 if (!sg_load_player_city(loading, plr, pcity, buf, wlist_max_length)) {
4763 adv_city_free(pcity);
4764 destroy_city_virtual(pcity);
4765 sg_failure_ret(FALSE, "Error loading city %d of player %d.", i, plrno);
4766 }
4767
4769 idex_register_city(&wld, pcity);
4770
4771 /* Load the information about the nationality of citizens. This is done
4772 * here because the city sanity check called by citizens_update() requires
4773 * that the city is registered. */
4774 sg_load_player_city_citizens(loading, plr, pcity, buf);
4775
4776 /* After everything is loaded, but before vision. */
4777 map_claim_ownership(city_tile(pcity), plr, city_tile(pcity), TRUE);
4778
4779 /* adding the city contribution to fog-of-war */
4780 pcity->server.vision = vision_new(plr, city_tile(pcity));
4782 city_refresh_vision(pcity);
4783
4784 city_list_append(plr->cities, pcity);
4785 }
4786
4787 tasks_handled = FALSE;
4788 for (i = 0; !tasks_handled; i++) {
4789 int city_id;
4790 struct city *pcity = NULL;
4791
4792 city_id = secfile_lookup_int_default(loading->file, -1, "player%d.task%d.city",
4793 plrno, i);
4794
4795 if (city_id != -1) {
4796 pcity = player_city_by_number(plr, city_id);
4797 }
4798
4799 if (pcity != NULL) {
4800 const char *str;
4801 int nat_x, nat_y;
4802 struct worker_task *ptask = fc_malloc(sizeof(struct worker_task));
4803
4804 nat_x = secfile_lookup_int_default(loading->file, -1, "player%d.task%d.x", plrno, i);
4805 nat_y = secfile_lookup_int_default(loading->file, -1, "player%d.task%d.y", plrno, i);
4806
4807 ptask->ptile = native_pos_to_tile(&(wld.map), nat_x, nat_y);
4808
4809 str = secfile_lookup_str(loading->file, "player%d.task%d.activity", plrno, i);
4810 ptask->act = unit_activity_by_name(str, fc_strcasecmp);
4811
4812 sg_failure_ret(unit_activity_is_valid(ptask->act),
4813 "Unknown workertask activity %s", str);
4814
4815 str = secfile_lookup_str(loading->file, "player%d.task%d.target", plrno, i);
4816
4817 if (strcmp("-", str)) {
4819
4820 sg_failure_ret(ptask->tgt != NULL,
4821 "Unknown workertask target %s", str);
4822 } else {
4823 ptask->tgt = NULL;
4824
4825 if (ptask->act == ACTIVITY_IRRIGATE) {
4826 ptask->act = ACTIVITY_CULTIVATE;
4827 } else if (ptask->act == ACTIVITY_MINE) {
4828 ptask->act = ACTIVITY_MINE;
4829 }
4830 }
4831
4832 ptask->want = secfile_lookup_int_default(loading->file, 1,
4833 "player%d.task%d.want", plrno, i);
4834
4835 worker_task_list_append(pcity->task_reqs, ptask);
4836 } else {
4837 tasks_handled = TRUE;
4838 }
4839 }
4840}
4841
4842/************************************************************************/
4845static bool sg_load_player_city(struct loaddata *loading, struct player *plr,
4846 struct city *pcity, const char *citystr,
4847 int wlist_max_length)
4848{
4849 struct player *past;
4850 const char *kind, *name, *str;
4851 int id, i, repair, sp_count = 0, workers = 0, value;
4852 int nat_x, nat_y;
4853 citizens size;
4854 const char *stylename;
4855 int partner;
4856 int want;
4857 const struct civ_map *nmap = &(wld.map);
4858
4859 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_x, "%s.x", citystr),
4860 FALSE, "%s", secfile_error());
4861 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_y, "%s.y", citystr),
4862 FALSE, "%s", secfile_error());
4863 pcity->tile = native_pos_to_tile(&(wld.map), nat_x, nat_y);
4864 sg_warn_ret_val(NULL != pcity->tile, FALSE,
4865 "%s has invalid center tile (%d, %d)",
4866 citystr, nat_x, nat_y);
4867 sg_warn_ret_val(NULL == tile_city(pcity->tile), FALSE,
4868 "%s duplicates city (%d, %d)", citystr, nat_x, nat_y);
4869
4870 /* Instead of dying, use 'citystr' string for damaged name. */
4871 city_name_set(pcity, secfile_lookup_str_default(loading->file, citystr,
4872 "%s.name", citystr));
4873
4874 sg_warn_ret_val(secfile_lookup_int(loading->file, &pcity->id, "%s.id",
4875 citystr), FALSE, "%s", secfile_error());
4876
4877 id = secfile_lookup_int_default(loading->file, player_number(plr),
4878 "%s.original", citystr);
4879 past = player_by_number(id);
4880 if (NULL != past) {
4881 pcity->original = past;
4882 }
4883
4884 sg_warn_ret_val(secfile_lookup_int(loading->file, &value, "%s.size",
4885 citystr), FALSE, "%s", secfile_error());
4886 size = (citizens)value; /* set the correct type */
4887 sg_warn_ret_val(value == (int)size, FALSE,
4888 "Invalid city size: %d, set to %d", value, size);
4889 city_size_set(pcity, size);
4890
4891 for (i = 0; i < loading->specialist.size; i++) {
4892 sg_warn_ret_val(secfile_lookup_int(loading->file, &value, "%s.nspe%d",
4893 citystr, i),
4894 FALSE, "%s", secfile_error());
4895 pcity->specialists[specialist_index(loading->specialist.order[i])]
4896 = (citizens)value;
4897 sp_count += value;
4898 }
4899
4900 partner = secfile_lookup_int_default(loading->file, 0, "%s.traderoute0", citystr);
4901 for (i = 0; partner != 0; i++) {
4902 struct trade_route *proute = fc_malloc(sizeof(struct trade_route));
4903 const char *dir;
4904 const char *good_str;
4905
4906 /* Append to routes list immediately, so the pointer can be found for freeing
4907 * even if we abort */
4908 trade_route_list_append(pcity->routes, proute);
4909
4910 proute->partner = partner;
4911 dir = secfile_lookup_str(loading->file, "%s.route_direction%d", citystr, i);
4912 sg_warn_ret_val(dir != NULL, FALSE,
4913 "No traderoute direction found for %s", citystr);
4914 proute->dir = route_direction_by_name(dir, fc_strcasecmp);
4915 sg_warn_ret_val(route_direction_is_valid(proute->dir), FALSE,
4916 "Illegal route direction %s", dir);
4917 good_str = secfile_lookup_str(loading->file, "%s.route_good%d", citystr, i);
4918 sg_warn_ret_val(dir != NULL, FALSE,
4919 "No good found for %s", citystr);
4920 proute->goods = goods_by_rule_name(good_str);
4921 sg_warn_ret_val(proute->goods != NULL, FALSE,
4922 "Illegal good %s", good_str);
4923
4924 /* Next one */
4926 "%s.traderoute%d", citystr, i + 1);
4927 }
4928
4929 for (; i < MAX_TRADE_ROUTES; i++) {
4930 (void) secfile_entry_lookup(loading->file, "%s.traderoute%d", citystr, i);
4931 (void) secfile_entry_lookup(loading->file, "%s.route_direction%d", citystr, i);
4932 (void) secfile_entry_lookup(loading->file, "%s.route_good%d", citystr, i);
4933 }
4934
4936 "%s.food_stock", citystr),
4937 FALSE, "%s", secfile_error());
4939 "%s.shield_stock", citystr),
4940 FALSE, "%s", secfile_error());
4941 pcity->history =
4942 secfile_lookup_int_default(loading->file, 0, "%s.history", citystr);
4943
4944 pcity->airlift =
4945 secfile_lookup_int_default(loading->file, 0, "%s.airlift", citystr);
4946 pcity->was_happy =
4947 secfile_lookup_bool_default(loading->file, FALSE, "%s.was_happy",
4948 citystr);
4949
4950 pcity->turn_plague =
4951 secfile_lookup_int_default(loading->file, 0, "%s.turn_plague", citystr);
4952
4954 "%s.anarchy", citystr),
4955 FALSE, "%s", secfile_error());
4956 pcity->rapture =
4957 secfile_lookup_int_default(loading->file, 0, "%s.rapture", citystr);
4958 pcity->steal =
4959 secfile_lookup_int_default(loading->file, 0, "%s.steal", citystr);
4960
4962 "%s.turn_founded", citystr),
4963 FALSE, "%s", secfile_error());
4964 sg_warn_ret_val(secfile_lookup_bool(loading->file, &pcity->did_buy, "%s.did_buy",
4965 citystr), FALSE, "%s", secfile_error());
4966 sg_warn_ret_val(secfile_lookup_bool(loading->file, &pcity->did_sell, "%s.did_sell",
4967 citystr), FALSE, "%s", secfile_error());
4968
4970 "%s.turn_last_built", citystr),
4971 FALSE, "%s", secfile_error());
4972
4973 kind = secfile_lookup_str(loading->file, "%s.currently_building_kind",
4974 citystr);
4975 name = secfile_lookup_str(loading->file, "%s.currently_building_name",
4976 citystr);
4977 pcity->production = universal_by_rule_name(kind, name);
4978 sg_warn_ret_val(pcity->production.kind != universals_n_invalid(), FALSE,
4979 "%s.currently_building: unknown \"%s\" \"%s\".",
4980 citystr, kind, name);
4981
4982 want = secfile_lookup_int_default(loading->file, 0,
4983 "%s.current_want", citystr);
4984 if (pcity->production.kind == VUT_IMPROVEMENT) {
4985 pcity->server.adv->
4986 building_want[improvement_index(pcity->production.value.building)]
4987 = want;
4988 }
4989
4990 kind = secfile_lookup_str(loading->file, "%s.changed_from_kind",
4991 citystr);
4992 name = secfile_lookup_str(loading->file, "%s.changed_from_name",
4993 citystr);
4995 sg_warn_ret_val(pcity->changed_from.kind != universals_n_invalid(), FALSE,
4996 "%s.changed_from: unknown \"%s\" \"%s\".",
4997 citystr, kind, name);
4998
4999 pcity->before_change_shields =
5001 "%s.before_change_shields", citystr);
5002 pcity->caravan_shields =
5003 secfile_lookup_int_default(loading->file, 0,
5004 "%s.caravan_shields", citystr);
5005 pcity->disbanded_shields =
5006 secfile_lookup_int_default(loading->file, 0,
5007 "%s.disbanded_shields", citystr);
5009 secfile_lookup_int_default(loading->file, 0,
5010 "%s.last_turns_shield_surplus",
5011 citystr);
5012
5013 stylename = secfile_lookup_str_default(loading->file, NULL,
5014 "%s.style", citystr);
5015 if (stylename != NULL) {
5016 pcity->style = city_style_by_rule_name(stylename);
5017 } else {
5018 pcity->style = 0;
5019 }
5020 if (pcity->style < 0) {
5021 pcity->style = city_style(pcity);
5022 }
5023
5024 pcity->server.synced = FALSE; /* must re-sync with clients */
5025
5026 /* Initialise list of city improvements. */
5027 for (i = 0; i < ARRAY_SIZE(pcity->built); i++) {
5028 pcity->built[i].turn = I_NEVER;
5029 }
5030
5031 /* Load city improvements. */
5032 str = secfile_lookup_str(loading->file, "%s.improvements", citystr);
5033 sg_warn_ret_val(str != NULL, FALSE, "%s", secfile_error());
5034 sg_warn_ret_val(strlen(str) == loading->improvement.size, FALSE,
5035 "Invalid length of '%s.improvements' ("
5036 SIZE_T_PRINTF " ~= " SIZE_T_PRINTF ").",
5037 citystr, strlen(str), loading->improvement.size);
5038 for (i = 0; i < loading->improvement.size; i++) {
5039 sg_warn_ret_val(str[i] == '1' || str[i] == '0', FALSE,
5040 "Undefined value '%c' within '%s.improvements'.",
5041 str[i], citystr)
5042
5043 if (str[i] == '1') {
5044 struct impr_type *pimprove =
5046
5047 if (pimprove) {
5048 city_add_improvement(pcity, pimprove);
5049 }
5050 }
5051 }
5052
5053 sg_failure_ret_val(loading->worked_tiles != NULL, FALSE,
5054 "No worked tiles map defined.");
5055
5056 city_freeze_workers(pcity);
5057
5058 /* Load new savegame with variable (squared) city radius and worked
5059 * tiles map */
5060
5061 int radius_sq
5062 = secfile_lookup_int_default(loading->file, -1, "%s.city_radius_sq",
5063 citystr);
5064 city_map_radius_sq_set(pcity, radius_sq);
5065
5066 city_tile_iterate(nmap, CITY_MAP_MAX_RADIUS_SQ, city_tile(pcity), ptile) {
5067 if (loading->worked_tiles[ptile->index] == pcity->id) {
5068 if (sq_map_distance(ptile, pcity->tile) > radius_sq) {
5069 log_sg("[%s] '%s' (%d, %d) has worker outside current radius "
5070 "at (%d, %d); repairing", citystr, city_name_get(pcity),
5071 TILE_XY(pcity->tile), TILE_XY(ptile));
5073 sp_count++;
5074 } else {
5075 tile_set_worked(ptile, pcity);
5076 workers++;
5077 }
5078
5079#ifdef FREECIV_DEBUG
5080 /* Set this tile to unused; a check for not resetted tiles is
5081 * included in game_load_internal() */
5082 loading->worked_tiles[ptile->index] = -1;
5083#endif /* FREECIV_DEBUG */
5084 }
5086
5087 if (tile_worked(city_tile(pcity)) != pcity) {
5088 struct city *pwork = tile_worked(city_tile(pcity));
5089
5090 if (NULL != pwork) {
5091 log_sg("[%s] city center of '%s' (%d,%d) [%d] is worked by '%s' "
5092 "(%d,%d) [%d]; repairing", citystr, city_name_get(pcity),
5093 TILE_XY(city_tile(pcity)), city_size_get(pcity), city_name_get(pwork),
5094 TILE_XY(city_tile(pwork)), city_size_get(pwork));
5095
5096 tile_set_worked(city_tile(pcity), NULL); /* Remove tile from pwork */
5098 auto_arrange_workers(pwork);
5099 } else {
5100 log_sg("[%s] city center of '%s' (%d,%d) [%d] is empty; repairing",
5101 citystr, city_name_get(pcity), TILE_XY(city_tile(pcity)),
5102 city_size_get(pcity));
5103 }
5104
5105 /* Repair pcity */
5106 tile_set_worked(city_tile(pcity), pcity);
5107 city_repair_size(pcity, -1);
5108 }
5109
5110 repair = city_size_get(pcity) - sp_count - (workers - FREE_WORKED_TILES);
5111 if (0 != repair) {
5112 log_sg("[%s] size mismatch for '%s' (%d,%d): size [%d] != "
5113 "(workers [%d] - free worked tiles [%d]) + specialists [%d]",
5114 citystr, city_name_get(pcity), TILE_XY(city_tile(pcity)), city_size_get(pcity),
5115 workers, FREE_WORKED_TILES, sp_count);
5116
5117 /* Repair pcity */
5118 city_repair_size(pcity, repair);
5119 }
5120
5121 /* worklist_init() done in create_city_virtual() */
5122 worklist_load(loading->file, wlist_max_length, &pcity->worklist, "%s", citystr);
5123
5124 /* Load city options. */
5125 BV_CLR_ALL(pcity->city_options);
5126 for (i = 0; i < CITYO_LAST; i++) {
5127 if (secfile_lookup_bool_default(loading->file, FALSE, "%s.option%d",
5128 citystr, i)) {
5129 BV_SET(pcity->city_options, i);
5130 }
5131 }
5132
5133 /* Load the city rally point. */
5134 {
5135 int len = secfile_lookup_int_default(loading->file, 0,
5136 "%s.rally_point_length", citystr);
5137 int unconverted;
5138
5139 pcity->rally_point.length = len;
5140 if (len > 0) {
5141 const char *rally_orders, *rally_dirs, *rally_activities;
5142
5143 pcity->rally_point.orders
5144 = fc_malloc(len * sizeof(*(pcity->rally_point.orders)));
5145 pcity->rally_point.persistent
5147 "%s.rally_point_persistent", citystr);
5148 pcity->rally_point.vigilant
5150 "%s.rally_point_vigilant", citystr);
5151
5152 rally_orders
5153 = secfile_lookup_str_default(loading->file, "",
5154 "%s.rally_point_orders", citystr);
5155 rally_dirs
5156 = secfile_lookup_str_default(loading->file, "",
5157 "%s.rally_point_dirs", citystr);
5158 rally_activities
5159 = secfile_lookup_str_default(loading->file, "",
5160 "%s.rally_point_activities", citystr);
5161
5162 for (i = 0; i < len; i++) {
5163 struct unit_order *order = &pcity->rally_point.orders[i];
5164
5165 if (rally_orders[i] == '\0' || rally_dirs[i] == '\0'
5166 || rally_activities[i] == '\0') {
5167 log_sg("Invalid rally point.");
5168 free(pcity->rally_point.orders);
5169 pcity->rally_point.orders = NULL;
5170 pcity->rally_point.length = 0;
5171 break;
5172 }
5173 order->order = char2order(rally_orders[i]);
5174 order->dir = char2dir(rally_dirs[i]);
5175 order->activity = char2activity(rally_activities[i]);
5176
5177 unconverted = secfile_lookup_int_default(loading->file, ACTION_NONE,
5178 "%s.rally_point_action_vec,%d",
5179 citystr, i);
5180
5181 if (unconverted >= 0 && unconverted < loading->action.size) {
5182 /* Look up what action id the unconverted number represents. */
5183 order->action = loading->action.order[unconverted];
5184 } else {
5185 if (order->order == ORDER_PERFORM_ACTION) {
5186 log_sg("Invalid action id in order for city rally point %d",
5187 pcity->id);
5188 }
5189
5190 order->action = ACTION_NONE;
5191 }
5192
5193 order->target
5195 "%s.rally_point_tgt_vec,%d",
5196 citystr, i);
5197 order->sub_target
5198 = secfile_lookup_int_default(loading->file, -1,
5199 "%s.rally_point_sub_tgt_vec,%d",
5200 citystr, i);
5201 }
5202 } else {
5203 pcity->rally_point.orders = NULL;
5204
5205 (void) secfile_entry_lookup(loading->file, "%s.rally_point_persistent",
5206 citystr);
5207 (void) secfile_entry_lookup(loading->file, "%s.rally_point_vigilant",
5208 citystr);
5209 (void) secfile_entry_lookup(loading->file, "%s.rally_point_orders",
5210 citystr);
5211 (void) secfile_entry_lookup(loading->file, "%s.rally_point_dirs",
5212 citystr);
5213 (void) secfile_entry_lookup(loading->file, "%s.rally_point_activities",
5214 citystr);
5215 (void) secfile_entry_lookup(loading->file, "%s.rally_point_action_vec",
5216 citystr);
5217 (void) secfile_entry_lookup(loading->file,
5218 "%s.rally_point_tgt_vec", citystr);
5219 (void) secfile_entry_lookup(loading->file,
5220 "%s.rally_point_sub_tgt_vec", citystr);
5221 }
5222 }
5223
5224 /* Load the city manager parameters. */
5225 {
5226 bool enabled = secfile_lookup_bool_default(loading->file, FALSE,
5227 "%s.cma_enabled", citystr);
5228 if (enabled) {
5229 struct cm_parameter *param = fc_calloc(1, sizeof(struct cm_parameter));
5230
5231 for (i = 0; i < O_LAST; i++) {
5233 loading->file, 0, "%s.cma_minimal_surplus,%d", citystr, i);
5235 loading->file, 0, "%s.cma_factor,%d", citystr, i);
5236 }
5237
5239 loading->file, FALSE, "%s.max_growth", citystr);
5241 loading->file, FALSE, "%s.require_happy", citystr);
5243 loading->file, FALSE, "%s.allow_disorder", citystr);
5245 loading->file, FALSE, "%s.allow_specialists", citystr);
5247 loading->file, 0, "%s.happy_factor", citystr);
5248 pcity->cm_parameter = param;
5249 } else {
5250 pcity->cm_parameter = NULL;
5251
5252 for (i = 0; i < O_LAST; i++) {
5253 (void) secfile_entry_lookup(loading->file,
5254 "%s.cma_minimal_surplus,%d", citystr, i);
5255 (void) secfile_entry_lookup(loading->file,
5256 "%s.cma_factor,%d", citystr, i);
5257 }
5258
5259 (void) secfile_entry_lookup(loading->file, "%s.max_growth",
5260 citystr);
5261 (void) secfile_entry_lookup(loading->file, "%s.require_happy",
5262 citystr);
5263 (void) secfile_entry_lookup(loading->file, "%s.allow_disorder",
5264 citystr);
5265 (void) secfile_entry_lookup(loading->file, "%s.allow_specialists",
5266 citystr);
5267 (void) secfile_entry_lookup(loading->file, "%s.happy_factor",
5268 citystr);
5269 }
5270 }
5271
5272 CALL_FUNC_EACH_AI(city_load, loading->file, pcity, citystr);
5273
5274 return TRUE;
5275}
5276
5277/************************************************************************/
5280static void sg_load_player_city_citizens(struct loaddata *loading,
5281 struct player *plr,
5282 struct city *pcity,
5283 const char *citystr)
5284{
5286 citizens size;
5287
5288 citizens_init(pcity);
5289 player_slots_iterate(pslot) {
5290 int nationality;
5291
5292 nationality = secfile_lookup_int_default(loading->file, -1,
5293 "%s.citizen%d", citystr,
5294 player_slot_index(pslot));
5295 if (nationality > 0 && !player_slot_is_used(pslot)) {
5296 log_sg("Citizens of an invalid nation for %s (player slot %d)!",
5297 city_name_get(pcity), player_slot_index(pslot));
5298 continue;
5299 }
5300
5301 if (nationality != -1 && player_slot_is_used(pslot)) {
5302 sg_warn(nationality >= 0 && nationality <= MAX_CITY_SIZE,
5303 "Invalid value for citizens of player %d in %s: %d.",
5304 player_slot_index(pslot), city_name_get(pcity), nationality);
5305 citizens_nation_set(pcity, pslot, nationality);
5306 }
5308 /* Sanity check. */
5309 size = citizens_count(pcity);
5310 if (size != city_size_get(pcity)) {
5311 if (size != 0) {
5312 /* size == 0 can be result from the fact that ruleset had no
5313 * nationality enabled at saving time, so no citizens at all
5314 * were saved. But something more serious must be going on if
5315 * citizens have been saved partially - if some of them are there. */
5316 log_sg("City size and number of citizens does not match in %s "
5317 "(%d != %d)! Repairing ...", city_name_get(pcity),
5318 city_size_get(pcity), size);
5319 }
5320 citizens_update(pcity, NULL);
5321 }
5322 }
5323}
5324
5325/************************************************************************/
5328static void sg_save_player_cities(struct savedata *saving,
5329 struct player *plr)
5330{
5331 int wlist_max_length = 0, rally_point_max_length = 0, routes_max = 0;
5332 int i = 0;
5333 int plrno = player_number(plr);
5335
5336 /* Check status and return if not OK (sg_success FALSE). */
5337 sg_check_ret();
5338
5339 secfile_insert_int(saving->file, city_list_size(plr->cities),
5340 "player%d.ncities", plrno);
5341
5343 /* Initialise the nation list for the citizens information. */
5344 player_slots_iterate(pslot) {
5347 }
5348
5349 /* First determine length of longest worklist, rally point order, and the
5350 * nationalities we have. */
5351 city_list_iterate(plr->cities, pcity) {
5352 int routes;
5353
5354 /* Check the sanity of the city. */
5355 city_refresh(pcity);
5356 sanity_check_city(pcity);
5357
5358 if (pcity->worklist.length > wlist_max_length) {
5359 wlist_max_length = pcity->worklist.length;
5360 }
5361
5362 if (pcity->rally_point.length > rally_point_max_length) {
5363 rally_point_max_length = pcity->rally_point.length;
5364 }
5365
5366 routes = city_num_trade_routes(pcity);
5367 if (routes > routes_max) {
5368 routes_max = routes;
5369 }
5370
5372 /* Find all nations of the citizens,*/
5373 players_iterate(pplayer) {
5374 if (!nations[player_index(pplayer)]
5375 && citizens_nation_get(pcity, pplayer->slot) != 0) {
5376 nations[player_index(pplayer)] = TRUE;
5377 }
5379 }
5381
5382 city_list_iterate(plr->cities, pcity) {
5383 struct tile *pcenter = city_tile(pcity);
5384 char impr_buf[B_LAST + 1];
5385 char buf[32];
5386 int j, nat_x, nat_y;
5387
5388 fc_snprintf(buf, sizeof(buf), "player%d.c%d", plrno, i);
5389
5390
5392 secfile_insert_int(saving->file, nat_y, "%s.y", buf);
5393 secfile_insert_int(saving->file, nat_x, "%s.x", buf);
5394
5395 secfile_insert_int(saving->file, pcity->id, "%s.id", buf);
5396
5397 if (pcity->original != NULL) {
5398 secfile_insert_int(saving->file, player_number(pcity->original),
5399 "%s.original", buf);
5400 } else {
5401 secfile_insert_int(saving->file, -1, "%s.original", buf);
5402 }
5403 secfile_insert_int(saving->file, city_size_get(pcity), "%s.size", buf);
5404
5405 j = 0;
5407 secfile_insert_int(saving->file, pcity->specialists[sp], "%s.nspe%d",
5408 buf, j++);
5410
5411 j = 0;
5412 trade_routes_iterate(pcity, proute) {
5413 secfile_insert_int(saving->file, proute->partner, "%s.traderoute%d",
5414 buf, j);
5415 secfile_insert_str(saving->file, route_direction_name(proute->dir),
5416 "%s.route_direction%d", buf, j);
5417 secfile_insert_str(saving->file, goods_rule_name(proute->goods),
5418 "%s.route_good%d", buf, j);
5419 j++;
5421
5422 /* Save dummy values to keep tabular format happy */
5423 for (; j < routes_max; j++) {
5424 secfile_insert_int(saving->file, 0, "%s.traderoute%d", buf, j);
5425 secfile_insert_str(saving->file, route_direction_name(RDIR_BIDIRECTIONAL),
5426 "%s.route_direction%d", buf, j);
5428 "%s.route_good%d", buf, j);
5429 }
5430
5431 secfile_insert_int(saving->file, pcity->food_stock, "%s.food_stock",
5432 buf);
5433 secfile_insert_int(saving->file, pcity->shield_stock, "%s.shield_stock",
5434 buf);
5435 secfile_insert_int(saving->file, pcity->history, "%s.history",
5436 buf);
5437
5438 secfile_insert_int(saving->file, pcity->airlift, "%s.airlift",
5439 buf);
5440 secfile_insert_bool(saving->file, pcity->was_happy, "%s.was_happy",
5441 buf);
5442 secfile_insert_int(saving->file, pcity->turn_plague, "%s.turn_plague",
5443 buf);
5444
5445 secfile_insert_int(saving->file, pcity->anarchy, "%s.anarchy", buf);
5446 secfile_insert_int(saving->file, pcity->rapture, "%s.rapture", buf);
5447 secfile_insert_int(saving->file, pcity->steal, "%s.steal", buf);
5448 secfile_insert_int(saving->file, pcity->turn_founded, "%s.turn_founded",
5449 buf);
5450 secfile_insert_bool(saving->file, pcity->did_buy, "%s.did_buy", buf);
5451 secfile_insert_bool(saving->file, pcity->did_sell, "%s.did_sell", buf);
5452 secfile_insert_int(saving->file, pcity->turn_last_built,
5453 "%s.turn_last_built", buf);
5454
5455 /* for visual debugging, variable length strings together here */
5456 secfile_insert_str(saving->file, city_name_get(pcity), "%s.name", buf);
5457
5458 secfile_insert_str(saving->file, universal_type_rule_name(&pcity->production),
5459 "%s.currently_building_kind", buf);
5460 secfile_insert_str(saving->file, universal_rule_name(&pcity->production),
5461 "%s.currently_building_name", buf);
5462
5463 if (pcity->production.kind == VUT_IMPROVEMENT) {
5464 secfile_insert_int(saving->file,
5465 pcity->server.adv->
5466 building_want[improvement_index(pcity->production.value.building)],
5467 "%s.current_want", buf);
5468 } else {
5469 secfile_insert_int(saving->file, 0,
5470 "%s.current_want", buf);
5471 }
5472
5473 secfile_insert_str(saving->file, universal_type_rule_name(&pcity->changed_from),
5474 "%s.changed_from_kind", buf);
5475 secfile_insert_str(saving->file, universal_rule_name(&pcity->changed_from),
5476 "%s.changed_from_name", buf);
5477
5478 secfile_insert_int(saving->file, pcity->before_change_shields,
5479 "%s.before_change_shields", buf);
5480 secfile_insert_int(saving->file, pcity->caravan_shields,
5481 "%s.caravan_shields", buf);
5482 secfile_insert_int(saving->file, pcity->disbanded_shields,
5483 "%s.disbanded_shields", buf);
5484 secfile_insert_int(saving->file, pcity->last_turns_shield_surplus,
5485 "%s.last_turns_shield_surplus", buf);
5486
5487 secfile_insert_str(saving->file, city_style_rule_name(pcity->style),
5488 "%s.style", buf);
5489
5490 /* Save the squared city radius and all tiles within the corresponing
5491 * city map. */
5492 secfile_insert_int(saving->file, pcity->city_radius_sq,
5493 "player%d.c%d.city_radius_sq", plrno, i);
5494 /* The tiles worked by the city are saved using the main map.
5495 * See also sg_save_map_worked(). */
5496
5497 /* Save improvement list as bytevector. Note that improvement order
5498 * is saved in savefile.improvement_order. */
5499 improvement_iterate(pimprove) {
5500 impr_buf[improvement_index(pimprove)]
5501 = (pcity->built[improvement_index(pimprove)].turn <= I_NEVER) ? '0'
5502 : '1';
5504 impr_buf[improvement_count()] = '\0';
5505
5506 sg_failure_ret(strlen(impr_buf) < sizeof(impr_buf),
5507 "Invalid size of the improvement vector (%s.improvements: "
5508 SIZE_T_PRINTF " < " SIZE_T_PRINTF ").", buf,
5509 strlen(impr_buf), sizeof(impr_buf));
5510 secfile_insert_str(saving->file, impr_buf, "%s.improvements", buf);
5511
5512 worklist_save(saving->file, &pcity->worklist, wlist_max_length, "%s",
5513 buf);
5514
5515 for (j = 0; j < CITYO_LAST; j++) {
5516 secfile_insert_bool(saving->file, BV_ISSET(pcity->city_options, j),
5517 "%s.option%d", buf, j);
5518 }
5519
5520 CALL_FUNC_EACH_AI(city_save, saving->file, pcity, buf);
5521
5523 /* Save nationality of the citizens,*/
5524 players_iterate(pplayer) {
5525 if (nations[player_index(pplayer)]) {
5526 secfile_insert_int(saving->file,
5527 citizens_nation_get(pcity, pplayer->slot),
5528 "%s.citizen%d", buf, player_index(pplayer));
5529 }
5531 }
5532
5533 secfile_insert_int(saving->file, pcity->rally_point.length,
5534 "%s.rally_point_length", buf);
5535 if (pcity->rally_point.length) {
5536 int len = pcity->rally_point.length;
5537 char orders[len + 1], dirs[len + 1], activities[len + 1];
5538 int actions[len];
5539 int targets[len];
5540 int sub_targets[len];
5541
5542 secfile_insert_bool(saving->file, pcity->rally_point.persistent,
5543 "%s.rally_point_persistent", buf);
5544 secfile_insert_bool(saving->file, pcity->rally_point.vigilant,
5545 "%s.rally_point_vigilant", buf);
5546
5547 for (j = 0; j < len; j++) {
5548 orders[j] = order2char(pcity->rally_point.orders[j].order);
5549 dirs[j] = '?';
5550 activities[j] = '?';
5551 targets[j] = NO_TARGET;
5552 sub_targets[j] = NO_TARGET;
5553 actions[j] = -1;
5554 switch (pcity->rally_point.orders[j].order) {
5555 case ORDER_MOVE:
5556 case ORDER_ACTION_MOVE:
5557 dirs[j] = dir2char(pcity->rally_point.orders[j].dir);
5558 break;
5559 case ORDER_ACTIVITY:
5560 sub_targets[j] = pcity->rally_point.orders[j].sub_target;
5561 activities[j]
5562 = activity2char(pcity->rally_point.orders[j].activity);
5563 break;
5565 actions[j] = pcity->rally_point.orders[j].action;
5566 targets[j] = pcity->rally_point.orders[j].target;
5567 sub_targets[j] = pcity->rally_point.orders[j].sub_target;
5568 break;
5569 case ORDER_FULL_MP:
5570 case ORDER_LAST:
5571 break;
5572 }
5573 }
5574 orders[len] = dirs[len] = activities[len] = '\0';
5575
5576 secfile_insert_str(saving->file, orders, "%s.rally_point_orders", buf);
5577 secfile_insert_str(saving->file, dirs, "%s.rally_point_dirs", buf);
5578 secfile_insert_str(saving->file, activities,
5579 "%s.rally_point_activities", buf);
5580
5582 "%s.rally_point_action_vec", buf);
5583 /* Fill in dummy values for order targets so the registry will save
5584 * the unit table in a tabular format. */
5585 for (j = len; j < rally_point_max_length; j++) {
5586 secfile_insert_int(saving->file, -1, "%s.rally_point_action_vec,%d",
5587 buf, j);
5588 }
5589
5590 secfile_insert_int_vec(saving->file, targets, len,
5591 "%s.rally_point_tgt_vec", buf);
5592 /* Fill in dummy values for order targets so the registry will save
5593 * the unit table in a tabular format. */
5594 for (j = len; j < rally_point_max_length; j++) {
5596 "%s.rally_point_tgt_vec,%d", buf, j);
5597 }
5598
5599 secfile_insert_int_vec(saving->file, sub_targets, len,
5600 "%s.rally_point_sub_tgt_vec", buf);
5601 /* Fill in dummy values for order targets so the registry will save
5602 * the unit table in a tabular format. */
5603 for (j = len; j < rally_point_max_length; j++) {
5604 secfile_insert_int(saving->file, -1, "%s.rally_point_sub_tgt_vec,%d",
5605 buf, j);
5606 }
5607 } else {
5608 /* Put all the same fields into the savegame - otherwise the
5609 * registry code can't correctly use a tabular format and the
5610 * savegame will be bigger. */
5611 secfile_insert_bool(saving->file, FALSE, "%s.rally_point_persistent",
5612 buf);
5613 secfile_insert_bool(saving->file, FALSE, "%s.rally_point_vigilant",
5614 buf);
5615 secfile_insert_str(saving->file, "-", "%s.rally_point_orders", buf);
5616 secfile_insert_str(saving->file, "-", "%s.rally_point_dirs", buf);
5617 secfile_insert_str(saving->file, "-", "%s.rally_point_activities",
5618 buf);
5619
5620 /* Fill in dummy values for order targets so the registry will save
5621 * the unit table in a tabular format. */
5622
5623 /* The start of a vector has no number. */
5624 secfile_insert_int(saving->file, -1, "%s.rally_point_action_vec",
5625 buf);
5626 for (j = 1; j < rally_point_max_length; j++) {
5627 secfile_insert_int(saving->file, -1, "%s.rally_point_action_vec,%d",
5628 buf, j);
5629 }
5630
5631 /* The start of a vector has no number. */
5632 secfile_insert_int(saving->file, NO_TARGET, "%s.rally_point_tgt_vec",
5633 buf);
5634 for (j = 1; j < rally_point_max_length; j++) {
5636 "%s.rally_point_tgt_vec,%d", buf, j);
5637 }
5638
5639 /* The start of a vector has no number. */
5640 secfile_insert_int(saving->file, -1, "%s.rally_point_sub_tgt_vec",
5641 buf);
5642 for (j = 1; j < rally_point_max_length; j++) {
5643 secfile_insert_int(saving->file, -1, "%s.rally_point_sub_tgt_vec,%d",
5644 buf, j);
5645 }
5646 }
5647
5648 secfile_insert_bool(saving->file, pcity->cm_parameter != NULL,
5649 "%s.cma_enabled", buf);
5650 if (pcity->cm_parameter) {
5652 pcity->cm_parameter->minimal_surplus, O_LAST,
5653 "%s.cma_minimal_surplus", buf);
5655 pcity->cm_parameter->factor, O_LAST,
5656 "%s.cma_factor", buf);
5657 secfile_insert_bool(saving->file, pcity->cm_parameter->max_growth,
5658 "%s.max_growth", buf);
5659 secfile_insert_bool(saving->file, pcity->cm_parameter->require_happy,
5660 "%s.require_happy", buf);
5661 secfile_insert_bool(saving->file, pcity->cm_parameter->allow_disorder,
5662 "%s.allow_disorder", buf);
5663 secfile_insert_bool(saving->file,
5664 pcity->cm_parameter->allow_specialists,
5665 "%s.allow_specialists", buf);
5666 secfile_insert_int(saving->file, pcity->cm_parameter->happy_factor,
5667 "%s.happy_factor", buf);
5668 } else {
5669 int zeros[O_LAST];
5670
5671 memset(zeros, 0, sizeof(zeros));
5672 secfile_insert_int_vec(saving->file, zeros, O_LAST,
5673 "%s.cma_minimal_surplus", buf);
5674 secfile_insert_int_vec(saving->file, zeros, O_LAST,
5675 "%s.cma_factor", buf);
5676 secfile_insert_bool(saving->file, FALSE, "%s.max_growth", buf);
5677 secfile_insert_bool(saving->file, FALSE, "%s.require_happy", buf);
5678 secfile_insert_bool(saving->file, FALSE, "%s.allow_disorder", buf);
5679 secfile_insert_bool(saving->file, FALSE, "%s.allow_specialists", buf);
5680 secfile_insert_int(saving->file, 0, "%s.happy_factor", buf);
5681 }
5682
5683 i++;
5685
5686 i = 0;
5687 city_list_iterate(plr->cities, pcity) {
5688 worker_task_list_iterate(pcity->task_reqs, ptask) {
5689 int nat_x, nat_y;
5690
5691 index_to_native_pos(&nat_x, &nat_y, tile_index(ptask->ptile));
5692 secfile_insert_int(saving->file, pcity->id, "player%d.task%d.city",
5693 plrno, i);
5694 secfile_insert_int(saving->file, nat_y, "player%d.task%d.y", plrno, i);
5695 secfile_insert_int(saving->file, nat_x, "player%d.task%d.x", plrno, i);
5696 secfile_insert_str(saving->file, unit_activity_name(ptask->act),
5697 "player%d.task%d.activity",
5698 plrno, i);
5699 if (ptask->tgt != NULL) {
5700 secfile_insert_str(saving->file, extra_rule_name(ptask->tgt),
5701 "player%d.task%d.target",
5702 plrno, i);
5703 } else {
5704 secfile_insert_str(saving->file, "-",
5705 "player%d.task%d.target",
5706 plrno, i);
5707 }
5708 secfile_insert_int(saving->file, ptask->want, "player%d.task%d.want", plrno, i);
5709
5710 i++;
5713}
5714
5715/************************************************************************/
5718static void sg_load_player_units(struct loaddata *loading,
5719 struct player *plr)
5720{
5721 int nunits, i, plrno = player_number(plr);
5722 size_t orders_max_length;
5723
5724 /* Check status and return if not OK (sg_success FALSE). */
5725 sg_check_ret();
5726
5727 sg_failure_ret(secfile_lookup_int(loading->file, &nunits,
5728 "player%d.nunits", plrno),
5729 "%s", secfile_error());
5730 if (!plr->is_alive && nunits > 0) {
5731 log_sg("'player%d.nunits' = %d for dead player!", plrno, nunits);
5732 nunits = 0; /* Some old savegames may be buggy. */
5733 }
5734
5735 orders_max_length = 0;
5736
5737 for (i = 0; i < nunits; i++) {
5738 int ol_length = secfile_lookup_int_default(loading->file, 0,
5739 "player%d.u%d.orders_length",
5740 plrno, i);
5741
5742 orders_max_length = MAX(orders_max_length, ol_length);
5743 }
5744
5745 for (i = 0; i < nunits; i++) {
5746 struct unit *punit;
5747 struct city *pcity;
5748 const char *name;
5749 char buf[32];
5750 struct unit_type *type;
5751 struct tile *ptile;
5752
5753 fc_snprintf(buf, sizeof(buf), "player%d.u%d", plrno, i);
5754
5755 name = secfile_lookup_str(loading->file, "%s.type_by_name", buf);
5757 sg_failure_ret(type != NULL, "%s: unknown unit type \"%s\".", buf, name);
5758
5759 /* Create a dummy unit. */
5760 punit = unit_virtual_create(plr, NULL, type, 0);
5761 if (!sg_load_player_unit(loading, plr, punit, orders_max_length, buf)) {
5763 sg_failure_ret(FALSE, "Error loading unit %d of player %d.", i, plrno);
5764 }
5765
5768
5769 if ((pcity = game_city_by_number(punit->homecity))) {
5770 unit_list_prepend(pcity->units_supported, punit);
5771 } else if (punit->homecity > IDENTITY_NUMBER_ZERO) {
5772 log_sg("%s: bad home city %d.", buf, punit->homecity);
5774 }
5775
5776 ptile = unit_tile(punit);
5777
5778 /* allocate the unit's contribution to fog of war */
5781 /* NOTE: There used to be some map_set_known calls here. These were
5782 * unneeded since unfogging the tile when the unit sees it will
5783 * automatically reveal that tile. */
5784
5785 unit_list_append(plr->units, punit);
5786 unit_list_prepend(unit_tile(punit)->units, punit);
5787 }
5788}
5789
5790/************************************************************************/
5793static bool sg_load_player_unit(struct loaddata *loading,
5794 struct player *plr, struct unit *punit,
5795 int orders_max_length,
5796 const char *unitstr)
5797{
5798 enum unit_activity activity;
5799 int nat_x, nat_y;
5800 struct extra_type *pextra = NULL;
5801 struct tile *ptile;
5802 int extra_id;
5803 int ei;
5804 const char *facing_str;
5805 int natnbr;
5806 int unconverted;
5807 const char *str;
5808
5809 sg_warn_ret_val(secfile_lookup_int(loading->file, &punit->id, "%s.id",
5810 unitstr), FALSE, "%s", secfile_error());
5811 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_x, "%s.x", unitstr),
5812 FALSE, "%s", secfile_error());
5813 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_y, "%s.y", unitstr),
5814 FALSE, "%s", secfile_error());
5815
5816 ptile = native_pos_to_tile(&(wld.map), nat_x, nat_y);
5817 sg_warn_ret_val(NULL != ptile, FALSE, "%s invalid tile (%d, %d)",
5818 unitstr, nat_x, nat_y);
5819 unit_tile_set(punit, ptile);
5820
5821 facing_str
5822 = secfile_lookup_str_default(loading->file, "x",
5823 "%s.facing", unitstr);
5824 if (facing_str[0] != 'x') {
5825 /* We don't touch punit->facing if savegame does not contain that
5826 * information. Initial orientation set by unit_virtual_create()
5827 * is as good as any. */
5828 enum direction8 facing = char2dir(facing_str[0]);
5829
5830 if (direction8_is_valid(facing)) {
5831 punit->facing = facing;
5832 } else {
5833 log_error("Illegal unit orientation '%s'", facing_str);
5834 }
5835 }
5836
5837 /* If savegame has unit nationality, it doesn't hurt to
5838 * internally set it even if nationality rules are disabled. */
5839 natnbr = secfile_lookup_int_default(loading->file,
5840 player_number(plr),
5841 "%s.nationality", unitstr);
5842
5844 if (punit->nationality == NULL) {
5845 punit->nationality = plr;
5846 }
5847
5849 "%s.homecity", unitstr), FALSE,
5850 "%s", secfile_error());
5852 "%s.moves", unitstr), FALSE,
5853 "%s", secfile_error());
5855 "%s.fuel", unitstr), FALSE,
5856 "%s", secfile_error());
5858 "%s.activity", unitstr), FALSE,
5859 "%s", secfile_error());
5860 activity = unit_activity_by_name(loading->activities.order[ei],
5862
5865 "%s.born", unitstr);
5866
5867 extra_id = secfile_lookup_int_default(loading->file, -2,
5868 "%s.activity_tgt", unitstr);
5869
5870 if (extra_id != -2) {
5871 if (extra_id >= 0 && extra_id < loading->extra.size) {
5872 pextra = loading->extra.order[extra_id];
5873 set_unit_activity_targeted(punit, activity, pextra);
5874 } else if (activity == ACTIVITY_IRRIGATE) {
5876 EC_IRRIGATION,
5878 punit);
5879 if (tgt != NULL) {
5880 set_unit_activity_targeted(punit, ACTIVITY_IRRIGATE, tgt);
5881 } else {
5882 set_unit_activity(punit, ACTIVITY_CULTIVATE);
5883 }
5884 } else if (activity == ACTIVITY_MINE) {
5886 EC_MINE,
5888 punit);
5889 if (tgt != NULL) {
5890 set_unit_activity_targeted(punit, ACTIVITY_MINE, tgt);
5891 } else {
5892 set_unit_activity(punit, ACTIVITY_PLANT);
5893 }
5894 } else {
5895 set_unit_activity(punit, activity);
5896 }
5897 } else {
5898 set_unit_activity_targeted(punit, activity, NULL);
5899 } /* activity_tgt == NULL */
5900
5902 "%s.activity_count", unitstr), FALSE,
5903 "%s", secfile_error());
5904
5906 secfile_lookup_int_default(loading->file, ACTIVITY_IDLE,
5907 "%s.changed_from", unitstr);
5908
5909 sg_warn_ret_val(secfile_lookup_int(loading->file, &extra_id,
5910 "%s.changed_from_tgt", unitstr), FALSE,
5911 "%s", secfile_error());
5912
5913 if (extra_id >= 0 && extra_id < loading->extra.size) {
5914 punit->changed_from_target = loading->extra.order[extra_id];
5915 } else {
5916 punit->changed_from_target = NULL;
5917 }
5918
5920 secfile_lookup_int_default(loading->file, 0,
5921 "%s.changed_from_count", unitstr);
5922
5923 /* Special case: for a long time, we accidentally incremented
5924 * activity_count while a unit was sentried, so it could increase
5925 * without bound (bug #20641) and be saved in old savefiles.
5926 * We zero it to prevent potential trouble overflowing the range
5927 * in network packets, etc. */
5928 if (activity == ACTIVITY_SENTRY) {
5929 punit->activity_count = 0;
5930 }
5931 if (punit->changed_from == ACTIVITY_SENTRY) {
5933 }
5934
5935 punit->veteran
5936 = secfile_lookup_int_default(loading->file, 0, "%s.veteran", unitstr);
5937 {
5938 /* Protect against change in veteran system in ruleset */
5939 const int levels = utype_veteran_levels(unit_type_get(punit));
5940
5941 if (punit->veteran >= levels) {
5942 fc_assert(levels >= 1);
5943 punit->veteran = levels - 1;
5944 }
5945 }
5948 "%s.done_moving", unitstr);
5951 "%s.battlegroup", unitstr);
5952
5954 "%s.go", unitstr)) {
5955 int gnat_x, gnat_y;
5956
5957 sg_warn_ret_val(secfile_lookup_int(loading->file, &gnat_x,
5958 "%s.goto_x", unitstr), FALSE,
5959 "%s", secfile_error());
5960 sg_warn_ret_val(secfile_lookup_int(loading->file, &gnat_y,
5961 "%s.goto_y", unitstr), FALSE,
5962 "%s", secfile_error());
5963
5964 punit->goto_tile = native_pos_to_tile(&(wld.map), gnat_x, gnat_y);
5965 } else {
5966 punit->goto_tile = NULL;
5967
5968 /* These variables are not used but needed for saving the unit table.
5969 * Load them to prevent unused variables errors. */
5970 (void) secfile_entry_lookup(loading->file, "%s.goto_x", unitstr);
5971 (void) secfile_entry_lookup(loading->file, "%s.goto_y", unitstr);
5972 }
5973
5974 /* Load AI data of the unit. */
5975 CALL_FUNC_EACH_AI(unit_load, loading->file, punit, unitstr);
5976
5977 unconverted
5978 = secfile_lookup_int_default(loading->file, 0,
5979 "%s.server_side_agent",
5980 unitstr);
5981 if (unconverted >= 0 && unconverted < loading->ssa.size) {
5982 /* Look up what server side agent the unconverted number represents. */
5983 punit->ssa_controller = loading->ssa.order[unconverted];
5984 } else {
5985 log_sg("Invalid server side agent %d for unit %d",
5986 unconverted, punit->id);
5987
5988 punit->ssa_controller = SSA_NONE;
5989 }
5990
5992 "%s.hp", unitstr), FALSE,
5993 "%s", secfile_error());
5994
5996 = secfile_lookup_int_default(loading->file, 0, "%s.ord_map", unitstr);
5998 = secfile_lookup_int_default(loading->file, 0, "%s.ord_city", unitstr);
5999 punit->moved
6000 = secfile_lookup_bool_default(loading->file, FALSE, "%s.moved", unitstr);
6003 "%s.paradropped", unitstr);
6004 str = secfile_lookup_str_default(loading->file, "", "%s.carrying", unitstr);
6005 if (str[0] != '\0') {
6007 }
6008
6009 /* The transport status (punit->transported_by) is loaded in
6010 * sg_player_units_transport(). */
6011
6012 /* Initialize upkeep values: these are hopefully initialized
6013 * elsewhere before use (specifically, in city_support(); but
6014 * fixme: check whether always correctly initialized?).
6015 * Below is mainly for units which don't have homecity --
6016 * otherwise these don't get initialized (and AI calculations
6017 * etc may use junk values). */
6021
6022 sg_warn_ret_val(secfile_lookup_int(loading->file, &unconverted,
6023 "%s.action_decision", unitstr),
6024 FALSE, "%s", secfile_error());
6025
6026 if (unconverted >= 0 && unconverted < loading->act_dec.size) {
6027 /* Look up what action decision want the unconverted number
6028 * represents. */
6029 punit->action_decision_want = loading->act_dec.order[unconverted];
6030 } else {
6031 log_sg("Invalid action decision want for unit %d", punit->id);
6032
6033 punit->action_decision_want = ACT_DEC_NOTHING;
6034 }
6035
6036 if (punit->action_decision_want != ACT_DEC_NOTHING) {
6037 /* Load the tile to act against. */
6038 int adwt_x, adwt_y;
6039
6040 if (secfile_lookup_int(loading->file, &adwt_x,
6041 "%s.action_decision_tile_x", unitstr)
6042 && secfile_lookup_int(loading->file, &adwt_y,
6043 "%s.action_decision_tile_y", unitstr)) {
6045 adwt_x, adwt_y);
6046 } else {
6047 punit->action_decision_want = ACT_DEC_NOTHING;
6049 log_sg("Bad action_decision_tile for unit %d", punit->id);
6050 }
6051 } else {
6052 (void) secfile_entry_lookup(loading->file, "%s.action_decision_tile_x", unitstr);
6053 (void) secfile_entry_lookup(loading->file, "%s.action_decision_tile_y", unitstr);
6055 }
6056
6057 punit->stay = secfile_lookup_bool_default(loading->file, FALSE, "%s.stay", unitstr);
6058
6059 /* Load the unit orders */
6060 {
6061 int len = secfile_lookup_int_default(loading->file, 0,
6062 "%s.orders_length", unitstr);
6063
6064 if (len > 0) {
6065 const char *orders_unitstr, *dir_unitstr, *act_unitstr;
6066 int j;
6067
6068 punit->orders.list = fc_malloc(len * sizeof(*(punit->orders.list)));
6071 = secfile_lookup_int_default(loading->file, 0,
6072 "%s.orders_index", unitstr);
6075 "%s.orders_repeat", unitstr);
6078 "%s.orders_vigilant", unitstr);
6079
6080 orders_unitstr
6081 = secfile_lookup_str_default(loading->file, "",
6082 "%s.orders_list", unitstr);
6083 dir_unitstr
6084 = secfile_lookup_str_default(loading->file, "",
6085 "%s.dir_list", unitstr);
6086 act_unitstr
6087 = secfile_lookup_str_default(loading->file, "",
6088 "%s.activity_list", unitstr);
6089
6091
6092 for (j = 0; j < len; j++) {
6093 struct unit_order *order = &punit->orders.list[j];
6094 bool action_wants_extra = FALSE;
6095 int order_sub_tgt;
6096
6097 if (orders_unitstr[j] == '\0' || dir_unitstr[j] == '\0'
6098 || act_unitstr[j] == '\0') {
6099 log_sg("Invalid unit orders.");
6101 break;
6102 }
6103 order->order = char2order(orders_unitstr[j]);
6104 order->dir = char2dir(dir_unitstr[j]);
6105 order->activity = char2activity(act_unitstr[j]);
6106
6107 unconverted = secfile_lookup_int_default(loading->file, ACTION_NONE,
6108 "%s.action_vec,%d",
6109 unitstr, j);
6110
6111 if (unconverted >= 0 && unconverted < loading->action.size) {
6112 /* Look up what action id the unconverted number represents. */
6113 order->action = loading->action.order[unconverted];
6114 } else {
6115 if (order->order == ORDER_PERFORM_ACTION) {
6116 log_sg("Invalid action id in order for unit %d", punit->id);
6117 }
6118
6119 order->action = ACTION_NONE;
6120 }
6121
6122 if (order->order == ORDER_LAST
6123 || (order->order == ORDER_MOVE && !direction8_is_valid(order->dir))
6124 || (order->order == ORDER_ACTION_MOVE
6125 && !direction8_is_valid(order->dir))
6126 || (order->order == ORDER_PERFORM_ACTION
6127 && !action_id_exists(order->action))
6128 || (order->order == ORDER_ACTIVITY
6129 && order->activity == ACTIVITY_LAST)) {
6130 /* An invalid order. Just drop the orders for this unit. */
6131 free(punit->orders.list);
6132 punit->orders.list = NULL;
6134 break;
6135 }
6136
6137 order->target = secfile_lookup_int_default(loading->file, NO_TARGET,
6138 "%s.tgt_vec,%d",
6139 unitstr, j);
6140 order_sub_tgt = secfile_lookup_int_default(loading->file, -1,
6141 "%s.sub_tgt_vec,%d",
6142 unitstr, j);
6143
6144 if (order->order == ORDER_PERFORM_ACTION) {
6145 /* Validate sub target */
6146 switch (action_id_get_sub_target_kind(order->action)) {
6147 case ASTK_BUILDING:
6148 /* Sub target is a building. */
6149 if (!improvement_by_number(order_sub_tgt)) {
6150 /* Sub target is invalid. */
6151 log_sg("Cannot find building %d for %s to %s",
6152 order_sub_tgt, unit_rule_name(punit),
6154 order->sub_target = B_LAST;
6155 } else {
6156 order->sub_target = order_sub_tgt;
6157 }
6158 break;
6159 case ASTK_TECH:
6160 /* Sub target is a technology. */
6161 if (order_sub_tgt == A_NONE
6162 || (!valid_advance_by_number(order_sub_tgt)
6163 && order_sub_tgt != A_FUTURE)) {
6164 /* Target tech is invalid. */
6165 log_sg("Cannot find tech %d for %s to steal",
6166 order_sub_tgt, unit_rule_name(punit));
6167 order->sub_target = A_NONE;
6168 } else {
6169 order->sub_target = order_sub_tgt;
6170 }
6171 break;
6172 case ASTK_EXTRA:
6173 case ASTK_EXTRA_NOT_THERE:
6174 /* These take an extra. */
6175 action_wants_extra = TRUE;
6176 break;
6177 case ASTK_NONE:
6178 /* None of these can take a sub target. */
6179 fc_assert_msg(order_sub_tgt == -1,
6180 "Specified sub target for action %d unsupported.",
6181 order->action);
6182 order->sub_target = NO_TARGET;
6183 break;
6184 case ASTK_COUNT:
6185 fc_assert_msg(order_sub_tgt == -1,
6186 "Bad action action %d.",
6187 order->action);
6188 order->sub_target = NO_TARGET;
6189 break;
6190 }
6191 }
6192
6193 if (order->order == ORDER_ACTIVITY || action_wants_extra) {
6194 enum unit_activity act;
6195
6196 if (order_sub_tgt < 0 || order_sub_tgt >= loading->extra.size) {
6197 if (order_sub_tgt != EXTRA_NONE) {
6198 log_sg("Cannot find extra %d for %s to build",
6199 order_sub_tgt, unit_rule_name(punit));
6200 }
6201
6202 order->sub_target = EXTRA_NONE;
6203 } else {
6204 order->sub_target = order_sub_tgt;
6205 }
6206
6207 /* An action or an activity may require an extra target. */
6208 if (action_wants_extra) {
6209 act = action_id_get_activity(order->action);
6210 } else {
6211 act = order->activity;
6212 }
6213
6214 if (unit_activity_is_valid(act)
6216 && order->sub_target == EXTRA_NONE) {
6217 /* Missing required action extra target. */
6218 free(punit->orders.list);
6219 punit->orders.list = NULL;
6221 break;
6222 }
6223 } else if (order->order != ORDER_PERFORM_ACTION) {
6224 if (order_sub_tgt != -1) {
6225 log_sg("Unexpected sub_target %d (expected %d) for order type %d",
6226 order_sub_tgt, -1, order->order);
6227 }
6228 order->sub_target = NO_TARGET;
6229 }
6230 }
6231
6232 for (; j < orders_max_length; j++) {
6233 (void) secfile_entry_lookup(loading->file,
6234 "%s.action_vec,%d", unitstr, j);
6235 (void) secfile_entry_lookup(loading->file,
6236 "%s.tgt_vec,%d", unitstr, j);
6237 (void) secfile_entry_lookup(loading->file,
6238 "%s.sub_tgt_vec,%d", unitstr, j);
6239 }
6240 } else {
6241 int j;
6242
6244 punit->orders.list = NULL;
6245
6246 (void) secfile_entry_lookup(loading->file, "%s.orders_index", unitstr);
6247 (void) secfile_entry_lookup(loading->file, "%s.orders_repeat", unitstr);
6248 (void) secfile_entry_lookup(loading->file, "%s.orders_vigilant", unitstr);
6249 (void) secfile_entry_lookup(loading->file, "%s.orders_list", unitstr);
6250 (void) secfile_entry_lookup(loading->file, "%s.dir_list", unitstr);
6251 (void) secfile_entry_lookup(loading->file, "%s.activity_list", unitstr);
6252 (void) secfile_entry_lookup(loading->file, "%s.action_vec", unitstr);
6253 (void) secfile_entry_lookup(loading->file, "%s.tgt_vec", unitstr);
6254 (void) secfile_entry_lookup(loading->file, "%s.sub_tgt_vec", unitstr);
6255
6256 for (j = 1; j < orders_max_length; j++) {
6257 (void) secfile_entry_lookup(loading->file,
6258 "%s.action_vec,%d", unitstr, j);
6259 (void) secfile_entry_lookup(loading->file,
6260 "%s.tgt_vec,%d", unitstr, j);
6261 (void) secfile_entry_lookup(loading->file,
6262 "%s.sub_tgt_vec,%d", unitstr, j);
6263 }
6264 }
6265 }
6266
6267 return TRUE;
6268}
6269
6270/************************************************************************/
6274static void sg_load_player_units_transport(struct loaddata *loading,
6275 struct player *plr)
6276{
6277 int nunits, i, plrno = player_number(plr);
6278
6279 /* Check status and return if not OK (sg_success FALSE). */
6280 sg_check_ret();
6281
6282 /* Recheck the number of units for the player. This is a copied from
6283 * sg_load_player_units(). */
6284 sg_failure_ret(secfile_lookup_int(loading->file, &nunits,
6285 "player%d.nunits", plrno),
6286 "%s", secfile_error());
6287 if (!plr->is_alive && nunits > 0) {
6288 log_sg("'player%d.nunits' = %d for dead player!", plrno, nunits);
6289 nunits = 0; /* Some old savegames may be buggy. */
6290 }
6291
6292 for (i = 0; i < nunits; i++) {
6293 int id_unit, id_trans;
6294 struct unit *punit, *ptrans;
6295
6296 id_unit = secfile_lookup_int_default(loading->file, -1,
6297 "player%d.u%d.id",
6298 plrno, i);
6299 punit = player_unit_by_number(plr, id_unit);
6300 fc_assert_action(punit != NULL, continue);
6301
6302 id_trans = secfile_lookup_int_default(loading->file, -1,
6303 "player%d.u%d.transported_by",
6304 plrno, i);
6305 if (id_trans == -1) {
6306 /* Not transported. */
6307 continue;
6308 }
6309
6310 ptrans = game_unit_by_number(id_trans);
6311 fc_assert_action(id_trans == -1 || ptrans != NULL, continue);
6312
6313 if (ptrans) {
6314#ifndef FREECIV_NDEBUG
6315 bool load_success =
6316#endif
6317 unit_transport_load(punit, ptrans, TRUE);
6318
6319 fc_assert_action(load_success, continue);
6320 }
6321 }
6322}
6323
6324/************************************************************************/
6327static void sg_save_player_units(struct savedata *saving,
6328 struct player *plr)
6329{
6330 int i = 0;
6331 int longest_order = 0;
6332 int plrno = player_number(plr);
6333
6334 /* Check status and return if not OK (sg_success FALSE). */
6335 sg_check_ret();
6336
6337 secfile_insert_int(saving->file, unit_list_size(plr->units),
6338 "player%d.nunits", plrno);
6339
6340 /* Find the longest unit order so different order length won't break
6341 * storing units in the tabular format. */
6343 if (punit->has_orders) {
6344 if (longest_order < punit->orders.length) {
6345 longest_order = punit->orders.length;
6346 }
6347 }
6349
6351 char buf[32];
6352 char dirbuf[2] = " ";
6353 int nat_x, nat_y;
6354 int last_order, j;
6355
6356 fc_snprintf(buf, sizeof(buf), "player%d.u%d", plrno, i);
6357 dirbuf[0] = dir2char(punit->facing);
6358 secfile_insert_int(saving->file, punit->id, "%s.id", buf);
6359
6361 secfile_insert_int(saving->file, nat_x, "%s.x", buf);
6362 secfile_insert_int(saving->file, nat_y, "%s.y", buf);
6363
6364 secfile_insert_str(saving->file, dirbuf, "%s.facing", buf);
6367 "%s.nationality", buf);
6368 }
6369 secfile_insert_int(saving->file, punit->veteran, "%s.veteran", buf);
6370 secfile_insert_int(saving->file, punit->hp, "%s.hp", buf);
6371 secfile_insert_int(saving->file, punit->homecity, "%s.homecity", buf);
6373 "%s.type_by_name", buf);
6374
6375 secfile_insert_int(saving->file, punit->activity, "%s.activity", buf);
6377 "%s.activity_count", buf);
6378 if (punit->activity_target == NULL) {
6379 secfile_insert_int(saving->file, -1, "%s.activity_tgt", buf);
6380 } else {
6382 "%s.activity_tgt", buf);
6383 }
6384
6386 "%s.changed_from", buf);
6388 "%s.changed_from_count", buf);
6389 if (punit->changed_from_target == NULL) {
6390 secfile_insert_int(saving->file, -1, "%s.changed_from_tgt", buf);
6391 } else {
6393 "%s.changed_from_tgt", buf);
6394 }
6395
6397 "%s.done_moving", buf);
6398 secfile_insert_int(saving->file, punit->moves_left, "%s.moves", buf);
6399 secfile_insert_int(saving->file, punit->fuel, "%s.fuel", buf);
6401 "%s.born", buf);
6403 "%s.battlegroup", buf);
6404
6405 if (punit->goto_tile) {
6407 secfile_insert_bool(saving->file, TRUE, "%s.go", buf);
6408 secfile_insert_int(saving->file, nat_x, "%s.goto_x", buf);
6409 secfile_insert_int(saving->file, nat_y, "%s.goto_y", buf);
6410 } else {
6411 secfile_insert_bool(saving->file, FALSE, "%s.go", buf);
6412 /* Set this values to allow saving it as table. */
6413 secfile_insert_int(saving->file, 0, "%s.goto_x", buf);
6414 secfile_insert_int(saving->file, 0, "%s.goto_y", buf);
6415 }
6416
6418 "%s.server_side_agent", buf);
6419
6420 /* Save AI data of the unit. */
6421 CALL_FUNC_EACH_AI(unit_save, saving->file, punit, buf);
6422
6424 "%s.ord_map", buf);
6426 "%s.ord_city", buf);
6427 secfile_insert_bool(saving->file, punit->moved, "%s.moved", buf);
6429 "%s.paradropped", buf);
6431 ? unit_transport_get(punit)->id : -1,
6432 "%s.transported_by", buf);
6433 if (punit->carrying != NULL) {
6435 "%s.carrying", buf);
6436 } else {
6437 secfile_insert_str(saving->file, "", "%s.carrying", buf);
6438 }
6439
6441 "%s.action_decision", buf);
6442
6443 /* Stored as tile rather than direction to make sure the target tile is
6444 * sane. */
6448 secfile_insert_int(saving->file, nat_x,
6449 "%s.action_decision_tile_x", buf);
6450 secfile_insert_int(saving->file, nat_y,
6451 "%s.action_decision_tile_y", buf);
6452 } else {
6453 /* Dummy values to get tabular format. */
6454 secfile_insert_int(saving->file, -1,
6455 "%s.action_decision_tile_x", buf);
6456 secfile_insert_int(saving->file, -1,
6457 "%s.action_decision_tile_y", buf);
6458 }
6459
6461 "%s.stay", buf);
6462
6463 if (punit->has_orders) {
6464 int len = punit->orders.length;
6465 char orders_buf[len + 1], dir_buf[len + 1];
6466 char act_buf[len + 1];
6467 int action_buf[len];
6468 int tgt_vec[len];
6469 int sub_tgt_vec[len];
6470
6471 last_order = len;
6472
6473 secfile_insert_int(saving->file, len, "%s.orders_length", buf);
6475 "%s.orders_index", buf);
6477 "%s.orders_repeat", buf);
6479 "%s.orders_vigilant", buf);
6480
6481 for (j = 0; j < len; j++) {
6482 orders_buf[j] = order2char(punit->orders.list[j].order);
6483 dir_buf[j] = '?';
6484 act_buf[j] = '?';
6485 tgt_vec[j] = NO_TARGET;
6486 sub_tgt_vec[j] = -1;
6487 action_buf[j] = -1;
6488 switch (punit->orders.list[j].order) {
6489 case ORDER_MOVE:
6490 case ORDER_ACTION_MOVE:
6491 dir_buf[j] = dir2char(punit->orders.list[j].dir);
6492 break;
6493 case ORDER_ACTIVITY:
6494 sub_tgt_vec[j] = punit->orders.list[j].sub_target;
6495 act_buf[j] = activity2char(punit->orders.list[j].activity);
6496 break;
6498 action_buf[j] = punit->orders.list[j].action;
6499 tgt_vec[j] = punit->orders.list[j].target;
6500 sub_tgt_vec[j] = punit->orders.list[j].sub_target;
6501 break;
6502 case ORDER_FULL_MP:
6503 case ORDER_LAST:
6504 break;
6505 }
6506 }
6507 orders_buf[len] = dir_buf[len] = act_buf[len] = '\0';
6508
6509 secfile_insert_str(saving->file, orders_buf, "%s.orders_list", buf);
6510 secfile_insert_str(saving->file, dir_buf, "%s.dir_list", buf);
6511 secfile_insert_str(saving->file, act_buf, "%s.activity_list", buf);
6512
6513 secfile_insert_int_vec(saving->file, action_buf, len,
6514 "%s.action_vec", buf);
6515 /* Fill in dummy values for order targets so the registry will save
6516 * the unit table in a tabular format. */
6517 for (j = last_order; j < longest_order; j++) {
6518 secfile_insert_int(saving->file, -1, "%s.action_vec,%d", buf, j);
6519 }
6520
6521 secfile_insert_int_vec(saving->file, tgt_vec, len,
6522 "%s.tgt_vec", buf);
6523 /* Fill in dummy values for order targets so the registry will save
6524 * the unit table in a tabular format. */
6525 for (j = last_order; j < longest_order; j++) {
6526 secfile_insert_int(saving->file, NO_TARGET, "%s.tgt_vec,%d", buf, j);
6527 }
6528
6529 secfile_insert_int_vec(saving->file, sub_tgt_vec, len,
6530 "%s.sub_tgt_vec", buf);
6531 /* Fill in dummy values for order targets so the registry will save
6532 * the unit table in a tabular format. */
6533 for (j = last_order; j < longest_order; j++) {
6534 secfile_insert_int(saving->file, -1, "%s.sub_tgt_vec,%d", buf, j);
6535 }
6536 } else {
6537
6538 /* Put all the same fields into the savegame - otherwise the
6539 * registry code can't correctly use a tabular format and the
6540 * savegame will be bigger. */
6541 secfile_insert_int(saving->file, 0, "%s.orders_length", buf);
6542 secfile_insert_int(saving->file, 0, "%s.orders_index", buf);
6543 secfile_insert_bool(saving->file, FALSE, "%s.orders_repeat", buf);
6544 secfile_insert_bool(saving->file, FALSE, "%s.orders_vigilant", buf);
6545 secfile_insert_str(saving->file, "-", "%s.orders_list", buf);
6546 secfile_insert_str(saving->file, "-", "%s.dir_list", buf);
6547 secfile_insert_str(saving->file, "-", "%s.activity_list", buf);
6548
6549 /* Fill in dummy values for order targets so the registry will save
6550 * the unit table in a tabular format. */
6551
6552 /* The start of a vector has no number. */
6553 secfile_insert_int(saving->file, -1, "%s.action_vec", buf);
6554 for (j = 1; j < longest_order; j++) {
6555 secfile_insert_int(saving->file, -1, "%s.action_vec,%d", buf, j);
6556 }
6557
6558 /* The start of a vector has no number. */
6559 secfile_insert_int(saving->file, NO_TARGET, "%s.tgt_vec", buf);
6560 for (j = 1; j < longest_order; j++) {
6561 secfile_insert_int(saving->file, NO_TARGET, "%s.tgt_vec,%d", buf, j);
6562 }
6563
6564 /* The start of a vector has no number. */
6565 secfile_insert_int(saving->file, -1, "%s.sub_tgt_vec", buf);
6566 for (j = 1; j < longest_order; j++) {
6567 secfile_insert_int(saving->file, -1, "%s.sub_tgt_vec,%d", buf, j);
6568 }
6569 }
6570
6571 i++;
6573}
6574
6575/************************************************************************/
6578static void sg_load_player_attributes(struct loaddata *loading,
6579 struct player *plr)
6580{
6581 int plrno = player_number(plr);
6582
6583 /* Check status and return if not OK (sg_success FALSE). */
6584 sg_check_ret();
6585
6586 /* Toss any existing attribute_block (should not exist) */
6587 if (plr->attribute_block.data) {
6588 free(plr->attribute_block.data);
6589 plr->attribute_block.data = NULL;
6590 }
6591
6592 /* This is a big heap of opaque data for the client, check everything! */
6594 loading->file, 0, "player%d.attribute_v2_block_length", plrno);
6595
6596 if (0 > plr->attribute_block.length) {
6597 log_sg("player%d.attribute_v2_block_length=%d too small", plrno,
6598 plr->attribute_block.length);
6599 plr->attribute_block.length = 0;
6600 } else if (MAX_ATTRIBUTE_BLOCK < plr->attribute_block.length) {
6601 log_sg("player%d.attribute_v2_block_length=%d too big (max %d)",
6603 plr->attribute_block.length = 0;
6604 } else if (0 < plr->attribute_block.length) {
6605 int part_nr, parts;
6606 int quoted_length;
6607 char *quoted;
6608#ifndef FREECIV_NDEBUG
6609 size_t actual_length;
6610#endif
6611
6613 secfile_lookup_int(loading->file, &quoted_length,
6614 "player%d.attribute_v2_block_length_quoted",
6615 plrno), "%s", secfile_error());
6617 secfile_lookup_int(loading->file, &parts,
6618 "player%d.attribute_v2_block_parts", plrno),
6619 "%s", secfile_error());
6620
6621 quoted = fc_malloc(quoted_length + 1);
6622 quoted[0] = '\0';
6624 for (part_nr = 0; part_nr < parts; part_nr++) {
6625 const char *current =
6626 secfile_lookup_str(loading->file,
6627 "player%d.attribute_v2_block_data.part%d",
6628 plrno, part_nr);
6629 if (!current) {
6630 log_sg("attribute_v2_block_parts=%d actual=%d", parts, part_nr);
6631 break;
6632 }
6633 log_debug("attribute_v2_block_length_quoted=%d"
6634 " have=" SIZE_T_PRINTF " part=" SIZE_T_PRINTF,
6635 quoted_length, strlen(quoted), strlen(current));
6636 fc_assert(strlen(quoted) + strlen(current) <= quoted_length);
6637 strcat(quoted, current);
6638 }
6639 fc_assert_msg(quoted_length == strlen(quoted),
6640 "attribute_v2_block_length_quoted=%d"
6641 " actual=" SIZE_T_PRINTF,
6642 quoted_length, strlen(quoted));
6643
6644#ifndef FREECIV_NDEBUG
6645 actual_length =
6646#endif
6647 unquote_block(quoted,
6648 plr->attribute_block.data,
6649 plr->attribute_block.length);
6650 fc_assert(actual_length == plr->attribute_block.length);
6651 free(quoted);
6652 }
6653}
6654
6655/************************************************************************/
6658static void sg_save_player_attributes(struct savedata *saving,
6659 struct player *plr)
6660{
6661 int plrno = player_number(plr);
6662
6663 /* Check status and return if not OK (sg_success FALSE). */
6664 sg_check_ret();
6665
6666 /* This is a big heap of opaque data from the client. Although the binary
6667 * format is not user editable, keep the lines short enough for debugging,
6668 * and hope that data compression will keep the file a reasonable size.
6669 * Note that the "quoted" format is a multiple of 3.
6670 */
6671#define PART_SIZE (3*256)
6672#define PART_ADJUST (3)
6673 if (plr->attribute_block.data) {
6674 char part[PART_SIZE + PART_ADJUST];
6675 int parts;
6676 int current_part_nr;
6677 char *quoted = quote_block(plr->attribute_block.data,
6678 plr->attribute_block.length);
6679 char *quoted_at = strchr(quoted, ':');
6680 size_t bytes_left = strlen(quoted);
6681 size_t bytes_at_colon = 1 + (quoted_at - quoted);
6682 size_t bytes_adjust = bytes_at_colon % PART_ADJUST;
6683
6685 "player%d.attribute_v2_block_length", plrno);
6686 secfile_insert_int(saving->file, bytes_left,
6687 "player%d.attribute_v2_block_length_quoted", plrno);
6688
6689 /* Try to wring some compression efficiencies out of the "quoted" format.
6690 * The first line has a variable length decimal, mis-aligning triples.
6691 */
6692 if ((bytes_left - bytes_adjust) > PART_SIZE) {
6693 /* first line can be longer */
6694 parts = 1 + (bytes_left - bytes_adjust - 1) / PART_SIZE;
6695 } else {
6696 parts = 1;
6697 }
6698
6699 secfile_insert_int(saving->file, parts,
6700 "player%d.attribute_v2_block_parts", plrno);
6701
6702 if (parts > 1) {
6703 size_t size_of_current_part = PART_SIZE + bytes_adjust;
6704
6705 /* first line can be longer */
6706 memcpy(part, quoted, size_of_current_part);
6707 part[size_of_current_part] = '\0';
6708 secfile_insert_str(saving->file, part,
6709 "player%d.attribute_v2_block_data.part%d",
6710 plrno, 0);
6711 bytes_left -= size_of_current_part;
6712 quoted_at = &quoted[size_of_current_part];
6713 current_part_nr = 1;
6714 } else {
6715 quoted_at = quoted;
6716 current_part_nr = 0;
6717 }
6718
6719 for (; current_part_nr < parts; current_part_nr++) {
6720 size_t size_of_current_part = MIN(bytes_left, PART_SIZE);
6721
6722 memcpy(part, quoted_at, size_of_current_part);
6723 part[size_of_current_part] = '\0';
6724 secfile_insert_str(saving->file, part,
6725 "player%d.attribute_v2_block_data.part%d",
6726 plrno,
6727 current_part_nr);
6728 bytes_left -= size_of_current_part;
6729 quoted_at = &quoted_at[size_of_current_part];
6730 }
6731 fc_assert(bytes_left == 0);
6732 free(quoted);
6733 }
6734#undef PART_ADJUST
6735#undef PART_SIZE
6736}
6737
6738/************************************************************************/
6741static void sg_load_player_vision(struct loaddata *loading,
6742 struct player *plr)
6743{
6744 int plrno = player_number(plr);
6745 int total_ncities =
6746 secfile_lookup_int_default(loading->file, -1,
6747 "player%d.dc_total", plrno);
6748 int i;
6749 bool someone_alive = FALSE;
6750
6751 /* Check status and return if not OK (sg_success FALSE). */
6752 sg_check_ret();
6753
6754 if (game.server.revealmap & REVEAL_MAP_DEAD) {
6755 player_list_iterate(team_members(plr->team), pteam_member) {
6756 if (pteam_member->is_alive) {
6757 someone_alive = TRUE;
6758 break;
6759 }
6761
6762 if (!someone_alive) {
6763 /* Reveal all for completely dead teams. */
6765 }
6766 }
6767
6768 if (-1 == total_ncities
6769 || !game.info.fogofwar
6771 "game.save_private_map")) {
6772 /* We have:
6773 * - a dead player;
6774 * - fogged cities are not saved for any reason;
6775 * - a savegame with fog of war turned off;
6776 * - or game.save_private_map is not set to FALSE in the scenario /
6777 * savegame. The players private knowledge is set to be what they could
6778 * see without fog of war. */
6779 whole_map_iterate(&(wld.map), ptile) {
6780 if (map_is_known(ptile, plr)) {
6781 struct city *pcity = tile_city(ptile);
6782
6783 update_player_tile_last_seen(plr, ptile);
6784 update_player_tile_knowledge(plr, ptile);
6785
6786 if (NULL != pcity) {
6787 update_dumb_city(plr, pcity);
6788 }
6789 }
6791
6792 /* Nothing more to do; */
6793 return;
6794 }
6795
6796 /* Load player map (terrain). */
6797 LOAD_MAP_CHAR(ch, ptile,
6798 map_get_player_tile(ptile, plr)->terrain
6799 = char2terrain(ch), loading->file,
6800 "player%d.map_t%04d", plrno);
6801
6802 /* Load player map (extras). */
6803 halfbyte_iterate_extras(j, loading->extra.size) {
6804 LOAD_MAP_CHAR(ch, ptile,
6806 ch, loading->extra.order + 4 * j),
6807 loading->file, "player%d.map_e%02d_%04d", plrno, j);
6809
6810 whole_map_iterate(&(wld.map), ptile) {
6811 struct player_tile *plrtile = map_get_player_tile(ptile, plr);
6812
6813 extra_type_by_cause_iterate(EC_RESOURCE, pres) {
6814 if (BV_ISSET(plrtile->extras, extra_number(pres))) {
6815 plrtile->resource = pres;
6816 if (!terrain_has_resource(plrtile->terrain, pres)) {
6817 BV_CLR(plrtile->extras, extra_number(pres));
6818 }
6819 }
6822
6824 /* Load player map (border). */
6825 int x, y;
6826
6827 for (y = 0; y < wld.map.ysize; y++) {
6828 const char *buffer
6829 = secfile_lookup_str(loading->file, "player%d.map_owner%04d",
6830 plrno, y);
6831 const char *buffer2
6832 = secfile_lookup_str(loading->file, "player%d.extras_owner%04d",
6833 plrno, y);
6834 const char *ptr = buffer;
6835 const char *ptr2 = buffer2;
6836
6837 sg_failure_ret(NULL != buffer,
6838 "Savegame corrupt - map line %d not found.", y);
6839 for (x = 0; x < wld.map.xsize; x++) {
6840 char token[TOKEN_SIZE];
6841 char token2[TOKEN_SIZE];
6842 int number;
6843 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
6844
6845 scanin(&ptr, ",", token, sizeof(token));
6846 sg_failure_ret('\0' != token[0],
6847 "Savegame corrupt - map size not correct.");
6848 if (strcmp(token, "-") == 0) {
6849 map_get_player_tile(ptile, plr)->owner = NULL;
6850 } else {
6851 sg_failure_ret(str_to_int(token, &number),
6852 "Savegame corrupt - got tile owner=%s in (%d, %d).",
6853 token, x, y);
6854 map_get_player_tile(ptile, plr)->owner = player_by_number(number);
6855 }
6856
6857 scanin(&ptr2, ",", token2, sizeof(token2));
6858 sg_failure_ret('\0' != token2[0],
6859 "Savegame corrupt - map size not correct.");
6860 if (strcmp(token2, "-") == 0) {
6861 map_get_player_tile(ptile, plr)->extras_owner = NULL;
6862 } else {
6863 sg_failure_ret(str_to_int(token2, &number),
6864 "Savegame corrupt - got extras owner=%s in (%d, %d).",
6865 token, x, y);
6866 map_get_player_tile(ptile, plr)->extras_owner = player_by_number(number);
6867 }
6868 }
6869 }
6870 }
6871
6872 /* Load player map (update time). */
6873 for (i = 0; i < 4; i++) {
6874 /* put 4-bit segments of 16-bit "updated" field */
6875 if (i == 0) {
6876 LOAD_MAP_CHAR(ch, ptile,
6877 map_get_player_tile(ptile, plr)->last_updated
6878 = ascii_hex2bin(ch, i),
6879 loading->file, "player%d.map_u%02d_%04d", plrno, i);
6880 } else {
6881 LOAD_MAP_CHAR(ch, ptile,
6882 map_get_player_tile(ptile, plr)->last_updated
6883 |= ascii_hex2bin(ch, i),
6884 loading->file, "player%d.map_u%02d_%04d", plrno, i);
6885 }
6886 }
6887
6888 /* Load player map known cities. */
6889 for (i = 0; i < total_ncities; i++) {
6890 struct vision_site *pdcity;
6891 char buf[32];
6892 fc_snprintf(buf, sizeof(buf), "player%d.dc%d", plrno, i);
6893
6894 pdcity = vision_site_new(0, NULL, NULL);
6895 if (sg_load_player_vision_city(loading, plr, pdcity, buf)) {
6897 pdcity);
6899 } else {
6900 /* Error loading the data. */
6901 log_sg("Skipping seen city %d for player %d.", i, plrno);
6902 if (pdcity != NULL) {
6903 vision_site_destroy(pdcity);
6904 }
6905 }
6906 }
6907
6908 /* Repair inconsistent player maps. */
6909 whole_map_iterate(&(wld.map), ptile) {
6910 if (map_is_known_and_seen(ptile, plr, V_MAIN)) {
6911 struct city *pcity = tile_city(ptile);
6912
6913 update_player_tile_knowledge(plr, ptile);
6914 reality_check_city(plr, ptile);
6915
6916 if (NULL != pcity) {
6917 update_dumb_city(plr, pcity);
6918 }
6919 } else if (!game.server.foggedborders && map_is_known(ptile, plr)) {
6920 /* Non fogged borders aren't loaded. See hrm Bug #879084 */
6921 struct player_tile *plrtile = map_get_player_tile(ptile, plr);
6922
6923 plrtile->owner = tile_owner(ptile);
6924 }
6926}
6927
6928/************************************************************************/
6931static bool sg_load_player_vision_city(struct loaddata *loading,
6932 struct player *plr,
6933 struct vision_site *pdcity,
6934 const char *citystr)
6935{
6936 const char *str;
6937 int i, id, size;
6938 citizens city_size;
6939 int nat_x, nat_y;
6940 const char *stylename;
6941 enum capital_type cap;
6942 const char *vname;
6943
6944 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_x, "%s.x",
6945 citystr),
6946 FALSE, "%s", secfile_error());
6947 sg_warn_ret_val(secfile_lookup_int(loading->file, &nat_y, "%s.y",
6948 citystr),
6949 FALSE, "%s", secfile_error());
6950 pdcity->location = native_pos_to_tile(&(wld.map), nat_x, nat_y);
6951 sg_warn_ret_val(NULL != pdcity->location, FALSE,
6952 "%s invalid tile (%d,%d)", citystr, nat_x, nat_y);
6953
6954 sg_warn_ret_val(secfile_lookup_int(loading->file, &id, "%s.owner",
6955 citystr),
6956 FALSE, "%s", secfile_error());
6957 pdcity->owner = player_by_number(id);
6958 sg_warn_ret_val(NULL != pdcity->owner, FALSE,
6959 "%s has invalid owner (%d); skipping.", citystr, id);
6960
6962 "%s.id", citystr),
6963 FALSE, "%s", secfile_error());
6964 sg_warn_ret_val(IDENTITY_NUMBER_ZERO < pdcity->identity, FALSE,
6965 "%s has invalid id (%d); skipping.", citystr, id);
6966
6968 "%s.size", citystr),
6969 FALSE, "%s", secfile_error());
6970 city_size = (citizens)size; /* set the correct type */
6971 sg_warn_ret_val(size == (int)city_size, FALSE,
6972 "Invalid city size: %d; set to %d.", size, city_size);
6973 vision_site_size_set(pdcity, city_size);
6974
6975 /* Initialise list of improvements */
6976 BV_CLR_ALL(pdcity->improvements);
6977 str = secfile_lookup_str(loading->file, "%s.improvements", citystr);
6978 sg_warn_ret_val(str != NULL, FALSE, "%s", secfile_error());
6979 sg_warn_ret_val(strlen(str) == loading->improvement.size, FALSE,
6980 "Invalid length of '%s.improvements' ("
6981 SIZE_T_PRINTF " ~= " SIZE_T_PRINTF ").",
6982 citystr, strlen(str), loading->improvement.size);
6983 for (i = 0; i < loading->improvement.size; i++) {
6984 sg_warn_ret_val(str[i] == '1' || str[i] == '0', FALSE,
6985 "Undefined value '%c' within '%s.improvements'.",
6986 str[i], citystr)
6987
6988 if (str[i] == '1') {
6989 struct impr_type *pimprove =
6991 if (pimprove) {
6992 BV_SET(pdcity->improvements, improvement_index(pimprove));
6993 }
6994 }
6995 }
6996
6997 vname = secfile_lookup_str_default(loading->file, NULL,
6998 "%s.name", citystr);
6999
7000 if (vname != NULL) {
7001 pdcity->name = fc_strdup(vname);
7002 }
7003
7004 pdcity->occupied = secfile_lookup_bool_default(loading->file, FALSE,
7005 "%s.occupied", citystr);
7006 pdcity->walls = secfile_lookup_bool_default(loading->file, FALSE,
7007 "%s.walls", citystr);
7008 pdcity->happy = secfile_lookup_bool_default(loading->file, FALSE,
7009 "%s.happy", citystr);
7010 pdcity->unhappy = secfile_lookup_bool_default(loading->file, FALSE,
7011 "%s.unhappy", citystr);
7012 stylename = secfile_lookup_str_default(loading->file, NULL,
7013 "%s.style", citystr);
7014 if (stylename != NULL) {
7015 pdcity->style = city_style_by_rule_name(stylename);
7016 } else {
7017 pdcity->style = 0;
7018 }
7019 if (pdcity->style < 0) {
7020 pdcity->style = 0;
7021 }
7022
7023 pdcity->city_image = secfile_lookup_int_default(loading->file, -100,
7024 "%s.city_image", citystr);
7025
7026 cap = capital_type_by_name(secfile_lookup_str_default(loading->file, NULL,
7027 "%s.capital", citystr),
7029
7030 if (capital_type_is_valid(cap)) {
7031 pdcity->capital = cap;
7032 } else {
7033 pdcity->capital = CAPITAL_NOT;
7034 }
7035
7036 return TRUE;
7037}
7038
7039/************************************************************************/
7042static void sg_save_player_vision(struct savedata *saving,
7043 struct player *plr)
7044{
7045 int i, plrno = player_number(plr);
7046
7047 /* Check status and return if not OK (sg_success FALSE). */
7048 sg_check_ret();
7049
7051 /* The player can see all, there's no reason to save the private map. */
7052 return;
7053 }
7054
7055 /* Save the map (terrain). */
7056 SAVE_MAP_CHAR(ptile,
7058 saving->file, "player%d.map_t%04d", plrno);
7059
7061 /* Save the map (borders). */
7062 int x, y;
7063
7064 for (y = 0; y < wld.map.ysize; y++) {
7065 char line[wld.map.xsize * TOKEN_SIZE];
7066
7067 line[0] = '\0';
7068 for (x = 0; x < wld.map.xsize; x++) {
7069 char token[TOKEN_SIZE];
7070 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
7071 struct player_tile *plrtile = map_get_player_tile(ptile, plr);
7072
7073 if (plrtile == NULL || plrtile->owner == NULL) {
7074 strcpy(token, "-");
7075 } else {
7076 fc_snprintf(token, sizeof(token), "%d",
7077 player_number(plrtile->owner));
7078 }
7079 strcat(line, token);
7080 if (x < wld.map.xsize) {
7081 strcat(line, ",");
7082 }
7083 }
7084 secfile_insert_str(saving->file, line, "player%d.map_owner%04d",
7085 plrno, y);
7086 }
7087
7088 for (y = 0; y < wld.map.ysize; y++) {
7089 char line[wld.map.xsize * TOKEN_SIZE];
7090
7091 line[0] = '\0';
7092 for (x = 0; x < wld.map.xsize; x++) {
7093 char token[TOKEN_SIZE];
7094 struct tile *ptile = native_pos_to_tile(&(wld.map), x, y);
7095 struct player_tile *plrtile = map_get_player_tile(ptile, plr);
7096
7097 if (plrtile == NULL || plrtile->extras_owner == NULL) {
7098 strcpy(token, "-");
7099 } else {
7100 fc_snprintf(token, sizeof(token), "%d",
7101 player_number(plrtile->extras_owner));
7102 }
7103 strcat(line, token);
7104 if (x < wld.map.xsize) {
7105 strcat(line, ",");
7106 }
7107 }
7108 secfile_insert_str(saving->file, line, "player%d.extras_owner%04d",
7109 plrno, y);
7110 }
7111 }
7112
7113 /* Save the map (extras). */
7115 int mod[4];
7116 int l;
7117
7118 for (l = 0; l < 4; l++) {
7119 if (4 * j + 1 > game.control.num_extra_types) {
7120 mod[l] = -1;
7121 } else {
7122 mod[l] = 4 * j + l;
7123 }
7124 }
7125
7126 SAVE_MAP_CHAR(ptile,
7128 map_get_player_tile(ptile, plr)->resource,
7129 mod),
7130 saving->file, "player%d.map_e%02d_%04d", plrno, j);
7132
7133 /* Save the map (update time). */
7134 for (i = 0; i < 4; i++) {
7135 /* put 4-bit segments of 16-bit "updated" field */
7136 SAVE_MAP_CHAR(ptile,
7138 map_get_player_tile(ptile, plr)->last_updated, i),
7139 saving->file, "player%d.map_u%02d_%04d", plrno, i);
7140 }
7141
7142 /* Save known cities. */
7143 i = 0;
7144 whole_map_iterate(&(wld.map), ptile) {
7145 struct vision_site *pdcity = map_get_player_city(ptile, plr);
7146 char impr_buf[B_LAST + 1];
7147 char buf[32];
7148
7149 fc_snprintf(buf, sizeof(buf), "player%d.dc%d", plrno, i);
7150
7151 if (NULL != pdcity && plr != vision_site_owner(pdcity)) {
7152 int nat_x, nat_y;
7153
7155 secfile_insert_int(saving->file, nat_y, "%s.y", buf);
7156 secfile_insert_int(saving->file, nat_x, "%s.x", buf);
7157
7158 secfile_insert_int(saving->file, pdcity->identity, "%s.id", buf);
7160 "%s.owner", buf);
7161
7163 "%s.size", buf);
7164 secfile_insert_bool(saving->file, pdcity->occupied,
7165 "%s.occupied", buf);
7166 secfile_insert_bool(saving->file, pdcity->walls, "%s.walls", buf);
7167 secfile_insert_bool(saving->file, pdcity->happy, "%s.happy", buf);
7168 secfile_insert_bool(saving->file, pdcity->unhappy, "%s.unhappy", buf);
7170 "%s.style", buf);
7171 secfile_insert_int(saving->file, pdcity->city_image, "%s.city_image", buf);
7172 secfile_insert_str(saving->file, capital_type_name(pdcity->capital),
7173 "%s.capital", buf);
7174
7175 /* Save improvement list as bitvector. Note that improvement order
7176 * is saved in savefile.improvement.order. */
7177 improvement_iterate(pimprove) {
7178 impr_buf[improvement_index(pimprove)]
7179 = BV_ISSET(pdcity->improvements, improvement_index(pimprove))
7180 ? '1' : '0';
7182 impr_buf[improvement_count()] = '\0';
7183 sg_failure_ret(strlen(impr_buf) < sizeof(impr_buf),
7184 "Invalid size of the improvement vector (%s.improvements: "
7185 SIZE_T_PRINTF " < " SIZE_T_PRINTF" ).",
7186 buf, strlen(impr_buf), sizeof(impr_buf));
7187 secfile_insert_str(saving->file, impr_buf, "%s.improvements", buf);
7188 if (pdcity->name != NULL) {
7189 secfile_insert_str(saving->file, pdcity->name, "%s.name", buf);
7190 }
7191
7192 i++;
7193 }
7195
7196 secfile_insert_int(saving->file, i, "player%d.dc_total", plrno);
7197}
7198
7199/* =======================================================================
7200 * Load / save the researches.
7201 * ======================================================================= */
7202
7203/************************************************************************/
7206static void sg_load_researches(struct loaddata *loading)
7207{
7208 struct research *presearch;
7209 int count;
7210 int number;
7211 const char *str;
7212 int i, j;
7213 int *vlist_research;
7214
7215 vlist_research = NULL;
7216 /* Check status and return if not OK (sg_success FALSE). */
7217 sg_check_ret();
7218
7219 /* Initialize all researches. */
7220 researches_iterate(pinitres) {
7221 init_tech(pinitres, FALSE);
7223
7224 /* May be unsaved (e.g. scenario case). */
7225 count = secfile_lookup_int_default(loading->file, 0, "research.count");
7226 for (i = 0; i < count; i++) {
7227 sg_failure_ret(secfile_lookup_int(loading->file, &number,
7228 "research.r%d.number", i),
7229 "%s", secfile_error());
7230 presearch = research_by_number(number);
7231 sg_failure_ret(presearch != NULL,
7232 "Invalid research number %d in 'research.r%d.number'",
7233 number, i);
7234
7235 presearch->tech_goal = technology_load(loading->file,
7236 "research.r%d.goal", i);
7238 &presearch->techs_researched,
7239 "research.r%d.techs", i),
7240 "%s", secfile_error());
7242 &presearch->future_tech,
7243 "research.r%d.futuretech", i),
7244 "%s", secfile_error());
7246 &presearch->bulbs_researched,
7247 "research.r%d.bulbs", i),
7248 "%s", secfile_error());
7250 &presearch->bulbs_researching_saved,
7251 "research.r%d.bulbs_before", i),
7252 "%s", secfile_error());
7253 presearch->researching_saved = technology_load(loading->file,
7254 "research.r%d.saved", i);
7255 presearch->researching = technology_load(loading->file,
7256 "research.r%d.now", i);
7258 &presearch->got_tech,
7259 "research.r%d.got_tech", i),
7260 "%s", secfile_error());
7261
7262 /* Older savegames (3.0 betas) had a bug that got_tech_multi was not saved.
7263 * Have to live with such savegames, so can't make it an error if value
7264 * is not found from the savegame. */
7266 "research.r%d.got_tech_multi",
7267 i);
7268
7269 str = secfile_lookup_str(loading->file, "research.r%d.done", i);
7270 sg_failure_ret(str != NULL, "%s", secfile_error());
7271 sg_failure_ret(strlen(str) == loading->technology.size,
7272 "Invalid length of 'research.r%d.done' ("
7273 SIZE_T_PRINTF " ~= " SIZE_T_PRINTF ").",
7274 i, strlen(str), loading->technology.size);
7275 for (j = 0; j < loading->technology.size; j++) {
7276 sg_failure_ret(str[j] == '1' || str[j] == '0',
7277 "Undefined value '%c' within 'research.r%d.done'.",
7278 str[j], i);
7279
7280 if (str[j] == '1') {
7281 struct advance *padvance =
7283
7284 if (padvance) {
7285 research_invention_set(presearch, advance_number(padvance),
7286 TECH_KNOWN);
7287 }
7288 }
7289 }
7290
7292 size_t count_res;
7293 int tn;
7294
7295 vlist_research = secfile_lookup_int_vec(loading->file, &count_res,
7296 "research.r%d.vbs", i);
7297
7298 for (tn = 0; tn < count_res; tn++) {
7299 struct advance *padvance = advance_by_rule_name(loading->technology.order[tn]);
7300
7301 if (padvance != NULL) {
7302 presearch->inventions[advance_index(padvance)].bulbs_researched_saved
7303 = vlist_research[tn];
7304 }
7305 }
7306 }
7307 }
7308
7309 /* In case of tech_leakage, we can update research only after all the
7310 * researches have been loaded */
7311 researches_iterate(pupres) {
7312 research_update(pupres);
7314}
7315
7316/************************************************************************/
7319static void sg_save_researches(struct savedata *saving)
7320{
7321 char invs[A_LAST];
7322 int i = 0;
7323 int *vlist_research;
7324
7325 vlist_research = NULL;
7326 /* Check status and return if not OK (sg_success FALSE). */
7327 sg_check_ret();
7328
7329 if (saving->save_players) {
7330 researches_iterate(presearch) {
7331 secfile_insert_int(saving->file, research_number(presearch),
7332 "research.r%d.number", i);
7333 technology_save(saving->file, "research.r%d.goal",
7334 i, presearch->tech_goal);
7335 secfile_insert_int(saving->file, presearch->techs_researched,
7336 "research.r%d.techs", i);
7337 secfile_insert_int(saving->file, presearch->future_tech,
7338 "research.r%d.futuretech", i);
7339 secfile_insert_int(saving->file, presearch->bulbs_researching_saved,
7340 "research.r%d.bulbs_before", i);
7342 vlist_research = fc_calloc(game.control.num_tech_types, sizeof(int));
7344 vlist_research[j] = presearch->inventions[j].bulbs_researched_saved;
7346 secfile_insert_int_vec(saving->file, vlist_research,
7348 "research.r%d.vbs", i);
7349 if (vlist_research) {
7350 free(vlist_research);
7351 }
7352 }
7353 technology_save(saving->file, "research.r%d.saved",
7354 i, presearch->researching_saved);
7355 secfile_insert_int(saving->file, presearch->bulbs_researched,
7356 "research.r%d.bulbs", i);
7357 technology_save(saving->file, "research.r%d.now",
7358 i, presearch->researching);
7359 secfile_insert_bool(saving->file, presearch->got_tech,
7360 "research.r%d.got_tech", i);
7361 secfile_insert_bool(saving->file, presearch->got_tech_multi,
7362 "research.r%d.got_tech_multi", i);
7363 /* Save technology lists as bytevector. Note that technology order is
7364 * saved in savefile.technology.order */
7365 advance_index_iterate(A_NONE, tech_id) {
7366 invs[tech_id] = (valid_advance_by_number(tech_id) != NULL
7367 && research_invention_state(presearch, tech_id)
7368 == TECH_KNOWN ? '1' : '0');
7370 invs[game.control.num_tech_types] = '\0';
7371 secfile_insert_str(saving->file, invs, "research.r%d.done", i);
7372 i++;
7374 secfile_insert_int(saving->file, i, "research.count");
7375 }
7376}
7377
7378/* =======================================================================
7379 * Load / save the event cache. Should be the last thing to do.
7380 * ======================================================================= */
7381
7382/************************************************************************/
7385static void sg_load_event_cache(struct loaddata *loading)
7386{
7387 /* Check status and return if not OK (sg_success FALSE). */
7388 sg_check_ret();
7389
7390 event_cache_load(loading->file, "event_cache");
7391}
7392
7393/************************************************************************/
7396static void sg_save_event_cache(struct savedata *saving)
7397{
7398 /* Check status and return if not OK (sg_success FALSE). */
7399 sg_check_ret();
7400
7401 if (saving->scenario) {
7402 /* Do _not_ save events in a scenario. */
7403 return;
7404 }
7405
7406 event_cache_save(saving->file, "event_cache");
7407}
7408
7409/* =======================================================================
7410 * Load / save the open treaties
7411 * ======================================================================= */
7412
7413/************************************************************************/
7416static void sg_load_treaties(struct loaddata *loading)
7417{
7418 int tidx;
7419 const char *plr0;
7420 struct treaty_list *treaties = get_all_treaties();
7421
7422 /* Check status and return if not OK (sg_success FALSE). */
7423 sg_check_ret();
7424
7425 for (tidx = 0; (plr0 = secfile_lookup_str_default(loading->file, NULL,
7426 "treaty%d.plr0", tidx)) != NULL ;
7427 tidx++) {
7428 const char *plr1;
7429 const char *ct;
7430 int cidx;
7431 struct player *p0, *p1;
7432
7433 plr1 = secfile_lookup_str(loading->file, "treaty%d.plr1", tidx);
7434
7435 p0 = player_by_name(plr0);
7436 p1 = player_by_name(plr1);
7437
7438 if (p0 == NULL || p1 == NULL) {
7439 log_error("Treaty between unknown players %s and %s", plr0, plr1);
7440 } else {
7441 struct Treaty *ptreaty = fc_malloc(sizeof(*ptreaty));
7442
7443 init_treaty(ptreaty, p0, p1);
7444 treaty_list_prepend(treaties, ptreaty);
7445
7446 for (cidx = 0; (ct = secfile_lookup_str_default(loading->file, NULL,
7447 "treaty%d.clause%d.type",
7448 tidx, cidx)) != NULL ;
7449 cidx++ ) {
7450 enum clause_type type = clause_type_by_name(ct, fc_strcasecmp);
7451 const char *plrx;
7452
7453 if (!clause_type_is_valid(type)) {
7454 log_error("Invalid clause type \"%s\"", ct);
7455 } else {
7456 struct player *pgiver = NULL;
7457
7458 plrx = secfile_lookup_str(loading->file, "treaty%d.clause%d.from",
7459 tidx, cidx);
7460
7461 if (!fc_strcasecmp(plrx, plr0)) {
7462 pgiver = p0;
7463 } else if (!fc_strcasecmp(plrx, plr1)) {
7464 pgiver = p1;
7465 } else {
7466 log_error("Clause giver %s is not participant of the treaty"
7467 "between %s and %s", plrx, plr0, plr1);
7468 }
7469
7470 if (pgiver != NULL) {
7471 int value;
7472
7473 value = secfile_lookup_int_default(loading->file, 0,
7474 "treaty%d.clause%d.value",
7475 tidx, cidx);
7476
7477 add_clause(ptreaty, pgiver, type, value, NULL);
7478 }
7479 }
7480 }
7481
7482 /* These must be after clauses have been added so that acceptance
7483 * does not get cleared by what seems like changes to the treaty. */
7484 ptreaty->accept0 = secfile_lookup_bool_default(loading->file, FALSE,
7485 "treaty%d.accept0", tidx);
7486 ptreaty->accept1 = secfile_lookup_bool_default(loading->file, FALSE,
7487 "treaty%d.accept1", tidx);
7488 }
7489 }
7490}
7491
7492/************************************************************************/
7495static void sg_save_treaties(struct savedata *saving)
7496{
7497 struct treaty_list *treaties = get_all_treaties();
7498 int tidx = 0;
7499
7501 char tpath[512];
7502 int cidx = 0;
7503
7504 fc_snprintf(tpath, sizeof(tpath), "treaty%d", tidx++);
7505
7506 secfile_insert_str(saving->file, player_name(ptr->plr0), "%s.plr0", tpath);
7507 secfile_insert_str(saving->file, player_name(ptr->plr1), "%s.plr1", tpath);
7508 secfile_insert_bool(saving->file, ptr->accept0, "%s.accept0", tpath);
7509 secfile_insert_bool(saving->file, ptr->accept1, "%s.accept1", tpath);
7510
7511 clause_list_iterate(ptr->clauses, pclaus) {
7512 char cpath[512];
7513
7514 fc_snprintf(cpath, sizeof(cpath), "%s.clause%d", tpath, cidx++);
7515
7516 secfile_insert_str(saving->file, clause_type_name(pclaus->type), "%s.type", cpath);
7517 secfile_insert_str(saving->file, player_name(pclaus->from), "%s.from", cpath);
7518 secfile_insert_int(saving->file, pclaus->value, "%s.value", cpath);
7521}
7522
7523/* =======================================================================
7524 * Load / save the history report
7525 * ======================================================================= */
7526
7527/************************************************************************/
7530static void sg_load_history(struct loaddata *loading)
7531{
7532 struct history_report *hist = history_report_get();
7533 int turn;
7534
7535 /* Check status and return if not OK (sg_success FALSE). */
7536 sg_check_ret();
7537
7538 turn = secfile_lookup_int_default(loading->file, -2, "history.turn");
7539
7540 if (turn != -2) {
7541 hist->turn = turn;
7542 }
7543
7544 if (turn + 1 >= game.info.turn) {
7545 const char *str;
7546
7547 str = secfile_lookup_str(loading->file, "history.title");
7548 sg_failure_ret(str != NULL, "%s", secfile_error());
7549 sz_strlcpy(hist->title, str);
7550 str = secfile_lookup_str(loading->file, "history.body");
7551 sg_failure_ret(str != NULL, "%s", secfile_error());
7552 sz_strlcpy(hist->body, str);
7553 }
7554}
7555
7556/************************************************************************/
7559static void sg_save_history(struct savedata *saving)
7560{
7561 struct history_report *hist = history_report_get();
7562
7563 secfile_insert_int(saving->file, hist->turn, "history.turn");
7564
7565 if (hist->turn + 1 >= game.info.turn) {
7566 secfile_insert_str(saving->file, hist->title, "history.title");
7567 secfile_insert_str(saving->file, hist->body, "history.body");
7568 }
7569}
7570
7571/* =======================================================================
7572 * Load / save the mapimg definitions.
7573 * ======================================================================= */
7574
7575/************************************************************************/
7578static void sg_load_mapimg(struct loaddata *loading)
7579{
7580 int mapdef_count, i;
7581
7582 /* Check status and return if not OK (sg_success FALSE). */
7583 sg_check_ret();
7584
7585 /* Clear all defined map images. */
7586 while (mapimg_count() > 0) {
7587 mapimg_delete(0);
7588 }
7589
7590 mapdef_count = secfile_lookup_int_default(loading->file, 0,
7591 "mapimg.count");
7592 log_verbose("Saved map image definitions: %d.", mapdef_count);
7593
7594 if (0 >= mapdef_count) {
7595 return;
7596 }
7597
7598 for (i = 0; i < mapdef_count; i++) {
7599 const char *p;
7600
7601 p = secfile_lookup_str(loading->file, "mapimg.mapdef%d", i);
7602 if (NULL == p) {
7603 log_verbose("[Mapimg %4d] Missing definition.", i);
7604 continue;
7605 }
7606
7607 if (!mapimg_define(p, FALSE)) {
7608 log_error("Invalid map image definition %4d: %s.", i, p);
7609 }
7610
7611 log_verbose("Mapimg %4d loaded.", i);
7612 }
7613}
7614
7615/************************************************************************/
7618static void sg_save_mapimg(struct savedata *saving)
7619{
7620 /* Check status and return if not OK (sg_success FALSE). */
7621 sg_check_ret();
7622
7623 secfile_insert_int(saving->file, mapimg_count(), "mapimg.count");
7624 if (mapimg_count() > 0) {
7625 int i;
7626
7627 for (i = 0; i < mapimg_count(); i++) {
7628 char buf[MAX_LEN_MAPDEF];
7629
7630 mapimg_id2str(i, buf, sizeof(buf));
7631 secfile_insert_str(saving->file, buf, "mapimg.mapdef%d", i);
7632 }
7633 }
7634}
7635
7636/* =======================================================================
7637 * Sanity checks for loading / saving a game.
7638 * ======================================================================= */
7639
7640/************************************************************************/
7643static void sg_load_sanitycheck(struct loaddata *loading)
7644{
7645 int players;
7646
7647 /* Check status and return if not OK (sg_success FALSE). */
7648 sg_check_ret();
7649
7650 if (game.info.is_new_game) {
7651 /* Nothing to do for new games (or not started scenarios). */
7652 return;
7653 }
7654
7655 /* Old savegames may have maxplayers lower than current player count,
7656 * fix. */
7657 players = normal_player_count();
7658 if (game.server.max_players < players) {
7659 log_verbose("Max players lower than current players, fixing");
7660 game.server.max_players = players;
7661 }
7662
7663 /* Fix ferrying sanity */
7664 players_iterate(pplayer) {
7665 unit_list_iterate_safe(pplayer->units, punit) {
7668 log_sg("Removing %s unferried %s in %s at (%d, %d)",
7674 }
7677
7678 /* Fix stacking issues. We don't rely on the savegame preserving
7679 * alliance invariants (old savegames often did not) so if there are any
7680 * unallied units on the same tile we just bounce them. */
7681 players_iterate(pplayer) {
7682 players_iterate(aplayer) {
7683 resolve_unit_stacks(pplayer, aplayer, TRUE);
7686
7687 /* Recalculate the potential buildings for each city. Has caused some
7688 * problems with game random state.
7689 * This also changes the game state if you save the game directly after
7690 * loading it and compare the results. */
7691 players_iterate(pplayer) {
7692 /* Building advisor needs data phase open in order to work */
7693 adv_data_phase_init(pplayer, FALSE);
7694 building_advisor(pplayer);
7695 /* Close data phase again so it can be opened again when game starts. */
7696 adv_data_phase_done(pplayer);
7698
7699 /* Prevent a buggy or intentionally crafted save game from crashing
7700 * Freeciv. See hrm Bug #887748 */
7701 players_iterate(pplayer) {
7702 city_list_iterate(pplayer->cities, pcity) {
7703 worker_task_list_iterate(pcity->task_reqs, ptask) {
7704 if (!worker_task_is_sane(ptask)) {
7705 log_error("[city id: %d] Bad worker task %d.",
7706 pcity->id, ptask->act);
7707 worker_task_list_remove(pcity->task_reqs, ptask);
7708 free(ptask);
7709 ptask = NULL;
7710 }
7714
7715 /* Check worked tiles map */
7716#ifdef FREECIV_DEBUG
7717 if (loading->worked_tiles != NULL) {
7718 /* check the entire map for unused worked tiles */
7719 whole_map_iterate(&(wld.map), ptile) {
7720 if (loading->worked_tiles[ptile->index] != -1) {
7721 log_error("[city id: %d] Unused worked tile at (%d, %d).",
7722 loading->worked_tiles[ptile->index], TILE_XY(ptile));
7723 }
7725 }
7726#endif /* FREECIV_DEBUG */
7727
7728 /* Check researching technologies and goals. */
7729 researches_iterate(presearch) {
7730 int techs;
7731
7732 if (presearch->researching != A_UNSET
7733 && !is_future_tech(presearch->researching)
7734 && (valid_advance_by_number(presearch->researching) == NULL
7735 || (research_invention_state(presearch, presearch->researching)
7736 != TECH_PREREQS_KNOWN))) {
7737 log_sg(_("%s had invalid researching technology."),
7738 research_name_translation(presearch));
7739 presearch->researching = A_UNSET;
7740 }
7741 if (presearch->tech_goal != A_UNSET
7742 && !is_future_tech(presearch->tech_goal)
7743 && (valid_advance_by_number(presearch->tech_goal) == NULL
7744 || !research_invention_reachable(presearch, presearch->tech_goal)
7745 || (research_invention_state(presearch, presearch->tech_goal)
7746 == TECH_KNOWN))) {
7747 log_sg(_("%s had invalid technology goal."),
7748 research_name_translation(presearch));
7749 presearch->tech_goal = A_UNSET;
7750 }
7751
7753
7754 if (presearch->techs_researched != techs) {
7755 sg_regr(3000300,
7756 _("%s had finished researches count wrong."),
7757 research_name_translation(presearch));
7758 presearch->techs_researched = techs;
7759 }
7761
7762 /* Check if some player has more than one of some UTYF_UNIQUE unit type */
7763 players_iterate(pplayer) {
7764 int unique_count[U_LAST];
7765
7766 memset(unique_count, 0, sizeof(unique_count));
7767
7768 unit_list_iterate(pplayer->units, punit) {
7769 unique_count[utype_index(unit_type_get(punit))]++;
7771
7772 unit_type_iterate(ut) {
7773 if (unique_count[utype_index(ut)] > 1 && utype_has_flag(ut, UTYF_UNIQUE)) {
7774 log_sg(_("%s has multiple units of type %s though it should be possible "
7775 "to have only one."),
7776 player_name(pplayer), utype_name_translation(ut));
7777 }
7780
7781 players_iterate(pplayer) {
7782 unit_list_iterate_safe(pplayer->units, punit) {
7784 punit->orders.list)) {
7785 log_sg("Invalid unit orders for unit %d.", punit->id);
7787 }
7790
7791 /* Check max rates (rules may have changed since saving) */
7792 players_iterate(pplayer) {
7795
7796 if (0 == strlen(server.game_identifier)
7797 || !is_base64url(server.game_identifier)) {
7798 /* This uses fc_rand(), so random state has to be initialized before. */
7799 randomize_base64url_string(server.game_identifier,
7800 sizeof(server.game_identifier));
7801 }
7802
7803 /* Restore game random state, just in case various initialization code
7804 * inexplicably altered the previously existing state. */
7805 if (!game.info.is_new_game) {
7806 fc_rand_set_state(loading->rstate);
7807 }
7808
7809 /* At the end do the default sanity checks. */
7810 sanity_check();
7811}
7812
7813/************************************************************************/
7816static void sg_save_sanitycheck(struct savedata *saving)
7817{
7818 /* Check status and return if not OK (sg_success FALSE). */
7819 sg_check_ret();
7820}
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:1119
const char * city_name_get(const struct city *pcity)
Definition city.c:1111
const char * city_style_rule_name(const int style)
Definition city.c:1734
struct city * create_city_virtual(struct player *pplayer, struct tile *ptile, const char *name)
Definition city.c:3339
int city_illness_calc(const struct city *pcity, int *ill_base, int *ill_size, int *ill_trade, int *ill_pollution)
Definition city.c:2769
void city_size_set(struct city *pcity, citizens size)
Definition city.c:1154
void city_add_improvement(struct city *pcity, const struct impr_type *pimprove)
Definition city.c:3266
void destroy_city_virtual(struct city *pcity)
Definition city.c:3415
int city_style_by_rule_name(const char *s)
Definition city.c:1707
#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:812
#define FREE_WORKED_TILES
Definition city.h:849
#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:818
bool update_dumb_city(struct player *pplayer, struct city *pcity)
Definition citytools.c:2676
bool send_city_suppression(bool now)
Definition citytools.c:2136
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:2744
void city_refresh_vision(struct city *pcity)
Definition citytools.c:3331
void auto_arrange_workers(struct city *pcity)
Definition cityturn.c:368
void city_repair_size(struct city *pcity, int change)
Definition cityturn.c:896
bool city_refresh(struct city *pcity)
Definition cityturn.c:161
static char * ruleset
Definition civmanual.c:202
char * techs
Definition comments.c:29
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:120
#define governments_iterate_end
Definition government.h:123
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 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
void map_init_topology(void)
Definition map.c:301
#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:784
void event_cache_save(struct section_file *file, const char *section)
Definition notify.c:904
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_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:9246
#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:7559
static void unit_ordering_apply(void)
Definition savegame3.c:1052
static void sg_load_players_basic(struct loaddata *loading)
Definition savegame3.c:3432
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:3313
static void sg_load_map_owner(struct loaddata *loading)
Definition savegame3.c:2983
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:2815
static void sg_save_map_worked(struct savedata *saving)
Definition savegame3.c:3274
static void sg_save_players(struct savedata *saving)
Definition savegame3.c:3877
#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:5328
static void sg_load_player_city_citizens(struct loaddata *loading, struct player *plr, struct city *pcity, const char *citystr)
Definition savegame3.c:5280
static void sg_load_player_cities(struct loaddata *loading, struct player *plr)
Definition savegame3.c:4719
static void sg_load_map_tiles(struct loaddata *loading)
Definition savegame3.c:2716
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:5793
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:4845
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:5718
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:2928
static void sg_load_researches(struct loaddata *loading)
Definition savegame3.c:7206
static void sg_load_map_worked(struct loaddata *loading)
Definition savegame3.c:3230
#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:6274
static void sg_load_history(struct loaddata *loading)
Definition savegame3.c:7530
static void sg_save_treaties(struct savedata *saving)
Definition savegame3.c:7495
static void sg_save_map_owner(struct savedata *saving)
Definition savegame3.c:3104
static void sg_save_researches(struct savedata *saving)
Definition savegame3.c:7319
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:3938
static char order2char(enum unit_orders order)
Definition savegame3.c:713
static void sg_load_treaties(struct loaddata *loading)
Definition savegame3.c:7416
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:6327
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:7042
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:7816
static void sg_load_mapimg(struct loaddata *loading)
Definition savegame3.c:7578
static void sg_load_player_attributes(struct loaddata *loading, struct player *plr)
Definition savegame3.c:6578
static void sg_save_player_attributes(struct savedata *saving, struct player *plr)
Definition savegame3.c:6658
static void sg_load_ruledata(struct loaddata *loading)
Definition savegame3.c:1969
static void sg_save_map(struct savedata *saving)
Definition savegame3.c:2676
static void sg_load_player_vision(struct loaddata *loading, struct player *plr)
Definition savegame3.c:6741
static void sg_save_map_tiles(struct savedata *saving)
Definition savegame3.c:2756
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:7618
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:6931
static void sg_load_map_startpos(struct loaddata *loading)
Definition savegame3.c:2841
static void loaddata_destroy(struct loaddata *loading)
Definition savegame3.c:603
static void sg_load_players(struct loaddata *loading)
Definition savegame3.c:3688
#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:7396
static void sg_load_map_tiles_extras(struct loaddata *loading)
Definition savegame3.c:2784
static void sg_load_sanitycheck(struct loaddata *loading)
Definition savegame3.c:7643
static void sg_load_event_cache(struct loaddata *loading)
Definition savegame3.c:7385
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:4412
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:3369
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:1909
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:60
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:161
#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:162
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:1069
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:1755
bool unit_transport_load(struct unit *pcargo, struct unit *ptrans, bool force)
Definition unit.c:2356
void set_unit_activity(struct unit *punit, enum unit_activity new_activity)
Definition unit.c:1108
struct player * unit_nationality(const struct unit *punit)
Definition unit.c:1272
struct unit * unit_transport_get(const struct unit *pcargo)
Definition unit.c:2427
bool can_unit_continue_current_activity(const struct civ_map *nmap, struct unit *punit)
Definition unit.c:846
void set_unit_activity_targeted(struct unit *punit, enum unit_activity new_activity, struct extra_type *new_target)
Definition unit.c:1125
struct unit * unit_virtual_create(struct player *pplayer, struct city *pcity, const struct unit_type *punittype, int veteran_level)
Definition unit.c:1619
bool unit_order_list_is_sane(const struct civ_map *nmap, int length, const struct unit_order *orders)
Definition unit.c:2634
void unit_virtual_destroy(struct unit *punit)
Definition unit.c:1715
void unit_tile_set(struct unit *punit, struct tile *ptile)
Definition unit.c:1282
#define unit_tile(_pu)
Definition unit.h:388
#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:387
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:1418
void unit_refresh_vision(struct unit *punit)
Definition unittools.c:4852
void bounce_unit(struct unit *punit, bool verbose)
Definition unittools.c:1245
bool unit_activity_needs_target_from_client(enum unit_activity activity)
Definition unittools.c:1082
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:2661
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:838
#define U_LAST
Definition unittype.h:40
#define unit_type_iterate_end
Definition unittype.h:845
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