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