Support changing players' science box in the editor.
[freeciv.git] / common / game.c
blobdb169e53303ded43078934eba3e7d1640667a5b2
1 /**********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 /* utility */
19 #include "fcintl.h"
20 #include "ioz.h"
21 #include "log.h"
22 #include "mem.h"
23 #include "shared.h"
24 #include "support.h"
26 /* aicore */
27 #include "cm.h"
29 /* common */
30 #include "base.h"
31 #include "city.h"
32 #include "connection.h"
33 #include "disaster.h"
34 #include "government.h"
35 #include "idex.h"
36 #include "map.h"
37 #include "nation.h"
38 #include "packets.h"
39 #include "player.h"
40 #include "research.h"
41 #include "spaceship.h"
42 #include "specialist.h"
43 #include "tech.h"
44 #include "terrain.h"
45 #include "traderoutes.h"
46 #include "unit.h"
47 #include "unitlist.h"
49 #include "game.h"
51 struct civ_game game;
54 struct player_score {
55 int happy;
56 int content;
57 int unhappy;
58 int angry;
59 int taxmen;
60 int scientists;
61 int elvis;
62 int wonders;
63 int techs;
64 int landarea;
65 int settledarea;
66 int population;
67 int cities;
68 int units;
69 int pollution;
70 int literacy;
71 int bnp;
72 int mfg;
73 int spaceship;
77 bool am_i_server = FALSE;
79 static void game_defaults(void);
81 /**************************************************************************
82 Is program type server?
83 **************************************************************************/
84 bool is_server(void)
86 return am_i_server;
89 /**************************************************************************
90 Set program type to server.
91 **************************************************************************/
92 void i_am_server(void)
94 am_i_server = TRUE;
97 /**************************************************************************
98 Set program type to client.
99 **************************************************************************/
100 void i_am_client(void)
102 am_i_server = FALSE;
105 /**************************************************************************
106 Count the # of thousand citizen in a civilisation.
107 **************************************************************************/
108 int civ_population(const struct player *pplayer)
110 int ppl=0;
111 city_list_iterate(pplayer->cities, pcity)
112 ppl+=city_population(pcity);
113 city_list_iterate_end;
114 return ppl;
118 /**************************************************************************
119 Find city with given name from any player.
120 **************************************************************************/
121 struct city *game_city_by_name(const char *name)
123 players_iterate(pplayer) {
124 struct city *pcity = city_list_find_name(pplayer->cities, name);
126 if (pcity) {
127 return pcity;
129 } players_iterate_end;
131 return NULL;
135 /**************************************************************************
136 Often used function to get a city pointer from a city ID.
137 City may be any city in the game. This now always uses fast idex
138 method, instead of looking through all cities of all players.
139 **************************************************************************/
140 struct city *game_city_by_number(int id)
142 return idex_lookup_city(id);
146 /**************************************************************************
147 Find unit out of all units in game: now uses fast idex method,
148 instead of looking through all units of all players.
149 **************************************************************************/
150 struct unit *game_unit_by_number(int id)
152 return idex_lookup_unit(id);
155 /**************************************************************************
156 In the server call wipe_unit(), and never this function directly.
157 **************************************************************************/
158 void game_remove_unit(struct unit *punit)
160 struct city *pcity;
162 /* It's possible that during city transfer homecity/unit owner
163 * information is inconsistent, and client then tries to remove
164 * now unseen unit so that homecity is not in the list of cities
165 * of the player (seemingly) owning the unit.
166 * Thus cannot use player_city_by_number() here, but have to
167 * consider cities of all players. */
168 pcity = game_city_by_number(punit->homecity);
169 if (pcity) {
170 unit_list_remove(pcity->units_supported, punit);
172 log_debug("game_remove_unit()"
173 " at (%d,%d) unit %d, %s %s home (%d,%d) city %d, %s %s",
174 TILE_XY(unit_tile(punit)),
175 punit->id,
176 nation_rule_name(nation_of_unit(punit)),
177 unit_rule_name(punit),
178 TILE_XY(pcity->tile),
179 punit->homecity,
180 nation_rule_name(nation_of_city(pcity)),
181 city_name(pcity));
182 } else if (IDENTITY_NUMBER_ZERO == punit->homecity) {
183 log_debug("game_remove_unit() at (%d,%d) unit %d, %s %s home %d",
184 TILE_XY(unit_tile(punit)),
185 punit->id,
186 nation_rule_name(nation_of_unit(punit)),
187 unit_rule_name(punit),
188 punit->homecity);
189 } else {
190 log_error("game_remove_unit() at (%d,%d) unit %d, %s %s home %d invalid",
191 TILE_XY(unit_tile(punit)),
192 punit->id,
193 nation_rule_name(nation_of_unit(punit)),
194 unit_rule_name(punit),
195 punit->homecity);
198 unit_list_remove(unit_tile(punit)->units, punit);
199 unit_list_remove(unit_owner(punit)->units, punit);
201 idex_unregister_unit(punit);
203 if (game.callbacks.unit_deallocate) {
204 (game.callbacks.unit_deallocate)(punit->id);
206 unit_virtual_destroy(punit);
209 /**************************************************************************
210 Remove city from game.
211 **************************************************************************/
212 void game_remove_city(struct city *pcity)
214 struct tile *pcenter = city_tile(pcity);
215 struct player *powner = city_owner(pcity);
217 if (NULL != powner) {
218 /* always unlink before clearing data */
219 city_list_remove(powner->cities, pcity);
222 if (NULL == pcenter) {
223 log_debug("game_remove_city() virtual city %d, %s",
224 pcity->id,
225 city_name(pcity));
226 } else {
227 log_debug("game_remove_city() at (%d,%d) city %d, %s %s",
228 TILE_XY(pcenter),
229 pcity->id,
230 nation_rule_name(nation_of_player(powner)),
231 city_name(pcity));
233 city_tile_iterate(city_map_radius_sq_get(pcity), pcenter, ptile) {
234 if (tile_worked(ptile) == pcity) {
235 tile_set_worked(ptile, NULL);
237 } city_tile_iterate_end;
240 idex_unregister_city(pcity);
241 destroy_city_virtual(pcity);
244 /****************************************************************************
245 Set default game values.
246 ****************************************************************************/
247 static void game_defaults(void)
249 int i;
251 /* The control packet. */
252 game.control.government_count = 0;
253 game.control.nation_count = 0;
254 game.control.num_base_types = 0;
255 game.control.num_road_types = 0;
256 game.control.num_impr_types = 0;
257 game.control.num_specialist_types = 0;
258 game.control.num_tech_types = 0;
259 game.control.num_unit_classes = 0;
260 game.control.num_unit_types = 0;
261 game.control.num_disaster_types = 0;
262 game.control.prefered_tileset[0] = '\0';
263 game.control.resource_count = 0;
264 game.control.styles_count = 0;
265 game.control.terrain_count = 0;
267 /* The info packet. */
268 game.info.aifill = GAME_DEFAULT_AIFILL;
269 game.info.airlifting_style = GAME_DEFAULT_AIRLIFTINGSTYLE;
270 game.info.angrycitizen = GAME_DEFAULT_ANGRYCITIZEN;
271 game.info.borders = GAME_DEFAULT_BORDERS;
272 game.info.calendar_skip_0 = FALSE;
273 game.info.celebratesize = GAME_DEFAULT_CELEBRATESIZE;
274 game.info.citymindist = GAME_DEFAULT_CITYMINDIST;
275 game.info.cooling = 0;
276 game.info.coolinglevel = 0; /* set later */
277 game.info.diplomacy = GAME_DEFAULT_DIPLOMACY;
278 game.info.fogofwar = GAME_DEFAULT_FOGOFWAR;
279 game.info.foodbox = GAME_DEFAULT_FOODBOX;
280 game.info.fulltradesize = GAME_DEFAULT_FULLTRADESIZE;
281 for (i = 0; i < A_LAST; i++) {
282 /* game.num_tech_types = 0 here */
283 game.info.global_advances[i] = FALSE;
285 for (i = 0; i < B_LAST; i++) {
286 /* game.num_impr_types = 0 here */
287 game.info.great_wonder_owners[i] = WONDER_NOT_OWNED;
289 game.info.globalwarming = 0;
290 game.info.global_warming = GAME_DEFAULT_GLOBAL_WARMING;
291 game.info.gold = GAME_DEFAULT_GOLD;
292 game.info.government_during_revolution_id = G_MAGIC; /* flag */
293 game.info.happyborders = GAME_DEFAULT_HAPPYBORDERS;
294 game.info.heating = 0;
295 game.info.is_edit_mode = FALSE;
296 game.info.is_new_game = TRUE;
297 game.info.killstack = GAME_DEFAULT_KILLSTACK;
298 game.info.killcitizen = GAME_DEFAULT_KILLCITIZEN;
299 game.info.negative_year_label[0] = '\0';
300 game.info.notradesize = GAME_DEFAULT_NOTRADESIZE;
301 game.info.nuclearwinter = 0;
302 game.info.nuclear_winter = GAME_DEFAULT_NUCLEAR_WINTER;
303 game.info.positive_year_label[0] = '\0';
304 game.info.rapturedelay = GAME_DEFAULT_RAPTUREDELAY;
305 game.info.restrictinfra = GAME_DEFAULT_RESTRICTINFRA;
306 game.info.sciencebox = GAME_DEFAULT_SCIENCEBOX;
307 game.info.shieldbox = GAME_DEFAULT_SHIELDBOX;
308 game.info.skill_level = GAME_DEFAULT_SKILL_LEVEL;
309 game.info.slow_invasions = RS_DEFAULT_SLOW_INVASIONS;
310 game.info.spacerace = GAME_DEFAULT_SPACERACE;
311 game.info.team_pooled_research = GAME_DEFAULT_TEAM_POOLED_RESEARCH;
312 game.info.tech = GAME_DEFAULT_TECHLEVEL;
313 game.info.timeout = GAME_DEFAULT_TIMEOUT;
314 game.info.trademindist = GAME_DEFAULT_TRADEMINDIST;
315 game.info.trading_city = GAME_DEFAULT_TRADING_CITY;
316 game.info.trading_gold = GAME_DEFAULT_TRADING_GOLD;
317 game.info.trading_tech = GAME_DEFAULT_TRADING_TECH;
318 game.info.turn = 0;
319 game.info.warminglevel = 0; /* set later */
320 game.info.year_0_hack = FALSE;
321 game.info.year = GAME_START_YEAR;
323 /* The scenario packet. */
324 game.scenario.description[0] = '\0';
325 game.scenario.is_scenario = FALSE;
326 game.scenario.name[0] = '\0';
327 game.scenario.players = TRUE;
328 game.scenario.startpos_nations = FALSE;
330 /* Veteran system. */
331 game.veteran = NULL;
333 /* player colors */
334 game.plr_bg_color = NULL;
336 if (is_server()) {
337 /* All settings only used by the server (./server/ and ./ai/ */
338 sz_strlcpy(game.server.allow_take, GAME_DEFAULT_ALLOW_TAKE);
339 game.server.allied_victory = GAME_DEFAULT_ALLIED_VICTORY;
340 game.server.allowed_city_names = GAME_DEFAULT_ALLOWED_CITY_NAMES;
341 game.server.aqueductloss = GAME_DEFAULT_AQUEDUCTLOSS;
342 game.server.auto_ai_toggle = GAME_DEFAULT_AUTO_AI_TOGGLE;
343 game.server.autoattack = GAME_DEFAULT_AUTOATTACK;
344 game.server.barbarianrate = GAME_DEFAULT_BARBARIANRATE;
345 game.server.civilwarsize = GAME_DEFAULT_CIVILWARSIZE;
346 game.server.connectmsg[0] = '\0';
347 game.server.conquercost = GAME_DEFAULT_CONQUERCOST;
348 game.server.contactturns = GAME_DEFAULT_CONTACTTURNS;
349 for (i = 0; i < DEBUG_LAST; i++) {
350 game.server.debug[i] = FALSE;
352 sz_strlcpy(game.server.demography, GAME_DEFAULT_DEMOGRAPHY);
353 game.server.diplchance = GAME_DEFAULT_DIPLCHANCE;
354 game.server.diplcost = GAME_DEFAULT_DIPLCOST;
355 game.server.dispersion = GAME_DEFAULT_DISPERSION;
356 game.server.endspaceship = GAME_DEFAULT_END_SPACESHIP;
357 game.server.end_turn = GAME_DEFAULT_END_TURN;
358 game.server.event_cache.chat = GAME_DEFAULT_EVENT_CACHE_CHAT;
359 game.server.event_cache.info = GAME_DEFAULT_EVENT_CACHE_INFO;
360 game.server.event_cache.max_size = GAME_DEFAULT_EVENT_CACHE_MAX_SIZE;
361 game.server.event_cache.turns = GAME_DEFAULT_EVENT_CACHE_TURNS;
362 game.server.foggedborders = GAME_DEFAULT_FOGGEDBORDERS;
363 game.server.fogofwar_old = game.info.fogofwar;
364 game.server.freecost = GAME_DEFAULT_FREECOST;
365 game.server.homecaughtunits = GAME_DEFAULT_HOMECAUGHTUNITS;
366 game.server.kick_time = GAME_DEFAULT_KICK_TIME;
367 game.server.killunhomed = GAME_DEFAULT_KILLUNHOMED;
368 game.server.maxconnectionsperhost = GAME_DEFAULT_MAXCONNECTIONSPERHOST;
369 game.server.last_ping = 0;
370 game.server.max_players = GAME_DEFAULT_MAX_PLAYERS;
371 game.server.meta_info.user_message[0] = '\0';
372 game.server.meta_info.user_message_set = FALSE;
373 game.server.mgr_distance = GAME_DEFAULT_MGR_DISTANCE;
374 game.server.mgr_foodneeded = GAME_DEFAULT_MGR_FOODNEEDED;
375 game.server.mgr_nationchance = GAME_DEFAULT_MGR_NATIONCHANCE;
376 game.server.mgr_turninterval = GAME_DEFAULT_MGR_TURNINTERVAL;
377 game.server.mgr_worldchance = GAME_DEFAULT_MGR_WORLDCHANCE;
378 game.server.migration = GAME_DEFAULT_MIGRATION;
379 game.server.min_players = GAME_DEFAULT_MIN_PLAYERS;
380 game.server.natural_city_names = GAME_DEFAULT_NATURALCITYNAMES;
381 game.server.plrcolormode = GAME_DEFAULT_PLRCOLORMODE;
382 game.server.netwait = GAME_DEFAULT_NETWAIT;
383 game.server.occupychance = GAME_DEFAULT_OCCUPYCHANCE;
384 game.server.onsetbarbarian = GAME_DEFAULT_ONSETBARBARIAN;
385 game.server.phase_mode_stored = GAME_DEFAULT_PHASE_MODE;
386 game.server.pingtime = GAME_DEFAULT_PINGTIME;
387 game.server.pingtimeout = GAME_DEFAULT_PINGTIMEOUT;
388 game.server.razechance = GAME_DEFAULT_RAZECHANCE;
389 game.server.revealmap = GAME_DEFAULT_REVEALMAP;
390 game.server.revolution_length = GAME_DEFAULT_REVOLUTION_LENGTH;
391 sz_strlcpy(game.server.rulesetdir, GAME_DEFAULT_RULESETDIR);
392 game.server.save_compress_level = GAME_DEFAULT_COMPRESS_LEVEL;
393 game.server.save_compress_type = GAME_DEFAULT_COMPRESS_TYPE;
394 sz_strlcpy(game.server.save_name, GAME_DEFAULT_SAVE_NAME);
395 game.server.save_nturns = GAME_DEFAULT_SAVETURNS;
396 game.server.save_options.save_known = TRUE;
397 game.server.save_options.save_private_map = TRUE;
398 game.server.save_options.save_random = TRUE;
399 game.server.save_options.save_starts = TRUE;
400 game.server.savepalace = GAME_DEFAULT_SAVEPALACE;
401 game.server.scorelog = GAME_DEFAULT_SCORELOG;
402 game.server.scoreturn = GAME_DEFAULT_SCORETURN;
403 game.server.seed = GAME_DEFAULT_SEED;
404 sz_strlcpy(game.server.start_units, GAME_DEFAULT_START_UNITS);
405 game.server.start_year = GAME_START_YEAR;
406 game.server.tcptimeout = GAME_DEFAULT_TCPTIMEOUT;
407 game.server.techlost_donor = GAME_DEFAULT_TECHLOST_DONOR;
408 game.server.techlost_recv = GAME_DEFAULT_TECHLOST_RECV;
409 game.server.techpenalty = GAME_DEFAULT_TECHPENALTY;
410 game.server.timeoutaddenemymove = GAME_DEFAULT_TIMEOUTADDEMOVE;
411 game.server.timeoutcounter = GAME_DEFAULT_TIMEOUTCOUNTER;
412 game.server.timeoutinc = GAME_DEFAULT_TIMEOUTINC;
413 game.server.timeoutincmult = GAME_DEFAULT_TIMEOUTINCMULT;
414 game.server.timeoutint = GAME_DEFAULT_TIMEOUTINT;
415 game.server.timeoutintinc = GAME_DEFAULT_TIMEOUTINTINC;
416 game.server.turnblock = GAME_DEFAULT_TURNBLOCK;
417 game.server.unitwaittime = GAME_DEFAULT_UNITWAITTIME;
418 game.server.plr_colors = NULL;
422 /****************************************************************************
423 Initialise all game settings.
425 The variables are listed in alphabetical order.
426 ****************************************************************************/
427 void game_init(void)
429 game_defaults();
430 player_slots_init();
431 map_init();
432 team_slots_init();
433 game_ruleset_init();
434 idex_init();
435 cm_init();
436 player_researches_init();
439 /****************************************************************************
440 Initialize map-specific parts of the game structure. Maybe these should
441 be moved into the map structure?
442 ****************************************************************************/
443 void game_map_init(void)
445 /* FIXME: it's not clear where these values should be initialized. It
446 * can't be done in game_init because the map isn't created yet. Maybe it
447 * should be done in the mapgen code or in the maphand code. It should
448 * surely be called when the map is generated. */
449 game.info.warminglevel = (map_num_tiles() + 499) / 500;
450 game.info.coolinglevel = (map_num_tiles() + 499) / 500;
453 /***************************************************************
454 Frees all memory of the game.
455 ***************************************************************/
456 void game_free(void)
458 player_slots_free();
459 map_free();
460 idex_free();
461 team_slots_free();
462 game_ruleset_free();
463 cm_free();
466 /***************************************************************
467 Do all changes to change view, and not full
468 game_free()/game_init().
469 ***************************************************************/
470 void game_reset(void)
472 if (is_server()) {
473 game_free();
474 game_init();
475 } else {
476 /* Reset the players infos. */
477 players_iterate(pplayer) {
478 player_clear(pplayer, FALSE);
479 } players_iterate_end;
481 map_free();
482 idex_free();
484 map_init();
485 idex_init();
489 /***************************************************************
490 Initialize the objects which will read from a ruleset.
491 ***************************************************************/
492 void game_ruleset_init(void)
494 nation_sets_groups_init();
495 ruleset_cache_init();
496 disaster_types_init();
497 trade_route_types_init();
498 terrains_init();
499 base_types_init();
500 road_types_init();
501 improvements_init();
502 techs_init();
503 unit_classes_init();
504 unit_types_init();
505 specialists_init();
506 user_unit_type_flags_init();
507 user_terrain_flags_init();
508 user_tech_flags_init();
511 /***************************************************************
512 Frees all memory which in objects which are read from a ruleset.
513 ***************************************************************/
514 void game_ruleset_free(void)
516 CALL_FUNC_EACH_AI(units_ruleset_close);
518 /* Clear main structures which can points to the ruleset dependent
519 * structures. */
520 players_iterate(pplayer) {
521 player_ruleset_close(pplayer);
522 } players_iterate_end;
523 game.government_during_revolution = NULL;
525 specialists_free();
526 unit_classes_free();
527 techs_free();
528 governments_free();
529 nations_free();
530 unit_types_free();
531 unit_type_flags_free();
532 role_unit_precalcs_free();
533 improvements_free();
534 base_types_free();
535 road_types_free();
536 city_styles_free();
537 disaster_types_free();
538 terrains_free();
539 user_tech_flags_free();
540 user_terrain_flags_free();
541 ruleset_cache_free();
542 nation_sets_groups_free();
544 /* Destroy the default veteran system. */
545 veteran_system_destroy(game.veteran);
546 game.veteran = NULL;
548 /* Player colors. */
549 if (game.plr_bg_color != NULL) {
550 rgbcolor_destroy(game.plr_bg_color);
551 game.plr_bg_color = NULL;
555 /***************************************************************
556 Initialize wonder information.
557 ***************************************************************/
558 void initialize_globals(void)
560 players_iterate(pplayer) {
561 city_list_iterate(pplayer->cities, pcity) {
562 city_built_iterate(pcity, pimprove) {
563 if (is_wonder(pimprove)) {
564 if (is_great_wonder(pimprove)) {
565 game.info.great_wonder_owners[improvement_index(pimprove)] =
566 player_number(pplayer);
568 pplayer->wonders[improvement_index(pimprove)] = pcity->id;
570 } city_built_iterate_end;
571 } city_list_iterate_end;
572 } players_iterate_end;
575 /***************************************************************
576 Returns the next year in the game.
577 ***************************************************************/
578 int game_next_year(int year)
580 int increase = get_world_bonus(EFT_TURN_YEARS);
581 const int slowdown = (game.info.spacerace
582 ? get_world_bonus(EFT_SLOW_DOWN_TIMELINE) : 0);
584 if (game.info.year_0_hack) {
585 /* hacked it to get rid of year 0 */
586 year = 0;
587 game.info.year_0_hack = FALSE;
590 /* !McFred:
591 - want year += 1 for spaceship.
594 /* test game with 7 normal AI's, gen 4 map, foodbox 10, foodbase 0:
595 * Gunpowder about 0 AD
596 * Railroad about 500 AD
597 * Electricity about 1000 AD
598 * Refining about 1500 AD (212 active units)
599 * about 1750 AD
600 * about 1900 AD
603 /* Note the slowdown operates even if Enable_Space is not active. See
604 * README.effects for specifics. */
605 if (slowdown >= 3) {
606 if (increase > 1) {
607 increase = 1;
609 } else if (slowdown >= 2) {
610 if (increase > 2) {
611 increase = 2;
613 } else if (slowdown >= 1) {
614 if (increase > 5) {
615 increase = 5;
619 year += increase;
621 if (year == 0 && game.info.calendar_skip_0) {
622 year = 1;
623 game.info.year_0_hack = TRUE;
626 return year;
629 /***************************************************************
630 Advance the game year.
631 ***************************************************************/
632 void game_advance_year(void)
634 game.info.year = game_next_year(game.info.year);
635 game.info.turn++;
638 /**************************************************************************
639 Return TRUE if it is this player's phase.
640 NB: The meaning of the 'phase' argument must match its use in the
641 function begin_turn() in server/srv_main.c.
642 NB: The phase mode PMT_TEAMS_ALTERNATE assumes that every player is
643 on a team, i.e. that pplayer->team is never NULL.
644 **************************************************************************/
645 bool is_player_phase(const struct player *pplayer, int phase)
647 switch (game.info.phase_mode) {
648 case PMT_CONCURRENT:
649 return TRUE;
650 break;
651 case PMT_PLAYERS_ALTERNATE:
652 return player_number(pplayer) == phase;
653 break;
654 case PMT_TEAMS_ALTERNATE:
655 fc_assert_ret_val(NULL != pplayer->team, FALSE);
656 return team_number(pplayer->team) == phase;
657 break;
658 default:
659 break;
662 fc_assert_msg(FALSE, "Unrecognized phase mode %d in is_player_phase().",
663 phase);
664 return TRUE;
667 /****************************************************************************
668 Return a prettily formatted string containing the population text. The
669 population is passed in as the number of citizens, in unit
670 (tens/hundreds/thousands...) defined in cities.ruleset.
671 ****************************************************************************/
672 const char *population_to_text(int thousand_citizen)
674 /* big_int_to_text can't handle negative values, and in any case we'd
675 * better not have a negative population. */
676 fc_assert_ret_val(thousand_citizen >= 0, NULL);
677 return big_int_to_text(thousand_citizen, game.info.pop_report_zeroes - 1);
680 /****************************************************************************
681 Produce a statically allocated textual representation of the given
682 year.
683 ****************************************************************************/
684 const char *textyear(int year)
686 static char y[32];
687 if (year < 0) {
688 /* TRANS: <year> <label> -> "1000 BC" */
689 fc_snprintf(y, sizeof(y), _("%d %s"), -year,
690 game.info.negative_year_label);
691 } else {
692 /* TRANS: <year> <label> -> "1000 AD" */
693 fc_snprintf(y, sizeof(y), _("%d %s"), year,
694 game.info.positive_year_label);
696 return y;
699 /**************************************************************************
700 Return a string conaining the save year.
701 **************************************************************************/
702 static char *year_suffix(void)
704 static char buf[MAX_LEN_NAME];
705 const char *year_suffix;
706 char safe_year_suffix[MAX_LEN_NAME];
707 const char *max = safe_year_suffix + MAX_LEN_NAME - 1;
708 char *c = safe_year_suffix;
710 if (game.info.year < 0) {
711 year_suffix = game.info.negative_year_label;
712 } else {
713 year_suffix = game.info.positive_year_label;
716 /* Remove all non alphanumeric characters from the year suffix. */
717 for (; '\0' != *year_suffix && c < max; year_suffix++) {
718 if (fc_isalnum(*year_suffix)) {
719 *c++ = *year_suffix;
722 *c = '\0';
724 fc_snprintf(buf, sizeof(buf), "%s", safe_year_suffix);
726 return buf;
729 /**************************************************************************
730 Generate a default save file name and place it in the provided buffer.
731 Within the name the following custom formats are allowed:
733 %R = <reason>
734 %S = <suffix>
735 %T = <game.info.turn>
736 %Y = <game.info.year>
738 Examples:
739 'freeciv-T%04T-Y%+04Y-%R' => 'freeciv-T0099-Y-0050-manual'
740 => 'freeciv-T0100-Y00001-auto'
742 Returns the number of characters written, or the number of characters
743 that would have been written if truncation occurs.
745 NB: If you change the format definition, be sure to update the above
746 function comment and the help text for the 'savename' setting.
747 **************************************************************************/
748 int generate_save_name(const char *format, char *buf, int buflen,
749 const char *reason)
751 struct cf_sequence sequences[] = {
752 cf_str_seq('R', (reason == NULL) ? "auto" : reason),
753 cf_str_seq('S', year_suffix()),
754 cf_int_seq('T', game.info.turn),
755 cf_int_seq('Y', game.info.year),
756 cf_end()
759 fc_vsnprintcf(buf, buflen, format, sequences, -1);
761 if (0 == strcmp(format, buf)) {
762 /* Use the default savename if 'format' does not contain
763 * printf information. */
764 char savename[512];
766 fc_snprintf(savename, sizeof(savename), "%s-T%%04T-Y%%05Y-%%R",
767 format);
768 fc_vsnprintcf(buf, buflen, savename, sequences, -1);
771 log_debug("save name generated from '%s': %s", format, buf);
773 return strlen(buf);
776 /**************************************************************************
777 Initialize user flag.
778 **************************************************************************/
779 void user_flag_init(struct user_flag *flag)
781 flag->name = NULL;
782 flag->helptxt = NULL;
785 /**************************************************************************
786 Free user flag.
787 **************************************************************************/
788 void user_flag_free(struct user_flag *flag)
790 if (flag->name != NULL) {
791 FC_FREE(flag->name);
792 flag->name = NULL;
794 if (flag->helptxt != NULL) {
795 FC_FREE(flag->helptxt);
796 flag->helptxt = NULL;