Freeciv21
Develop your civilization from humble roots to a global empire
rulesave.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2020 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 
14 // utility
15 #include "registry.h"
16 
17 // common
18 #include "achievements.h"
19 #include "game.h"
20 #include "government.h"
21 #include "map.h"
22 #include "movement.h"
23 #include "multipliers.h"
24 #include "nation.h"
25 #include "rgbcolor.h"
26 #include "specialist.h"
27 #include "style.h"
28 #include "unittype.h"
29 #include "version.h"
30 
31 // server
32 #include "ruleset.h"
33 #include "settings.h"
34 
35 /* tools/ruleutil */
36 #include "comments.h"
37 
38 #include "rulesave.h"
39 
40 // Ruleset format version
41 /*
42  * 1 - Freeciv-2.6
43  * 10 - Freeciv-3.0
44  * 20 - Freeciv-3.1
45  */
46 #define FORMAT_VERSION 20
47 
51 static struct section_file *create_ruleset_file(const char *rsname,
52  const char *rstype)
53 {
54  struct section_file *sfile = secfile_new(true);
55  char buf[500];
56 
57  comment_file_header(sfile);
58 
59  if (rsname != nullptr && rsname[0] != '\0') {
60  fc_snprintf(buf, sizeof(buf), "%s %s data for Freeciv21", rsname,
61  rstype);
62  } else {
63  fc_snprintf(buf, sizeof(buf), "Template %s data for Freeciv21", rstype);
64  }
65 
66  secfile_insert_str(sfile, buf, "datafile.description");
67  secfile_insert_str(sfile, freeciv21_version(), "datafile.ruledit");
68  secfile_insert_str(sfile, RULESET_CAPABILITIES, "datafile.options");
69  secfile_insert_int(sfile, FORMAT_VERSION, "datafile.format_version");
70 
71  return sfile;
72 }
73 
77 static bool save_default_int(struct section_file *sfile, int value,
78  int default_value, const char *path,
79  const char *entry)
80 {
81  if (value != default_value) {
82  if (entry != nullptr) {
83  secfile_insert_int(sfile, value, "%s.%s", path, entry);
84  } else {
85  secfile_insert_int(sfile, value, "%s", path);
86  }
87  }
88 
89  return true;
90 }
91 
95 static bool save_default_bool(struct section_file *sfile, bool value,
96  bool default_value, const char *path,
97  const char *entry)
98 {
99  if ((value && !default_value) || (!value && default_value)) {
100  if (entry != nullptr) {
101  secfile_insert_bool(sfile, value, "%s.%s", path, entry);
102  } else {
103  secfile_insert_bool(sfile, value, "%s", path);
104  }
105  }
106 
107  return true;
108 }
109 
113 static bool save_name_translation(struct section_file *sfile,
114  struct name_translation *name,
115  const char *path)
116 {
117  struct entry *mod_entry;
118 
119  mod_entry =
120  secfile_insert_str(sfile, untranslated_name(name), "%s.name", path);
121  entry_str_set_gt_marking(mod_entry, true);
123  rule_name_get(name))) {
124  secfile_insert_str(sfile, rule_name_get(name), "%s.rule_name", path);
125  }
126 
127  return true;
128 }
129 
133 static bool save_reqs_vector(struct section_file *sfile,
134  const struct requirement_vector *reqs,
135  const char *path, const char *entry)
136 {
137  int i;
138  bool includes_negated = false;
139  bool includes_surviving = false;
140  bool includes_quiet = false;
141 
143  {
144  if (!preq->present) {
145  includes_negated = true;
146  }
147  if (preq->survives) {
148  includes_surviving = true;
149  }
150  if (preq->quiet) {
151  includes_quiet = true;
152  }
153  }
155 
156  i = 0;
158  {
159  secfile_insert_str(sfile, universals_n_name(preq->source.kind),
160  "%s.%s%d.type", path, entry, i);
161  secfile_insert_str(sfile, universal_rule_name(&(preq->source)),
162  "%s.%s%d.name", path, entry, i);
163  secfile_insert_str(sfile, req_range_name(preq->range), "%s.%s%d.range",
164  path, entry, i);
165 
166  if (includes_surviving) {
167  secfile_insert_bool(sfile, preq->survives, "%s.%s%d.survives", path,
168  entry, i);
169  }
170 
171  if (includes_negated) {
172  secfile_insert_bool(sfile, preq->present, "%s.%s%d.present", path,
173  entry, i);
174  }
175 
176  if (includes_quiet) {
177  secfile_insert_bool(sfile, preq->quiet, "%s.%s%d.quiet", path, entry,
178  i);
179  }
180 
181  i++;
182  }
184 
185  return true;
186 }
187 
191 static bool save_tech_list(struct section_file *sfile, int *input,
192  const char *path, const char *entry)
193 {
194  const char *tech_names[MAX_NUM_TECH_LIST];
195  int set_count;
196  int i;
197 
198  set_count = 0;
199  for (i = 0; i < MAX_NUM_TECH_LIST && input[i] != A_LAST; i++) {
200  tech_names[set_count++] = advance_rule_name(advance_by_number(input[i]));
201  }
202 
203  if (set_count > 0) {
204  secfile_insert_str_vec(sfile, tech_names, set_count, "%s.%s", path,
205  entry);
206  }
207 
208  return true;
209 }
210 
214 static bool save_tech_ref(struct section_file *sfile,
215  const struct advance *padv, const char *path,
216  const char *entry)
217 {
218  if (padv == A_NEVER) {
219  secfile_insert_str(sfile, "Never", "%s.%s", path, entry);
220  } else {
221  secfile_insert_str(sfile, advance_rule_name(padv), "%s.%s", path, entry);
222  }
223 
224  return true;
225 }
226 
230 static bool save_terrain_ref(struct section_file *sfile,
231  const struct terrain *save,
232  const struct terrain *pthis, const char *path,
233  const char *entry)
234 {
235  if (save == nullptr) {
236  secfile_insert_str(sfile, "none", "%s.%s", path, entry);
237  } else if (save == pthis) {
238  secfile_insert_str(sfile, "yes", "%s.%s", path, entry);
239  } else {
240  secfile_insert_str(sfile, terrain_rule_name(save), "%s.%s", path, entry);
241  }
242 
243  return true;
244 }
245 
249 static bool save_gov_ref(struct section_file *sfile,
250  const struct government *gov, const char *path,
251  const char *entry)
252 {
253  secfile_insert_str(sfile, government_rule_name(gov), "%s.%s", path, entry);
254 
255  return true;
256 }
257 
262 static bool save_building_list(struct section_file *sfile, int *input,
263  const char *path, const char *entry)
264 {
265  const char *building_names[MAX_NUM_BUILDING_LIST];
266  int set_count;
267  int i;
268 
269  set_count = 0;
270  for (i = 0; i < MAX_NUM_BUILDING_LIST && input[i] != B_LAST; i++) {
271  building_names[set_count++] =
273  }
274 
275  if (set_count > 0) {
276  secfile_insert_str_vec(sfile, building_names, set_count, "%s.%s", path,
277  entry);
278  }
279 
280  return true;
281 }
282 
287 static bool
289  const std::array<unit_type *, MAX_NUM_UNIT_LIST> &input,
290  const char *path, const char *entry)
291 {
292  const char *unit_names[MAX_NUM_UNIT_LIST];
293  int set_count;
294 
295  set_count = 0;
296  for (const auto &utype : input) {
297  if (utype == nullptr) {
298  break;
299  }
300  unit_names[set_count++] = utype_rule_name(utype);
301  }
302 
303  if (set_count > 0) {
304  secfile_insert_str_vec(sfile, unit_names, set_count, "%s.%s", path,
305  entry);
306  }
307 
308  return true;
309 }
310 
314 static bool save_uclass_vec(struct section_file *sfile,
315  bv_unit_classes *bits, const char *path,
316  const char *entry, bool unreachable_only)
317 {
318  const char *class_names[UCL_LAST];
319  int classes = 0;
320 
321  unit_class_iterate(pcargo)
322  {
323  if (BV_ISSET(*(bits), uclass_index(pcargo))
324  && (uclass_has_flag(pcargo, UCF_UNREACHABLE) || !unreachable_only)) {
325  class_names[classes++] = uclass_rule_name(pcargo);
326  }
327  }
329 
330  if (classes > 0) {
331  secfile_insert_str_vec(sfile, class_names, classes, "%s.%s", path,
332  entry);
333  }
334 
335  return true;
336 }
337 
341 static bool save_strvec(struct section_file *sfile,
342  QVector<QString> *to_save, const char *path,
343  const char *entry)
344 {
345  if (to_save != nullptr) {
346  secfile_insert_str_vec(sfile, *to_save, to_save->size(), "%s.%s", path,
347  entry);
348  }
349 
350  return true;
351 }
352 
356 static bool save_ruleset_file(struct section_file *sfile,
357  const char *filename)
358 {
359  return secfile_save(sfile, filename);
360 }
361 
365 static bool save_buildings_ruleset(const char *filename, const char *name)
366 {
367  struct section_file *sfile = create_ruleset_file(name, "building");
368  int sect_idx;
369 
370  if (sfile == nullptr) {
371  return false;
372  }
373 
374  comment_buildings(sfile);
375 
376  sect_idx = 0;
378  {
379  if (!pb->ruledit_disabled) {
380  char path[512];
381  const char *flag_names[IF_COUNT];
382  int set_count;
383  int flagi;
384 
385  fc_snprintf(path, sizeof(path), "building_%d", sect_idx++);
386 
387  save_name_translation(sfile, &(pb->name), path);
388 
389  secfile_insert_str(sfile, impr_genus_id_name(pb->genus), "%s.genus",
390  path);
391 
392  if (strcmp(pb->graphic_str, "-")) {
393  secfile_insert_str(sfile, pb->graphic_str, "%s.graphic", path);
394  }
395  if (strcmp(pb->graphic_alt, "-")) {
396  secfile_insert_str(sfile, pb->graphic_alt, "%s.graphic_alt", path);
397  }
398  if (strcmp(pb->soundtag, "-")) {
399  secfile_insert_str(sfile, pb->soundtag, "%s.sound", path);
400  }
401  if (strcmp(pb->soundtag_alt, "-")) {
402  secfile_insert_str(sfile, pb->soundtag_alt, "%s.sound_alt", path);
403  }
404 
405  save_reqs_vector(sfile, &(pb->reqs), path, "reqs");
406  save_reqs_vector(sfile, &(pb->obsolete_by), path, "obsolete_by");
407 
408  secfile_insert_int(sfile, pb->build_cost, "%s.build_cost", path);
409  secfile_insert_int(sfile, pb->upkeep, "%s.upkeep", path);
410  secfile_insert_int(sfile, pb->sabotage, "%s.sabotage", path);
411 
412  set_count = 0;
413  for (flagi = 0; flagi < IF_COUNT; flagi++) {
414  if (improvement_has_flag(pb, impr_flag_id(flagi))) {
415  flag_names[set_count++] = impr_flag_id_name(impr_flag_id(flagi));
416  }
417  }
418 
419  if (set_count > 0) {
420  secfile_insert_str_vec(sfile, flag_names, set_count, "%s.flags",
421  path);
422  }
423 
424  save_strvec(sfile, pb->helptext, path, "helptext");
425  }
426  }
428 
429  return save_ruleset_file(sfile, filename);
430 }
431 
435 static bool save_styles_ruleset(const char *filename, const char *name)
436 {
437  struct section_file *sfile = create_ruleset_file(name, "styles");
438  int sect_idx;
439  int i;
440 
441  if (sfile == nullptr) {
442  return false;
443  }
444 
445  comment_styles(sfile);
446 
447  sect_idx = 0;
449  {
450  char path[512];
451 
452  fc_snprintf(path, sizeof(path), "style_%d", sect_idx++);
453 
454  save_name_translation(sfile, &(pstyle->name), path);
455  }
457 
458  comment_citystyles(sfile);
459 
460  sect_idx = 0;
461  for (i = 0; i < game.control.styles_count; i++) {
462  char path[512];
463 
464  fc_snprintf(path, sizeof(path), "citystyle_%d", sect_idx++);
465 
466  save_name_translation(sfile, &(city_styles[i].name), path);
467 
468  secfile_insert_str(sfile, city_styles[i].graphic, "%s.graphic", path);
469  secfile_insert_str(sfile, city_styles[i].graphic_alt, "%s.graphic_alt",
470  path);
471  if (strcmp(city_styles[i].citizens_graphic, "-")) {
472  secfile_insert_str(sfile, city_styles[i].citizens_graphic,
473  "%s.citizens_graphic", path);
474  }
475  if (strcmp(city_styles[i].citizens_graphic_alt, "generic")) {
476  secfile_insert_str(sfile, city_styles[i].citizens_graphic_alt,
477  "%s.citizens_graphic_alt", path);
478  }
479 
480  save_reqs_vector(sfile, &(city_styles[i].reqs), path, "reqs");
481  }
482 
483  comment_musicstyles(sfile);
484 
485  sect_idx = 0;
487  {
488  char path[512];
489 
490  fc_snprintf(path, sizeof(path), "musicstyle_%d", sect_idx++);
491 
492  secfile_insert_str(sfile, qUtf8Printable(pmus->music_peaceful),
493  "%s.music_peaceful", path);
494  secfile_insert_str(sfile, qUtf8Printable(pmus->music_combat),
495  "%s.music_combat", path);
496 
497  save_reqs_vector(sfile, &(pmus->reqs), path, "reqs");
498  }
500 
501  return save_ruleset_file(sfile, filename);
502 }
503 
511  struct section_file *sfile, const int aap, const char *uflags_path,
512  bool (*unexpected_req)(const struct requirement *preq))
513 {
514  enum unit_type_flag_id protecor_flag[MAX_NUM_USER_UNIT_FLAGS];
515  size_t i;
516  size_t ret;
517 
518  const struct action_auto_perf *auto_perf = action_auto_perf_by_number(aap);
519 
520  i = 0;
521  requirement_vector_iterate(&auto_perf->reqs, req)
522  {
523  fc_assert(req->range == REQ_RANGE_LOCAL);
524 
525  if (req->source.kind == VUT_UTFLAG) {
526  fc_assert(!req->present);
527 
528  protecor_flag[i++] = unit_type_flag_id(req->source.value.unitflag);
529  } else if (unexpected_req(req)) {
530  qCritical("Can't handle action auto performer requirement %s",
531  qUtf8Printable(req_to_fstring(req)));
532 
533  return false;
534  }
535  }
537 
538  ret = secfile_insert_enum_vec(sfile, &protecor_flag, i, unit_type_flag_id,
539  "%s", uflags_path);
540 
541  if (ret != i) {
542  qCritical("%s: didn't save all unit type flags.", uflags_path);
543 
544  return false;
545  }
546 
547  return true;
548 }
549 
556 static bool save_action_auto_actions(struct section_file *sfile,
557  const int aap, const char *actions_path)
558 {
559  enum gen_action unit_acts[MAX_NUM_ACTIONS];
560  size_t i;
561  size_t ret;
562 
563  const struct action_auto_perf *auto_perf = action_auto_perf_by_number(aap);
564 
565  i = 0;
566  for (i = 0; i < NUM_ACTIONS && auto_perf->alternatives[i] != ACTION_NONE;
567  i++) {
568  unit_acts[i] = gen_action(auto_perf->alternatives[i]);
569  }
570 
571  ret = secfile_insert_enum_vec(sfile, &unit_acts, i, gen_action, "%s",
572  actions_path);
573 
574  if (ret != i) {
575  qCritical("%s: didn't save all actions.", actions_path);
576 
577  return false;
578  }
579 
580  return true;
581 }
582 
587 static bool unexpected_non_otype(const struct requirement *req)
588 {
589  return !(req->source.kind == VUT_OTYPE && req->present);
590 }
591 
597 static bool save_muuk_action_auto(struct section_file *sfile, const int aap,
598  const char *item)
599 {
600  char uflags_path[100];
601  char action_path[100];
602 
603  fc_snprintf(uflags_path, sizeof(uflags_path),
604  "missing_unit_upkeep.%s_protected", item);
605  fc_snprintf(action_path, sizeof(action_path),
606  "missing_unit_upkeep.%s_unit_act", item);
607 
608  return (save_action_auto_uflag_block(sfile, aap, uflags_path,
610  && save_action_auto_actions(sfile, aap, action_path));
611 }
612 
616 static bool save_cities_ruleset(const char *filename, const char *name)
617 {
618  struct section_file *sfile = create_ruleset_file(name, "cities");
619  int sect_idx;
620 
621  if (sfile == nullptr) {
622  return false;
623  }
624 
625  comment_specialists(sfile);
626 
627  sect_idx = 0;
629  {
630  struct specialist *s = specialist_by_number(sp);
631  char path[512];
632 
633  fc_snprintf(path, sizeof(path), "specialist_%d", sect_idx++);
634 
635  save_name_translation(sfile, &(s->name), path);
636 
637  if (strcmp(rule_name_get(&s->name), rule_name_get(&s->abbreviation))) {
639  "%s.short_name", path);
640  }
641 
642  save_reqs_vector(sfile, &(s->reqs), path, "reqs");
643 
644  secfile_insert_str(sfile, s->graphic_str, "%s.graphic", path);
645  if (strcmp(s->graphic_alt, "-")) {
646  secfile_insert_str(sfile, s->graphic_alt, "%s.graphic_alt", path);
647  }
648 
649  save_strvec(sfile, s->helptext, path, "helptext");
650  }
652 
653  if (game.info.celebratesize != GAME_DEFAULT_CELEBRATESIZE) {
654  secfile_insert_int(sfile, game.info.celebratesize,
655  "parameters.celebrate_size_limit");
656  }
657  if (game.info.add_to_size_limit != GAME_DEFAULT_ADDTOSIZE) {
658  secfile_insert_int(sfile, game.info.add_to_size_limit,
659  "parameters.add_to_size_limit");
660  }
661  if (game.info.angrycitizen != GAME_DEFAULT_ANGRYCITIZEN) {
662  secfile_insert_bool(sfile, game.info.angrycitizen,
663  "parameters.angry_citizens");
664  }
665  if (game.info.changeable_budget != GAME_DEFAULT_CHANGEABLE_BUDGET) {
666  secfile_insert_bool(sfile, game.info.changeable_budget,
667  "parameters.changeable_budget");
668  }
669  if (game.info.forced_science != 0) {
670  secfile_insert_int(sfile, game.info.forced_science,
671  "parameters.forced_science");
672  }
673  if (game.info.forced_luxury != 100) {
674  secfile_insert_int(sfile, game.info.forced_luxury,
675  "parameters.forced_luxury");
676  }
677  if (game.info.forced_gold != 0) {
678  secfile_insert_int(sfile, game.info.forced_gold,
679  "parameters.forced_gold");
680  }
681  if (game.server.vision_reveal_tiles != GAME_DEFAULT_VISION_REVEAL_TILES) {
682  secfile_insert_bool(sfile, game.server.vision_reveal_tiles,
683  "parameters.vision_reveal_tiles");
684  }
685  if (game.info.pop_report_zeroes != 1) {
686  secfile_insert_int(sfile, game.info.pop_report_zeroes,
687  "parameters.pop_report_zeroes");
688  }
689  if (game.info.citizen_nationality != GAME_DEFAULT_NATIONALITY) {
690  secfile_insert_bool(sfile, game.info.citizen_nationality,
691  "citizen.nationality");
692  }
693  if (game.info.citizen_convert_speed != GAME_DEFAULT_CONVERT_SPEED) {
694  secfile_insert_int(sfile, game.info.citizen_convert_speed,
695  "citizen.convert_speed");
696  }
697  if (game.info.conquest_convert_pct != 0) {
698  secfile_insert_int(sfile, game.info.conquest_convert_pct,
699  "citizen.conquest_convert_pct");
700  }
701  if (game.info.citizen_partisans_pct != 0) {
702  secfile_insert_int(sfile, game.info.citizen_partisans_pct,
703  "citizen.partisans_pct");
704  }
705 
707  if (game.info.muuk_food_wipe != RS_DEFAULT_MUUK_FOOD_WIPE) {
708  secfile_insert_bool(sfile, game.info.muuk_food_wipe,
709  "missing_unit_upkeep.food_wipe");
710  }
711 
713  if (game.info.muuk_gold_wipe != RS_DEFAULT_MUUK_GOLD_WIPE) {
714  secfile_insert_bool(sfile, game.info.muuk_gold_wipe,
715  "missing_unit_upkeep.gold_wipe");
716  }
717 
719  if (game.info.muuk_shield_wipe != RS_DEFAULT_MUUK_SHIELD_WIPE) {
720  secfile_insert_bool(sfile, game.info.muuk_shield_wipe,
721  "missing_unit_upkeep.shield_wipe");
722  }
723 
724  return save_ruleset_file(sfile, filename);
725 }
726 
730 typedef struct {
731  int idx;
734 
738 static bool effect_save(struct effect *peffect, void *data)
739 {
740  effect_cb_data *cbdata = (effect_cb_data *) data;
741  char path[512];
742 
743  fc_snprintf(path, sizeof(path), "effect_%d", cbdata->idx++);
744 
745  secfile_insert_str(cbdata->sfile, effect_type_name(peffect->type),
746  "%s.type", path);
747  secfile_insert_int(cbdata->sfile, peffect->value, "%s.value", path);
748 
749  save_reqs_vector(cbdata->sfile, &peffect->reqs, path, "reqs");
750 
751  return true;
752 }
753 
757 static bool save_effects_ruleset(const char *filename, const char *name)
758 {
759  struct section_file *sfile = create_ruleset_file(name, "effect");
760  effect_cb_data data;
761 
762  if (sfile == nullptr) {
763  return false;
764  }
765 
766  data.idx = 0;
767  data.sfile = sfile;
768 
769  comment_effects(sfile);
770 
771  if (!iterate_effect_cache(effect_save, &data)) {
772  return false;
773  }
774 
775  return save_ruleset_file(sfile, filename);
776 }
777 
781 static bool save_action_ui_name(struct section_file *sfile, int act,
782  const char *entry_name)
783 {
784  const char *ui_name = action_by_number(act)->ui_name;
785 
786  if (strcmp(ui_name, action_ui_name_default(act))) {
787  secfile_insert_str(sfile, ui_name, "actions.%s", entry_name);
788  }
789 
790  return true;
791 }
792 
796 static bool save_action_max_range(struct section_file *sfile, action_id act)
797 {
798  if (action_by_number(act)->max_distance == ACTION_DISTANCE_UNLIMITED) {
799  return secfile_insert_str(sfile, RS_ACTION_NO_MAX_DISTANCE, "actions.%s",
801  != nullptr;
802  } else {
803  return save_default_int(sfile, action_by_number(act)->max_distance,
804  action_max_range_default(act), "actions",
806  }
807 }
808 
812 static bool save_action_range(struct section_file *sfile, action_id act)
813 {
814  if (action_min_range_ruleset_var_name(act) != nullptr) {
815  // Min range can be loaded from the ruleset.
816  save_default_int(sfile, action_by_number(act)->min_distance,
817  action_min_range_default(act), "actions",
819  }
820 
821  if (action_max_range_ruleset_var_name(act) != nullptr) {
822  // Max range can be loaded from the ruleset.
823  if (!save_action_max_range(sfile, act)) {
824  return false;
825  }
826  }
827 
828  return true;
829 }
830 
834 static bool save_action_kind(struct section_file *sfile, action_id act)
835 {
836  if (action_target_kind_ruleset_var_name(act) != nullptr) {
837  // Target kind can be loaded from the ruleset.
838  if ((action_by_number(act)->target_kind
840  && action_enabler_list_size(action_enablers_for_action(act)) == 0) {
841  // Don't save the default for actions that aren't enabled.
842  return true;
843  }
844 
845  secfile_insert_enum(sfile, action_by_number(act)->target_kind,
846  action_target_kind, "actions.%s",
848  }
849 
850  return true;
851 }
852 
857  action_id act)
858 {
860  // Actor consumption can be loaded from the ruleset.
861  if (action_enabler_list_size(action_enablers_for_action(act)) == 0) {
862  // Don't save value for actions that aren't enabled.
863  return true;
864  }
865 
866  save_default_bool(sfile, action_by_number(act)->actor_consuming_always,
869  }
870 
871  return true;
872 }
873 
877 static bool save_game_ruleset(const char *filename, const char *name)
878 {
879  struct section_file *sfile = create_ruleset_file(name, "game");
880  int sect_idx;
881  int col_idx;
882  int set_count;
883  enum gameloss_style gs;
884  const char
885  *style_names[32]; /* FIXME: Should determine max length automatically.
886  * currently it's 3 (bits 0,1, and 2) so there's
887  * plenty of safety margin here. */
888  const char *tnames[game.server.ruledit.named_teams];
889  int i;
890  enum gen_action quiet_actions[MAX_NUM_ACTIONS];
891  bool locks;
892  int force_capture_units, force_bombard, force_explode_nuclear;
893 
894  if (sfile == nullptr) {
895  return false;
896  }
897 
898  if (game.server.ruledit.description_file != nullptr) {
899  secfile_insert_str(sfile, game.server.ruledit.description_file,
900  "ruledit.description_file");
901  }
902 
903  if (game.control.preferred_tileset[0] != '\0') {
904  secfile_insert_str(sfile, game.control.preferred_tileset,
905  "tileset.preferred");
906  }
907  if (game.control.preferred_soundset[0] != '\0') {
908  secfile_insert_str(sfile, game.control.preferred_soundset,
909  "soundset.preferred");
910  }
911  if (game.control.preferred_musicset[0] != '\0') {
912  secfile_insert_str(sfile, game.control.preferred_musicset,
913  "musicset.preferred");
914  }
915 
916  secfile_insert_str(sfile, game.control.name, "about.name");
917  secfile_insert_str(sfile, game.control.version, "about.version");
918 
919  if (game.control.alt_dir[0] != '\0') {
920  secfile_insert_str(sfile, game.control.alt_dir, "about.alt_dir");
921  }
922 
923  if (game.ruleset_summary != nullptr) {
924  struct entry *mod_entry;
925 
926  mod_entry =
927  secfile_insert_str(sfile, game.ruleset_summary, "about.summary");
928  entry_str_set_gt_marking(mod_entry, true);
929  }
930 
931  if (game.ruleset_description != nullptr) {
932  if (game.server.ruledit.description_file == nullptr) {
934  "about.description");
935  } else {
937  sfile, game.server.ruledit.description_file, "about.description");
938  }
939  }
940 
941  if (game.ruleset_capabilities != nullptr) {
943  "about.capabilities");
944  } else {
945  secfile_insert_str(sfile, "", "about.capabilities");
946  }
947 
948  save_tech_list(sfile, game.rgame.global_init_techs, "options",
949  "global_init_techs");
951  "global_init_buildings");
952 
953  save_default_bool(sfile, game.control.popup_tech_help, false,
954  "options.popup_tech_help", nullptr);
955  save_default_int(sfile, game.info.base_pollution,
956  RS_DEFAULT_BASE_POLLUTION, "civstyle.base_pollution",
957  nullptr);
958 
959  set_count = 0;
960  for (gs = gameloss_style_begin(); gs != gameloss_style_end();
961  gs = gameloss_style_next(gs)) {
962  if (game.info.gameloss_style & gs) {
963  style_names[set_count++] = gameloss_style_name(gs);
964  }
965  }
966 
967  if (set_count > 0) {
968  secfile_insert_str_vec(sfile, style_names, set_count,
969  "civstyle.gameloss_style");
970  }
971 
972  save_default_int(sfile, game.info.happy_cost, RS_DEFAULT_HAPPY_COST,
973  "civstyle.happy_cost", nullptr);
975  "civstyle.food_cost", nullptr);
976  save_default_bool(sfile, game.info.civil_war_enabled, true,
977  "civstyle.civil_war_enabled", nullptr);
978  save_default_int(sfile, game.info.civil_war_bonus_celebrating,
980  "civstyle.civil_war_bonus_celebrating", nullptr);
981  save_default_int(sfile, game.info.civil_war_bonus_unhappy,
983  "civstyle.civil_war_bonus_unhappy", nullptr);
984  save_default_bool(sfile, game.info.paradrop_to_transport, false,
985  "civstyle.paradrop_to_transport", nullptr);
986  save_default_int(sfile, game.info.base_bribe_cost,
987  RS_DEFAULT_BASE_BRIBE_COST, "civstyle.base_bribe_cost",
988  nullptr);
990  "civstyle.ransom_gold", nullptr);
991  save_default_bool(sfile, game.info.pillage_select,
992  RS_DEFAULT_PILLAGE_SELECT, "civstyle.pillage_select",
993  nullptr);
994  save_default_bool(sfile, game.info.tech_steal_allow_holes,
996  "civstyle.tech_steal_allow_holes", nullptr);
997  save_default_bool(sfile, game.info.tech_trade_allow_holes,
999  "civstyle.tech_trade_allow_holes", nullptr);
1000  save_default_bool(sfile, game.info.tech_trade_loss_allow_holes,
1002  "civstyle.tech_trade_loss_allow_holes", nullptr);
1003  save_default_bool(sfile, game.info.tech_parasite_allow_holes,
1005  "civstyle.tech_parasite_allow_holes", nullptr);
1006  save_default_bool(sfile, game.info.tech_loss_allow_holes,
1008  "civstyle.tech_loss_allow_holes", nullptr);
1009  save_default_int(sfile, game.server.upgrade_veteran_loss,
1011  "civstyle.upgrade_veteran_loss", nullptr);
1012  save_default_int(sfile, game.server.autoupgrade_veteran_loss,
1014  "civstyle.autoupgrade_veteran_loss", nullptr);
1015 
1016  secfile_insert_int_vec(sfile, game.info.granary_food_ini,
1017  game.info.granary_num_inis,
1018  "civstyle.granary_food_ini");
1019 
1020  save_default_int(sfile, game.info.granary_food_inc,
1021  RS_DEFAULT_GRANARY_FOOD_INC, "civstyle.granary_food_inc",
1022  nullptr);
1023 
1025  {
1026  char buffer[256];
1027 
1028  fc_snprintf(buffer, sizeof(buffer), "civstyle.min_city_center_%s",
1030 
1031  save_default_int(sfile, game.info.min_city_center_output[o],
1032  RS_DEFAULT_CITY_CENTER_OUTPUT, buffer, nullptr);
1033  }
1035 
1036  save_default_int(sfile, game.server.init_vis_radius_sq,
1037  RS_DEFAULT_VIS_RADIUS_SQ, "civstyle.init_vis_radius_sq",
1038  nullptr);
1039  save_default_int(sfile, game.info.init_city_radius_sq,
1040  RS_DEFAULT_CITY_RADIUS_SQ, "civstyle.init_city_radius_sq",
1041  nullptr);
1042  if (0
1043  != fc_strcasecmp(gold_upkeep_style_name(game.info.gold_upkeep_style),
1045  secfile_insert_str(sfile,
1046  gold_upkeep_style_name(game.info.gold_upkeep_style),
1047  "civstyle.gold_upkeep_style");
1048  }
1049  save_default_int(sfile, game.info.granularity, 1,
1050  "civstyle.output_granularity", nullptr);
1051  save_default_bool(sfile, game.info.illness_on, RS_DEFAULT_ILLNESS_ON,
1052  "illness.illness_on", nullptr);
1053  save_default_int(sfile, game.info.illness_base_factor,
1055  "illness.illness_base_factor", nullptr);
1056  save_default_int(sfile, game.info.illness_min_size,
1057  RS_DEFAULT_ILLNESS_MIN_SIZE, "illness.illness_min_size",
1058  nullptr);
1059  save_default_int(sfile, game.info.illness_trade_infection,
1061  "illness.illness_trade_infection", nullptr);
1062  save_default_int(sfile, game.info.illness_pollution_factor,
1064  "illness.illness_pollution_factor", nullptr);
1065  save_default_int(sfile, game.server.base_incite_cost,
1067  "incite_cost.base_incite_cost", nullptr);
1068  save_default_int(sfile, game.server.incite_improvement_factor,
1070  "incite_cost.improvement_factor", nullptr);
1071  save_default_int(sfile, game.server.incite_unit_factor,
1072  RS_DEFAULT_INCITE_UNIT_FCT, "incite_cost.unit_factor",
1073  nullptr);
1074  save_default_int(sfile, game.server.incite_total_factor,
1075  RS_DEFAULT_INCITE_TOTAL_FCT, "incite_cost.total_factor",
1076  nullptr);
1077 
1078  {
1079  /* Action auto performers aren't ready to be exposed in the ruleset
1080  * yet. The behavior when two action auto performers for the same
1081  * cause can fire isn't set in stone yet. How is one of them chosen?
1082  * What if all the actions of the chosen action auto performer turned
1083  * out to be illegal but one of the other action auto performers that
1084  * fired has legal actions? These issues can decide what other action
1085  * rules action auto performers can represent in the future. Deciding
1086  * should therefore wait until a rule needs action auto performers to
1087  * work a certain way. */
1088  /* Only one action auto performer, ACTION_AUTO_MOVED_ADJ, is caused
1089  * by AAPC_UNIT_MOVED_ADJ. It is therefore safe to expose the full
1090  * requirement vector to the ruleset. */
1091  const struct action_auto_perf *auto_perf =
1093 
1095  "auto_attack.attack_actions");
1096 
1097  save_reqs_vector(sfile, &auto_perf->reqs, "auto_attack", "if_attacker");
1098  }
1099 
1101  sfile,
1102  action_id_would_be_blocked_by(ACTION_MARKETPLACE, ACTION_TRADE_ROUTE),
1103  RS_DEFAULT_FORCE_TRADE_ROUTE, "actions.force_trade_route", nullptr);
1104 
1105  /* The ruleset options force_capture_units, force_bombard and
1106  * force_explode_nuclear sets their respective action to block many other
1107  * actions' blocked_by. Checking one is therefore enough. */
1108  force_capture_units = BV_ISSET(action_by_number(ACTION_ATTACK)->blocked_by,
1109  ACTION_CAPTURE_UNITS);
1110  save_default_bool(sfile, force_capture_units,
1112  "actions.force_capture_units", nullptr);
1113  force_bombard =
1114  BV_ISSET(action_by_number(ACTION_ATTACK)->blocked_by, ACTION_BOMBARD);
1115  save_default_bool(sfile, force_bombard, RS_DEFAULT_FORCE_BOMBARD,
1116  "actions.force_bombard", nullptr);
1117  force_explode_nuclear =
1118  BV_ISSET(action_by_number(ACTION_ATTACK)->blocked_by, ACTION_NUKE);
1119  save_default_bool(sfile, force_explode_nuclear,
1121  "actions.force_explode_nuclear", nullptr);
1122 
1123  save_default_bool(sfile, game.info.poison_empties_food_stock,
1125  "actions.poison_empties_food_stock", nullptr);
1126 
1127  save_default_bool(sfile, game.info.steal_maps_reveals_all_cities,
1129  "actions.steal_maps_reveals_all_cities", nullptr);
1130 
1131  action_iterate(act_id)
1132  {
1133  save_action_ui_name(sfile, act_id,
1135  save_action_kind(sfile, act_id);
1136  save_action_range(sfile, act_id);
1137  save_action_actor_consuming_always(sfile, act_id);
1138  }
1140 
1141  i = 0;
1142  action_iterate(act)
1143  {
1144  if (action_by_number(act)->quiet) {
1145  quiet_actions[i] = gen_action(act);
1146  i++;
1147  }
1148  }
1150 
1151  if (secfile_insert_enum_vec(sfile, &quiet_actions, i, gen_action,
1152  "actions.quiet_actions")
1153  != i) {
1154  qCritical("Didn't save all quiet actions.");
1155 
1156  return false;
1157  }
1158 
1159  comment_enablers(sfile);
1160  sect_idx = 0;
1162  {
1163  char path[512];
1164 
1165  if (pae->disabled) {
1166  continue;
1167  }
1168 
1169  fc_snprintf(path, sizeof(path), "actionenabler_%d", sect_idx++);
1170 
1171  secfile_insert_str(sfile, action_id_rule_name(pae->action), "%s.action",
1172  path);
1173 
1174  save_reqs_vector(sfile, &(pae->actor_reqs), path, "actor_reqs");
1175  save_reqs_vector(sfile, &(pae->target_reqs), path, "target_reqs");
1176  }
1178 
1179  save_default_bool(sfile, game.info.tired_attack, RS_DEFAULT_TIRED_ATTACK,
1180  "combat_rules.tired_attack", nullptr);
1181  save_default_bool(sfile, game.info.only_killing_makes_veteran,
1183  "combat_rules.only_killing_makes_veteran", nullptr);
1184  save_default_int(sfile, game.info.nuke_pop_loss_pct,
1186  "combat_rules.nuke_pop_loss_pct", nullptr);
1187  save_default_int(sfile, game.info.nuke_defender_survival_chance_pct,
1189  "combat_rules.nuke_defender_survival_chance_pct",
1190  nullptr);
1191  save_default_int(sfile, game.info.border_city_radius_sq,
1193  "borders.radius_sq_city", nullptr);
1194  save_default_int(sfile, game.info.border_size_effect,
1195  RS_DEFAULT_BORDER_SIZE_EFFECT, "borders.size_effect",
1196  nullptr);
1197  save_default_int(sfile, game.info.border_city_permanent_radius_sq,
1199  "borders.radius_sq_city_permanent", nullptr);
1200  secfile_insert_str(sfile, tech_cost_style_name(game.info.tech_cost_style),
1201  "research.tech_cost_style");
1202  save_default_int(sfile, game.info.base_tech_cost,
1203  RS_DEFAULT_BASE_TECH_COST, "research.base_tech_cost",
1204  nullptr);
1205  secfile_insert_str(sfile, tech_leakage_style_name(game.info.tech_leakage),
1206  "research.tech_leakage");
1207  secfile_insert_str(sfile,
1208  tech_upkeep_style_name(game.info.tech_upkeep_style),
1209  "research.tech_upkeep_style");
1210  save_default_int(sfile, game.info.tech_upkeep_divider,
1212  "research.tech_upkeep_divider", nullptr);
1213  secfile_insert_str(sfile,
1214  free_tech_method_name(game.info.free_tech_method),
1215  "research.free_tech_method");
1216 
1217  save_default_int(sfile, game.info.culture_vic_points,
1219  "culture.victory_min_points", nullptr);
1220  save_default_int(sfile, game.info.culture_vic_lead,
1221  RS_DEFAULT_CULTURE_VIC_LEAD, "culture.victory_lead_pct",
1222  nullptr);
1223  save_default_int(sfile, game.info.culture_migration_pml,
1224  RS_DEFAULT_CULTURE_MIGRATION_PML, "culture.migration_pml",
1225  nullptr);
1226  save_default_int(sfile, game.info.history_interest_pml,
1228  "culture.history_interest_pml", nullptr);
1229 
1230  save_default_bool(sfile, game.calendar.calendar_skip_0,
1231  RS_DEFAULT_CALENDAR_SKIP_0, "calendar.skip_year_0",
1232  nullptr);
1233  save_default_int(sfile, game.server.start_year, GAME_START_YEAR,
1234  "calendar.start_year", nullptr);
1235  save_default_int(sfile, game.calendar.calendar_fragments, 0,
1236  "calendar.fragments", nullptr);
1237 
1238  for (i = 0; i < MAX_CALENDAR_FRAGMENTS; i++) {
1239  if (game.calendar.calendar_fragment_name[i][0] != '\0') {
1240  secfile_insert_str(sfile, game.calendar.calendar_fragment_name[i],
1241  "calendar.fragment_name%d", i);
1242  }
1243  }
1244 
1245  if (strcmp(game.calendar.positive_year_label, RS_DEFAULT_POS_YEAR_LABEL)) {
1246  secfile_insert_str(sfile, game.calendar.positive_year_label,
1247  "calendar.positive_label");
1248  }
1249  if (strcmp(game.calendar.negative_year_label, RS_DEFAULT_NEG_YEAR_LABEL)) {
1250  secfile_insert_str(sfile, game.calendar.negative_year_label,
1251  "calendar.negative_label");
1252  }
1253 
1254  if (game.plr_bg_color != nullptr) {
1255  rgbcolor_save(sfile, game.plr_bg_color, "playercolors.background");
1256  }
1257 
1258  col_idx = 0;
1259  rgbcolor_list_iterate(game.server.plr_colors, pcol)
1260  {
1261  rgbcolor_save(sfile, pcol, "playercolors.colorlist%d", col_idx++);
1262  }
1264 
1265  if (game.server.ruledit.named_teams > 0) {
1266  for (i = 0; i < game.server.ruledit.named_teams; i++) {
1267  tnames[i] = team_slot_rule_name(team_slot_by_number(i));
1268  }
1269 
1270  secfile_insert_str_vec(sfile, tnames, game.server.ruledit.named_teams,
1271  "teams.names");
1272  }
1273 
1274  comment_disasters(sfile);
1275 
1276  sect_idx = 0;
1278  {
1279  char path[512];
1280  enum disaster_effect_id de;
1281  const char *effect_names[DE_COUNT];
1282 
1283  fc_snprintf(path, sizeof(path), "disaster_%d", sect_idx++);
1284 
1285  save_name_translation(sfile, &(pd->name), path);
1286  save_reqs_vector(sfile, &(pd->reqs), path, "reqs");
1287  if (pd->frequency != GAME_DEFAULT_DISASTER_FREQ) {
1288  secfile_insert_int(sfile, pd->frequency, "%s.frequency", path);
1289  }
1290 
1291  set_count = 0;
1292  for (de = disaster_effect_id_begin(); de != disaster_effect_id_end();
1293  de = disaster_effect_id_next(de)) {
1294  if (BV_ISSET(pd->effects, de)) {
1295  effect_names[set_count++] = disaster_effect_id_name(de);
1296  }
1297  }
1298 
1299  if (set_count > 0) {
1300  secfile_insert_str_vec(sfile, effect_names, set_count, "%s.effects",
1301  path);
1302  }
1303  }
1305 
1306  comment_achievements(sfile);
1307 
1308  sect_idx = 0;
1309  achievements_iterate(pach)
1310  {
1311  char path[512];
1312 
1313  fc_snprintf(path, sizeof(path), "achievement_%d", sect_idx++);
1314 
1315  save_name_translation(sfile, &(pach->name), path);
1316 
1317  secfile_insert_str(sfile, achievement_type_name(pach->type), "%s.type",
1318  path);
1319 
1320  save_default_bool(sfile, pach->unique, GAME_DEFAULT_ACH_UNIQUE, path,
1321  "unique");
1322  save_default_int(sfile, pach->value, GAME_DEFAULT_ACH_VALUE, path,
1323  "value");
1324  save_default_int(sfile, pach->culture, 0, path, "culture");
1325 
1326  secfile_insert_str(sfile, pach->first_msg, "%s.first_msg", path);
1327  if (pach->cons_msg != nullptr) {
1328  secfile_insert_str(sfile, pach->cons_msg, "%s.cons_msg", path);
1329  }
1330  }
1332 
1333  set_count = 0;
1334  for (int itrt = 0; itrt < TRT_LAST; itrt++) {
1335  trade_route_type trt = trade_route_type(itrt);
1337  const char *cancelling =
1339 
1340  if (set->trade_pct != 100 || strcmp(cancelling, "Active")) {
1341  char path[256];
1342 
1343  fc_snprintf(path, sizeof(path), "trade.settings%d", set_count++);
1344 
1345  secfile_insert_str(sfile, trade_route_type_name(trt), "%s.type", path);
1346  secfile_insert_int(sfile, set->trade_pct, "%s.pct", path);
1347  secfile_insert_str(sfile, cancelling, "%s.cancelling", path);
1348  secfile_insert_str(sfile, traderoute_bonus_type_name(set->bonus_type),
1349  "%s.bonus", path);
1350  }
1351  }
1352 
1353  // Goods
1354  comment_goods(sfile);
1355 
1356  sect_idx = 0;
1358  {
1359  char path[512];
1360  const char *flag_names[GF_COUNT];
1361  int flagi;
1362 
1363  fc_snprintf(path, sizeof(path), "goods_%d", sect_idx++);
1364 
1365  save_name_translation(sfile, &(pgood->name), path);
1366 
1367  save_reqs_vector(sfile, &(pgood->reqs), path, "reqs");
1368 
1369  save_default_int(sfile, pgood->from_pct, 100, path, "from_pct");
1370  save_default_int(sfile, pgood->to_pct, 100, path, "to_pct");
1371  save_default_int(sfile, pgood->onetime_pct, 100, path, "onetime_pct");
1372 
1373  set_count = 0;
1374  for (flagi = 0; flagi < GF_COUNT; flagi++) {
1375  if (goods_has_flag(pgood, goods_flag_id(flagi))) {
1376  flag_names[set_count++] = goods_flag_id_name(goods_flag_id(flagi));
1377  }
1378  }
1379 
1380  if (set_count > 0) {
1381  secfile_insert_str_vec(sfile, flag_names, set_count, "%s.flags", path);
1382  }
1383 
1384  save_strvec(sfile, pgood->helptext, path, "helptext");
1385  }
1387 
1388  // Clauses
1389  comment_clauses(sfile);
1390 
1391  sect_idx = 0;
1392  for (i = 0; i < CLAUSE_COUNT; i++) {
1393  struct clause_info *info = clause_info_get(clause_type(i));
1394 
1395  if (info->enabled) {
1396  char path[512];
1397 
1398  fc_snprintf(path, sizeof(path), "clause_%d", sect_idx++);
1399 
1400  secfile_insert_str(sfile, clause_type_name(info->type), "%s.type",
1401  path);
1402  save_reqs_vector(sfile, &(info->giver_reqs), path, "giver_reqs");
1403  save_reqs_vector(sfile, &(info->receiver_reqs), path, "receiver_reqs");
1404  }
1405  }
1406 
1407  locks = false;
1408  settings_iterate(SSET_ALL, pset)
1409  {
1410  if (setting_locked(pset)) {
1411  locks = true;
1412  break;
1413  }
1414  }
1416 
1417  set_count = 0;
1418  settings_iterate(SSET_ALL, pset)
1419  {
1420  if (setting_get_setdef(pset) == SETDEF_RULESET || setting_locked(pset)) {
1421  secfile_insert_str(sfile, setting_name(pset), "settings.set%d.name",
1422  set_count);
1423  switch (setting_type(pset)) {
1424  case SST_BOOL:
1426  "settings.set%d.value", set_count);
1427  break;
1428  case SST_INT:
1429  secfile_insert_int(sfile, setting_int_get(pset),
1430  "settings.set%d.value", set_count);
1431  break;
1432  case SST_STRING:
1433  secfile_insert_str(sfile, setting_str_get(pset),
1434  "settings.set%d.value", set_count);
1435  break;
1436  case SST_ENUM:
1437  secfile_insert_enum_data(sfile, read_enum_value(pset), false,
1439  "settings.set%d.value", set_count);
1440  break;
1441  case SST_BITWISE:
1442  secfile_insert_enum_data(sfile, setting_bitwise_get(pset), true,
1444  "settings.set%d.value", set_count);
1445  break;
1446  case SST_COUNT:
1447  fc_assert(setting_type(pset) != SST_COUNT);
1448  secfile_insert_str(sfile, "Unknown setting type",
1449  "settings.set%d.value", set_count);
1450  break;
1451  }
1452 
1453  if (locks) {
1454  secfile_insert_bool(sfile, setting_locked(pset),
1455  "settings.set%d.lock", set_count);
1456  }
1457 
1458  set_count++;
1459  }
1460  }
1462 
1463  return save_ruleset_file(sfile, filename);
1464 }
1465 
1469 static bool save_governments_ruleset(const char *filename, const char *name)
1470 {
1471  struct section_file *sfile = create_ruleset_file(name, "government");
1472  int sect_idx;
1473 
1474  if (sfile == nullptr) {
1475  return false;
1476  }
1477 
1478  save_gov_ref(sfile, game.government_during_revolution, "governments",
1479  "during_revolution");
1480 
1481  comment_govs(sfile);
1482 
1483  sect_idx = 0;
1484  for (auto &pg : governments) {
1485  if (!pg.ruledit_disabled) {
1486  {
1487  char path[512];
1488 
1489  fc_snprintf(path, sizeof(path), "government_%d", sect_idx++);
1490 
1491  save_name_translation(sfile, &(pg.name), path);
1492 
1493  secfile_insert_str(sfile, pg.graphic_str, "%s.graphic", path);
1494  secfile_insert_str(sfile, pg.graphic_alt, "%s.graphic_alt", path);
1495 
1496  save_reqs_vector(sfile, &pg.reqs, path, "reqs");
1497 
1498  if (pg.ai.better != nullptr) {
1499  save_gov_ref(sfile, pg.ai.better, path, "ai_better");
1500  }
1501 
1502  const auto prtitle = pg.ruler_titles->value(nullptr);
1503  if (prtitle != nullptr) {
1504  const char *title;
1505 
1506  title = ruler_title_male_untranslated_name(prtitle);
1507  if (title != nullptr) {
1508  secfile_insert_str(sfile, title, "%s.ruler_male_title", path);
1509  }
1510 
1511  title = ruler_title_female_untranslated_name(prtitle);
1512  if (title != nullptr) {
1513  secfile_insert_str(sfile, title, "%s.ruler_female_title", path);
1514  }
1515  }
1516 
1517  save_strvec(sfile, pg.helptext, path, "helptext");
1518  }
1519  }
1520  } // iterate governments - pg
1521 
1522  comment_policies(sfile);
1523 
1524  sect_idx = 0;
1525  multipliers_iterate(pmul)
1526  {
1527  if (!pmul->ruledit_disabled) {
1528  char path[512];
1529 
1530  fc_snprintf(path, sizeof(path), "multiplier_%d", sect_idx++);
1531 
1532  save_name_translation(sfile, &(pmul->name), path);
1533 
1534  secfile_insert_int(sfile, pmul->start, "%s.start", path);
1535  secfile_insert_int(sfile, pmul->stop, "%s.stop", path);
1536  secfile_insert_int(sfile, pmul->step, "%s.step", path);
1537  secfile_insert_int(sfile, pmul->def, "%s.default", path);
1538 
1539  save_reqs_vector(sfile, &(pmul->reqs), path, "reqs");
1540 
1541  save_strvec(sfile, pmul->helptext, path, "helptext");
1542  }
1543  }
1545 
1546  return save_ruleset_file(sfile, filename);
1547 }
1548 
1552 static bool save_traits(struct trait_limits *traits,
1553  struct trait_limits *default_traits,
1554  struct section_file *sfile, const char *secname,
1555  const char *field_prefix)
1556 {
1557  enum trait tr;
1558 
1559  /* FIXME: Use specenum trait names without duplicating them here.
1560  * Just needs to take care of case. */
1561  const char *trait_names[] = {"expansionist", "trader", "aggressive",
1562  nullptr};
1563 
1564  for (tr = trait_begin(); tr != trait_end() && trait_names[tr] != nullptr;
1565  tr = trait_next(tr)) {
1566  int default_default;
1567 
1568  default_default = (traits[tr].min + traits[tr].max) / 2;
1569 
1570  if ((default_traits == nullptr && traits[tr].min != TRAIT_DEFAULT_VALUE)
1571  || (default_traits != nullptr
1572  && traits[tr].min != default_traits[tr].min)) {
1573  secfile_insert_int(sfile, traits[tr].min, "%s.%s%s_min", secname,
1574  field_prefix, trait_names[tr]);
1575  }
1576  if ((default_traits == nullptr && traits[tr].max != TRAIT_DEFAULT_VALUE)
1577  || (default_traits != nullptr
1578  && traits[tr].max != default_traits[tr].max)) {
1579  secfile_insert_int(sfile, traits[tr].max, "%s.%s%s_max", secname,
1580  field_prefix, trait_names[tr]);
1581  }
1582  if (default_default != traits[tr].fixed) {
1583  secfile_insert_int(sfile, traits[tr].fixed, "%s.%s%s_default", secname,
1584  field_prefix, trait_names[tr]);
1585  }
1586  }
1587 
1588  return true;
1589 }
1590 
1594 static bool save_nation(struct section_file *sfile, struct nation_type *pnat,
1595  int sect_idx)
1596 {
1597  char path[512];
1598  int max_items = nation_city_list_size(pnat->server.default_cities);
1599  char *city_str[max_items];
1600  max_items = MAX(max_items, MAX_NUM_NATION_SETS + MAX_NUM_NATION_GROUPS);
1601  max_items = MAX(max_items, game.control.nation_count);
1602  const char *list_items[max_items];
1603  int set_count;
1604  int subsect_idx;
1605 
1606  fc_snprintf(path, sizeof(path), "nation_%d", sect_idx++);
1607 
1608  if (pnat->translation_domain == nullptr) {
1609  secfile_insert_str(sfile, "freeciv", "%s.translation_domain", path);
1610  } else {
1612  "%s.translation_domain", path);
1613  }
1614 
1615  save_name_translation(sfile, &(pnat->adjective), path);
1617  "%s.plural", path);
1618 
1619  set_count = 0;
1620  nation_sets_iterate(pset)
1621  {
1622  if (nation_is_in_set(pnat, pset)) {
1623  list_items[set_count++] = nation_set_rule_name(pset);
1624  }
1625  }
1627  nation_groups_iterate(pgroup)
1628  {
1629  if (nation_is_in_group(pnat, pgroup)) {
1630  list_items[set_count++] = nation_group_rule_name(pgroup);
1631  }
1632  }
1634 
1635  if (set_count > 0) {
1636  secfile_insert_str_vec(sfile, list_items, set_count, "%s.groups", path);
1637  }
1638 
1639  set_count = 0;
1640  nation_list_iterate(pnat->server.conflicts_with, pconfl)
1641  {
1642  list_items[set_count++] = nation_rule_name(pconfl);
1643  }
1645  if (set_count > 0) {
1646  secfile_insert_str_vec(sfile, list_items, set_count, "%s.conflicts_with",
1647  path);
1648  }
1649 
1650  subsect_idx = 0;
1651  nation_leader_list_iterate(pnat->leaders, pleader)
1652  {
1653  secfile_insert_str(sfile, nation_leader_name(pleader),
1654  "%s.leaders%d.name", path, subsect_idx);
1655  secfile_insert_str(sfile,
1656  nation_leader_is_male(pleader) ? "Male" : "Female",
1657  "%s.leaders%d.sex", path, subsect_idx++);
1658  }
1660 
1661  if (pnat->server.rgb != nullptr) {
1662  rgbcolor_save(sfile, pnat->server.rgb, "%s.color", path);
1663  }
1664 
1665  save_traits(pnat->server.traits, game.server.default_traits, sfile, path,
1666  "trait_");
1667 
1668  if (!pnat->is_playable) {
1669  secfile_insert_bool(sfile, pnat->is_playable, "%s.is_playable", path);
1670  }
1671 
1672  if (pnat->barb_type != NOT_A_BARBARIAN) {
1673  secfile_insert_str(sfile, barbarian_type_name(pnat->barb_type),
1674  "%s.barbarian_type", path);
1675  }
1676 
1677  if (strcmp(pnat->flag_graphic_str, "-")) {
1678  secfile_insert_str(sfile, pnat->flag_graphic_str, "%s.flag", path);
1679  }
1680  if (strcmp(pnat->flag_graphic_alt, "-")) {
1681  secfile_insert_str(sfile, pnat->flag_graphic_alt, "%s.flag_alt", path);
1682  }
1683 
1684  subsect_idx = 0;
1685  for (auto &pgov : governments) {
1686  struct ruler_title *prtitle;
1687  prtitle = pgov.ruler_titles->value(pnat);
1688  if (prtitle) {
1690  "%s.ruler_titles%d.government", path, subsect_idx);
1692  "%s.ruler_titles%d.male_title", path, subsect_idx);
1694  sfile, ruler_title_female_untranslated_name(prtitle),
1695  "%s.ruler_titles%d.female_title", path, subsect_idx++);
1696  }
1697  }
1698 
1699  secfile_insert_str(sfile, style_rule_name(pnat->style), "%s.style", path);
1700 
1701  set_count = 0;
1702  nation_list_iterate(pnat->server.civilwar_nations, pconfl)
1703  {
1704  list_items[set_count++] = nation_rule_name(pconfl);
1705  }
1707  if (set_count > 0) {
1708  secfile_insert_str_vec(sfile, list_items, set_count,
1709  "%s.civilwar_nations", path);
1710  }
1711 
1712  save_tech_list(sfile, pnat->init_techs, path, "init_techs");
1713  save_building_list(sfile, pnat->init_buildings, path, "init_buildings");
1714  save_unit_list(sfile, pnat->init_units, path, "init_units");
1715 
1716  if (pnat->init_government) {
1718  "%s.init_government", path);
1719  }
1720 
1721  set_count = 0;
1722  nation_city_list_iterate(pnat->server.default_cities, pncity)
1723  {
1724  bool list_started = false;
1725 
1726  city_str[set_count] =
1727  new char[strlen(nation_city_name(pncity)) + qstrlen(" (!river")
1728  + qstrlen(")")
1729  + MAX_NUM_TERRAINS * (strlen(", ") + MAX_LEN_NAME)];
1730 
1731  qstrcpy(city_str[set_count], nation_city_name(pncity));
1732  switch (nation_city_river_preference(pncity)) {
1733  case NCP_DISLIKE:
1734  strcat(city_str[set_count], " (!river");
1735  list_started = true;
1736  break;
1737  case NCP_LIKE:
1738  strcat(city_str[set_count], " (river");
1739  list_started = true;
1740  break;
1741  case NCP_NONE:
1742  break;
1743  }
1744 
1745  terrain_type_iterate(pterr)
1746  {
1747  const char *pref = nullptr;
1748 
1749  switch (nation_city_terrain_preference(pncity, pterr)) {
1750  case NCP_DISLIKE:
1751  pref = "!";
1752  break;
1753  case NCP_LIKE:
1754  pref = "";
1755  break;
1756  case NCP_NONE:
1757  pref = nullptr;
1758  break;
1759  }
1760 
1761  if (pref != nullptr) {
1762  if (list_started) {
1763  strcat(city_str[set_count], ", ");
1764  } else {
1765  strcat(city_str[set_count], " (");
1766  list_started = true;
1767  }
1768  strcat(city_str[set_count], pref);
1769  strcat(city_str[set_count], terrain_rule_name(pterr));
1770  }
1771  }
1773 
1774  if (list_started) {
1775  strcat(city_str[set_count], ")");
1776  }
1777 
1778  list_items[set_count] = city_str[set_count];
1779  set_count++;
1780  }
1782  if (set_count > 0) {
1783  int i;
1784 
1785  secfile_insert_str_vec(sfile, list_items, set_count, "%s.cities", path);
1786 
1787  for (i = 0; i < set_count; i++) {
1788  delete[] city_str[i];
1789  city_str[i] = nullptr;
1790  }
1791  }
1792 
1793  secfile_insert_str(sfile, pnat->legend, "%s.legend", path);
1794 
1795  return true;
1796 }
1797 
1801 static bool save_nations_ruleset(const char *filename, const char *name,
1802  struct rule_data *data)
1803 {
1804  struct section_file *sfile = create_ruleset_file(name, "nation");
1805 
1806  if (sfile == nullptr) {
1807  return false;
1808  }
1809 
1810  if (data->nationlist != nullptr) {
1811  secfile_insert_str(sfile, data->nationlist, "ruledit.nationlist");
1812  }
1813  if (game.server.ruledit.embedded_nations != nullptr) {
1814  int i;
1815  const char **tmp =
1816  new const char *[game.server.ruledit.embedded_nations_count];
1817 
1818  /* Dance around the secfile_insert_str_vec() parameter type (requires
1819  * extra const) resrictions */
1820  for (i = 0; i < game.server.ruledit.embedded_nations_count; i++) {
1821  tmp[i] = game.server.ruledit.embedded_nations[i];
1822  }
1823 
1824  secfile_insert_str_vec(sfile, tmp,
1825  game.server.ruledit.embedded_nations_count,
1826  "ruledit.embedded_nations");
1827  delete[] tmp;
1828  }
1829 
1830  save_traits(game.server.default_traits, nullptr, sfile, "default_traits",
1831  "");
1832 
1833  if (data->nationlist == nullptr) {
1834  if (game.server.ruledit.allowed_govs != nullptr) {
1835  secfile_insert_str_vec(sfile, game.server.ruledit.allowed_govs,
1836  game.server.ruledit.ag_count,
1837  "compatibility.allowed_govs");
1838  }
1839  if (game.server.ruledit.allowed_terrains != nullptr) {
1840  secfile_insert_str_vec(sfile, game.server.ruledit.allowed_terrains,
1841  game.server.ruledit.at_count,
1842  "compatibility.allowed_terrains");
1843  }
1844  if (game.server.ruledit.allowed_styles != nullptr) {
1845  secfile_insert_str_vec(sfile, game.server.ruledit.allowed_styles,
1846  game.server.ruledit.as_count,
1847  "compatibility.allowed_styles");
1848  }
1849  }
1850 
1851  if (game.default_government != nullptr) {
1853  "compatibility.default_government");
1854  }
1855 
1856  if (data->nationlist != nullptr) {
1857  secfile_insert_include(sfile, data->nationlist);
1858 
1859  if (game.server.ruledit.embedded_nations != nullptr) {
1860  int sect_idx;
1861 
1862  comment_nations(sfile);
1863 
1864  for (sect_idx = 0;
1865  sect_idx < game.server.ruledit.embedded_nations_count;
1866  sect_idx++) {
1867  struct nation_type *pnat = nation_by_rule_name(
1868  game.server.ruledit.embedded_nations[sect_idx]);
1869 
1870  if (pnat == nullptr) {
1871  qCritical("Embedded nation \"%s\" not found!",
1872  game.server.ruledit.embedded_nations[sect_idx]);
1873  } else {
1874  save_nation(sfile, pnat, sect_idx);
1875  }
1876  }
1877  }
1878  } else {
1879  int sect_idx = 0;
1880 
1881  comment_nationsets(sfile);
1882 
1883  nation_sets_iterate(pset)
1884  {
1885  char path[512];
1886 
1887  fc_snprintf(path, sizeof(path), "nset_%d", sect_idx++);
1888 
1889  /* We don't use save_name_translation() for this as name and rule_name
1890  * must always be saved separately */
1892  "%s.name", path);
1893  secfile_insert_str(sfile, nation_set_rule_name(pset), "%s.rule_name",
1894  path);
1896  "%s.description", path);
1897  }
1899 
1900  comment_nationgroups(sfile);
1901 
1902  sect_idx = 0;
1903  nation_groups_iterate(pgroup)
1904  {
1905  char path[512];
1906 
1907  fc_snprintf(path, sizeof(path), "ngroup_%d", sect_idx++);
1908 
1909  save_name_translation(sfile, &(pgroup->name), path);
1910 
1911  secfile_insert_int(sfile, pgroup->server.match, "%s.match", path);
1912  if (pgroup->hidden) {
1913  secfile_insert_bool(sfile, pgroup->hidden, "%s.hidden", path);
1914  }
1915  }
1917 
1918  comment_nations(sfile);
1919 
1920  sect_idx = 0;
1921  for (auto &pnat : nations) {
1922  save_nation(sfile, &pnat, sect_idx++);
1923  }
1924  }
1925 
1926  return save_ruleset_file(sfile, filename);
1927 }
1928 
1932 static bool save_techs_ruleset(const char *filename, const char *name)
1933 {
1934  struct section_file *sfile = create_ruleset_file(name, "tech");
1935  int i;
1936  int sect_idx;
1937  struct advance *a_none = advance_by_number(A_NONE);
1938 
1939  if (sfile == nullptr) {
1940  return false;
1941  }
1942 
1943  for (i = 0; i < MAX_NUM_USER_TECH_FLAGS; i++) {
1944  const char *flagname =
1945  tech_flag_id_name_cb(tech_flag_id(i + TECH_USER_1));
1946  const char *helptxt = tech_flag_helptxt(tech_flag_id(i + TECH_USER_1));
1947 
1948  if (flagname != nullptr) {
1949  secfile_insert_str(sfile, flagname, "control.flags%d.name", i);
1950 
1951  /* Save the user flag help text even when it is undefined. That makes
1952  * the formatting code happy. The resulting "" is ignored when the
1953  * ruleset is loaded. */
1954  secfile_insert_str(sfile, helptxt, "control.flags%d.helptxt", i);
1955  }
1956  }
1957 
1958  comment_tech_classes(sfile);
1959 
1960  sect_idx = 0;
1961  tech_class_iterate(ptclass)
1962  {
1963  char path[512];
1964 
1965  fc_snprintf(path, sizeof(path), "techclass_%d", sect_idx++);
1966 
1967  save_name_translation(sfile, &(ptclass->name), path);
1968  }
1970 
1971  comment_techs(sfile);
1972 
1973  sect_idx = 0;
1975  {
1976  if (pa->require[AR_ONE] != A_NEVER) {
1977  char path[512];
1978  const char *flag_names[TF_COUNT];
1979  int set_count;
1980  int flagi;
1981 
1982  fc_snprintf(path, sizeof(path), "advance_%d", sect_idx++);
1983 
1984  save_name_translation(sfile, &(pa->name), path);
1985 
1986  if (game.control.num_tech_classes > 0) {
1987  if (pa->tclass != nullptr) {
1988  secfile_insert_str(sfile, tech_class_rule_name(pa->tclass),
1989  "%s.class", path);
1990  }
1991  }
1992 
1993  save_tech_ref(sfile, pa->require[AR_ONE], path, "req1");
1994  save_tech_ref(sfile, pa->require[AR_TWO], path, "req2");
1995  if (pa->require[AR_ROOT] != a_none && !pa->inherited_root_req) {
1996  save_tech_ref(sfile, pa->require[AR_ROOT], path, "root_req");
1997  }
1998 
1999  save_reqs_vector(sfile, &(pa->research_reqs), path, "research_reqs");
2000 
2001  secfile_insert_str(sfile, pa->graphic_str, "%s.graphic", path);
2002  if (strcmp("-", pa->graphic_alt)) {
2003  secfile_insert_str(sfile, pa->graphic_alt, "%s.graphic_alt", path);
2004  }
2005  if (pa->bonus_message != nullptr) {
2006  secfile_insert_str(sfile, pa->bonus_message, "%s.bonus_message",
2007  path);
2008  }
2009 
2010  set_count = 0;
2011  for (flagi = 0; flagi < TF_COUNT; flagi++) {
2012  if (advance_has_flag(advance_index(pa), tech_flag_id(flagi))) {
2013  flag_names[set_count++] = tech_flag_id_name(tech_flag_id(flagi));
2014  }
2015  }
2016 
2017  if (set_count > 0) {
2018  secfile_insert_str_vec(sfile, flag_names, set_count, "%s.flags",
2019  path);
2020  }
2021  if (pa->cost >= 0) {
2022  secfile_insert_int(sfile, pa->cost, "%s.cost", path);
2023  }
2024 
2025  save_strvec(sfile, pa->helptext, path, "helptext");
2026  }
2027  }
2029 
2030  return save_ruleset_file(sfile, filename);
2031 }
2032 
2036 static bool save_terrain_ruleset(const char *filename, const char *name)
2037 {
2038  struct section_file *sfile = create_ruleset_file(name, "terrain");
2039  int sect_idx;
2040  int i;
2041 
2042  if (sfile == nullptr) {
2043  return false;
2044  }
2045 
2046  for (i = 0; i < MAX_NUM_USER_TER_FLAGS; i++) {
2047  const char *flagname =
2048  terrain_flag_id_name_cb(terrain_flag_id(i + TER_USER_1));
2049  const char *helptxt =
2050  terrain_flag_helptxt(terrain_flag_id(i + TER_USER_1));
2051 
2052  if (flagname != nullptr) {
2053  secfile_insert_str(sfile, flagname, "control.flags%d.name", i);
2054 
2055  /* Save the user flag help text even when it is undefined. That makes
2056  * the formatting code happy. The resulting "" is ignored when the
2057  * ruleset is loaded. */
2058  secfile_insert_str(sfile, helptxt, "control.flags%d.helptxt", i);
2059  }
2060  }
2061 
2062  for (i = 0; i < MAX_NUM_USER_EXTRA_FLAGS; i++) {
2063  const char *flagname =
2064  extra_flag_id_name_cb(extra_flag_id(i + EF_USER_FLAG_1));
2065  const char *helptxt =
2066  extra_flag_helptxt(extra_flag_id(i + EF_USER_FLAG_1));
2067 
2068  if (flagname != nullptr) {
2069  secfile_insert_str(sfile, flagname, "control.extra_flags%d.name", i);
2070 
2071  /* Save the user flag help text even when it is undefined. That makes
2072  * the formatting code happy. The resulting "" is ignored when the
2073  * ruleset is loaded. */
2074  secfile_insert_str(sfile, helptxt, "control.extra_flags%d.helptxt", i);
2075  }
2076  }
2077 
2078  if (terrain_control.ocean_reclaim_requirement_pct <= 100) {
2079  secfile_insert_int(sfile, terrain_control.ocean_reclaim_requirement_pct,
2080  "parameters.ocean_reclaim_requirement");
2081  }
2082  if (terrain_control.land_channel_requirement_pct <= 100) {
2083  secfile_insert_int(sfile, terrain_control.land_channel_requirement_pct,
2084  "parameters.land_channel_requirement");
2085  }
2086  if (terrain_control.terrain_thaw_requirement_pct <= 100) {
2087  secfile_insert_int(sfile, terrain_control.terrain_thaw_requirement_pct,
2088  "parameters.thaw_requirement");
2089  }
2090  if (terrain_control.terrain_freeze_requirement_pct <= 100) {
2091  secfile_insert_int(sfile, terrain_control.terrain_freeze_requirement_pct,
2092  "parameters.freeze_requirement");
2093  }
2094  if (terrain_control.lake_max_size != 0) {
2095  secfile_insert_int(sfile, terrain_control.lake_max_size,
2096  "parameters.lake_max_size");
2097  }
2098  if (terrain_control.min_start_native_area != 0) {
2099  secfile_insert_int(sfile, terrain_control.min_start_native_area,
2100  "parameters.min_start_native_area");
2101  }
2102  if (terrain_control.move_fragments != 3) {
2103  secfile_insert_int(sfile, terrain_control.move_fragments,
2104  "parameters.move_fragments");
2105  }
2106  if (terrain_control.igter_cost != 1) {
2107  secfile_insert_int(sfile, terrain_control.igter_cost,
2108  "parameters.igter_cost");
2109  }
2110  if (terrain_control.pythagorean_diagonal
2112  secfile_insert_bool(sfile, terrain_control.pythagorean_diagonal,
2113  "parameters.pythagorean_diagonal");
2114  }
2115  if (wld.map.server.ocean_resources) {
2116  secfile_insert_bool(sfile, true, "parameters.ocean_resources");
2117  }
2118 
2119  comment_terrains(sfile);
2120 
2121  sect_idx = 0;
2122  terrain_type_iterate(pterr)
2123  {
2124  char path[512];
2125  char identifier[2];
2126  int r;
2127  const char *flag_names[TER_USER_LAST];
2128  const char *puc_names[UCL_LAST];
2129  int flagi;
2130  int set_count;
2131 
2132  fc_snprintf(path, sizeof(path), "terrain_%d", sect_idx++);
2133 
2134  save_name_translation(sfile, &(pterr->name), path);
2135 
2136  secfile_insert_str(sfile, pterr->graphic_str, "%s.graphic", path);
2137  secfile_insert_str(sfile, pterr->graphic_alt, "%s.graphic_alt", path);
2138  identifier[0] = pterr->identifier;
2139  identifier[1] = '\0';
2140  secfile_insert_str(sfile, identifier, "%s.identifier", path);
2141 
2142  secfile_insert_str(sfile, terrain_class_name(pterr->tclass), "%s.class",
2143  path);
2144 
2145  secfile_insert_int(sfile, pterr->movement_cost, "%s.movement_cost",
2146  path);
2147  secfile_insert_int(sfile, pterr->defense_bonus, "%s.defense_bonus",
2148  path);
2149 
2151  {
2152  if (pterr->output[o] != 0) {
2153  secfile_insert_int(sfile, pterr->output[o], "%s.%s", path,
2155  }
2156  }
2158 
2159  // Check resource count
2160  for (r = 0; pterr->resources[r] != nullptr; r++) {
2161  // Just increasing r as long as there is resources
2162  }
2163 
2164  {
2165  const char *resource_names[r];
2166 
2167  for (r = 0; pterr->resources[r] != nullptr; r++) {
2168  resource_names[r] = extra_rule_name(pterr->resources[r]);
2169  }
2170 
2171  secfile_insert_str_vec(sfile, resource_names, r, "%s.resources", path);
2172  }
2173 
2175  {
2176  if (pterr->road_output_incr_pct[o] != 0) {
2177  secfile_insert_int(sfile, pterr->road_output_incr_pct[o],
2178  "%s.road_%s_incr_pct", path,
2180  }
2181  }
2183 
2184  secfile_insert_int(sfile, pterr->base_time, "%s.base_time", path);
2185  secfile_insert_int(sfile, pterr->road_time, "%s.road_time", path);
2186 
2187  secfile_insert_int(sfile, pterr->cultivate_time, "%s.cultivate_time",
2188  path);
2189 
2190  secfile_insert_int(sfile, pterr->plant_time, "%s.plant_time", path);
2191 
2192  save_terrain_ref(sfile, pterr->irrigation_result, pterr, path,
2193  "irrigation_result");
2194  secfile_insert_int(sfile, pterr->irrigation_food_incr,
2195  "%s.irrigation_food_incr", path);
2196  secfile_insert_int(sfile, pterr->irrigation_time, "%s.irrigation_time",
2197  path);
2198 
2199  save_terrain_ref(sfile, pterr->mining_result, pterr, path,
2200  "mining_result");
2201  secfile_insert_int(sfile, pterr->mining_shield_incr,
2202  "%s.mining_shield_incr", path);
2203  secfile_insert_int(sfile, pterr->mining_time, "%s.mining_time", path);
2204 
2205  save_terrain_ref(sfile, pterr->transform_result, pterr, path,
2206  "transform_result");
2207  secfile_insert_int(sfile, pterr->transform_time, "%s.transform_time",
2208  path);
2209 
2210  if (pterr->animal != nullptr) {
2211  secfile_insert_str(sfile, utype_rule_name(pterr->animal), "%s.animal",
2212  path);
2213  } else {
2214  secfile_insert_str(sfile, "None", "%s.animal", path);
2215  }
2216 
2217  secfile_insert_int(sfile, pterr->placing_time, "%s.placing_time", path);
2218  secfile_insert_int(sfile, pterr->pillage_time, "%s.pillage_time", path);
2219  secfile_insert_int(sfile, pterr->clean_pollution_time,
2220  "%s.clean_pollution_time", path);
2221  secfile_insert_int(sfile, pterr->clean_fallout_time,
2222  "%s.clean_fallout_time", path);
2223 
2224  save_terrain_ref(sfile, pterr->warmer_wetter_result, pterr, path,
2225  "warmer_wetter_result");
2226  save_terrain_ref(sfile, pterr->warmer_drier_result, pterr, path,
2227  "warmer_drier_result");
2228  save_terrain_ref(sfile, pterr->cooler_wetter_result, pterr, path,
2229  "cooler_wetter_result");
2230  save_terrain_ref(sfile, pterr->cooler_drier_result, pterr, path,
2231  "cooler_drier_result");
2232 
2233  set_count = 0;
2234  for (flagi = 0; flagi < TER_USER_LAST; flagi++) {
2235  if (terrain_has_flag(pterr, flagi)) {
2236  flag_names[set_count++] =
2237  terrain_flag_id_name(terrain_flag_id(flagi));
2238  }
2239  }
2240 
2241  if (set_count > 0) {
2242  secfile_insert_str_vec(sfile, flag_names, set_count, "%s.flags", path);
2243  }
2244 
2245  {
2246  enum mapgen_terrain_property mtp;
2247 
2248  for (mtp = mapgen_terrain_property_begin();
2249  mtp != mapgen_terrain_property_end();
2250  mtp = mapgen_terrain_property_next(mtp)) {
2251  if (pterr->property[mtp] != 0) {
2252  secfile_insert_int(sfile, pterr->property[mtp], "%s.property_%s",
2253  path, mapgen_terrain_property_name(mtp));
2254  }
2255  }
2256  }
2257 
2258  set_count = 0;
2259  unit_class_iterate(puc)
2260  {
2261  if (BV_ISSET(pterr->native_to, uclass_index(puc))) {
2262  puc_names[set_count++] = uclass_rule_name(puc);
2263  }
2264  }
2266 
2267  if (set_count > 0) {
2268  secfile_insert_str_vec(sfile, puc_names, set_count, "%s.native_to",
2269  path);
2270  }
2271 
2272  rgbcolor_save(sfile, pterr->rgb, "%s.color", path);
2273 
2274  save_strvec(sfile, pterr->helptext, path, "helptext");
2275  }
2277 
2278  comment_resources(sfile);
2279 
2280  sect_idx = 0;
2281  extra_type_by_cause_iterate(EC_RESOURCE, pres)
2282  {
2283  if (!pres->ruledit_disabled) {
2284  char path[512];
2285  char identifier[2];
2286 
2287  fc_snprintf(path, sizeof(path), "resource_%d", sect_idx++);
2288 
2289  secfile_insert_str(sfile, extra_rule_name(pres), "%s.extra", path);
2290 
2292  {
2293  if (pres->data.resource->output[o] != 0) {
2294  secfile_insert_int(sfile, pres->data.resource->output[o], "%s.%s",
2295  path, get_output_identifier(o));
2296  }
2297  }
2299 
2300  identifier[0] = pres->data.resource->id_old_save;
2301  identifier[1] = '\0';
2302  secfile_insert_str(sfile, identifier, "%s.identifier", path);
2303  }
2304  }
2306 
2307  secfile_insert_str(sfile, terrain_control.gui_type_base0,
2308  "extraui.ui_name_base_fortress");
2309  secfile_insert_str(sfile, terrain_control.gui_type_base1,
2310  "extraui.ui_name_base_airbase");
2311 
2312  comment_extras(sfile);
2313 
2314  sect_idx = 0;
2316  {
2317  char path[512];
2318  const char *flag_names[EF_COUNT];
2319  const char *cause_names[EC_COUNT];
2320  const char *puc_names[UCL_LAST];
2321  const char *extra_names[MAX_EXTRA_TYPES];
2322  int flagi;
2323  int causei;
2324  int set_count;
2325 
2326  fc_snprintf(path, sizeof(path), "extra_%d", sect_idx++);
2327 
2328  save_name_translation(sfile, &(pextra->name), path);
2329 
2330  secfile_insert_str(sfile, extra_category_name(pextra->category),
2331  "%s.category", path);
2332 
2333  set_count = 0;
2334  for (causei = 0; causei < EC_COUNT; causei++) {
2335  if (is_extra_caused_by(pextra, causei)) {
2336  cause_names[set_count++] = extra_cause_name(extra_cause(causei));
2337  }
2338  }
2339 
2340  if (set_count > 0) {
2341  secfile_insert_str_vec(sfile, cause_names, set_count, "%s.causes",
2342  path);
2343  }
2344 
2345  set_count = 0;
2346  for (causei = 0; causei < ERM_COUNT; causei++) {
2347  if (is_extra_removed_by(pextra, extra_rmcause(causei))) {
2348  cause_names[set_count++] = extra_rmcause_name(extra_rmcause(causei));
2349  }
2350  }
2351 
2352  if (set_count > 0) {
2353  secfile_insert_str_vec(sfile, cause_names, set_count, "%s.rmcauses",
2354  path);
2355  }
2356 
2357  if (strcmp(pextra->graphic_str, "-")) {
2358  secfile_insert_str(sfile, pextra->graphic_str, "%s.graphic", path);
2359  }
2360  if (strcmp(pextra->graphic_alt, "-")) {
2361  secfile_insert_str(sfile, pextra->graphic_alt, "%s.graphic_alt", path);
2362  }
2363  if (strcmp(pextra->activity_gfx, "-")) {
2364  secfile_insert_str(sfile, pextra->activity_gfx, "%s.activity_gfx",
2365  path);
2366  }
2367  if (strcmp(pextra->act_gfx_alt, "-")) {
2368  secfile_insert_str(sfile, pextra->act_gfx_alt, "%s.act_gfx_alt", path);
2369  }
2370  if (strcmp(pextra->act_gfx_alt2, "-")) {
2371  secfile_insert_str(sfile, pextra->act_gfx_alt2, "%s.act_gfx_alt2",
2372  path);
2373  }
2374  if (strcmp(pextra->rmact_gfx, "-")) {
2375  secfile_insert_str(sfile, pextra->rmact_gfx, "%s.rmact_gfx", path);
2376  }
2377  if (strcmp(pextra->rmact_gfx_alt, "-")) {
2378  secfile_insert_str(sfile, pextra->rmact_gfx_alt, "%s.rmact_gfx_alt",
2379  path);
2380  }
2381 
2382  save_reqs_vector(sfile, &(pextra->reqs), path, "reqs");
2383  save_reqs_vector(sfile, &(pextra->rmreqs), path, "rmreqs");
2384  save_reqs_vector(sfile, &(pextra->appearance_reqs), path,
2385  "appearance_reqs");
2386  save_reqs_vector(sfile, &(pextra->disappearance_reqs), path,
2387  "disappearance_reqs");
2388 
2389  if (!pextra->buildable) {
2390  secfile_insert_bool(sfile, pextra->buildable, "%s.buildable", path);
2391  }
2392  if (!pextra->generated) {
2393  secfile_insert_bool(sfile, pextra->generated, "%s.generated", path);
2394  }
2395  secfile_insert_int(sfile, pextra->build_time, "%s.build_time", path);
2396  secfile_insert_int(sfile, pextra->removal_time, "%s.removal_time", path);
2397  if (pextra->build_time_factor != 1) {
2398  secfile_insert_int(sfile, pextra->build_time_factor,
2399  "%s.build_time_factor", path);
2400  }
2401  if (pextra->removal_time_factor != 1) {
2402  secfile_insert_int(sfile, pextra->removal_time_factor,
2403  "%s.removal_time_factor", path);
2404  }
2405  if (pextra->defense_bonus != 0) {
2406  secfile_insert_int(sfile, pextra->defense_bonus, "%s.defense_bonus",
2407  path);
2408  }
2409  if (pextra->eus != EUS_NORMAL) {
2410  secfile_insert_str(sfile, extra_unit_seen_type_name(pextra->eus),
2411  "%s.unit_seen", path);
2412  }
2413  if (is_extra_caused_by(pextra, EC_APPEARANCE)
2414  && pextra->appearance_chance != RS_DEFAULT_EXTRA_APPEARANCE) {
2415  secfile_insert_int(sfile, pextra->appearance_chance,
2416  "%s.appearance_chance", path);
2417  }
2418  if (is_extra_removed_by(pextra, ERM_DISAPPEARANCE)
2419  && pextra->disappearance_chance != RS_DEFAULT_EXTRA_DISAPPEARANCE) {
2420  secfile_insert_int(sfile, pextra->disappearance_chance,
2421  "%s.disappearance_chance", path);
2422  }
2423 
2424  set_count = 0;
2425  unit_class_iterate(puc)
2426  {
2427  if (BV_ISSET(pextra->native_to, uclass_index(puc))) {
2428  puc_names[set_count++] = uclass_rule_name(puc);
2429  }
2430  }
2432 
2433  if (set_count > 0) {
2434  secfile_insert_str_vec(sfile, puc_names, set_count, "%s.native_to",
2435  path);
2436  }
2437 
2438  set_count = 0;
2439  for (flagi = 0; flagi < EF_COUNT; flagi++) {
2440  if (extra_has_flag(pextra, extra_flag_id(flagi))) {
2441  flag_names[set_count++] = extra_flag_id_name(extra_flag_id(flagi));
2442  }
2443  }
2444 
2445  if (set_count > 0) {
2446  secfile_insert_str_vec(sfile, flag_names, set_count, "%s.flags", path);
2447  }
2448 
2449  set_count = 0;
2450  extra_type_iterate(confl)
2451  {
2452  if (!can_extras_coexist(pextra, confl)) {
2453  extra_names[set_count++] = extra_rule_name(confl);
2454  }
2455  }
2457 
2458  if (set_count > 0) {
2459  secfile_insert_str_vec(sfile, extra_names, set_count, "%s.conflicts",
2460  path);
2461  }
2462 
2463  set_count = 0;
2464  extra_type_iterate(top)
2465  {
2466  if (BV_ISSET(pextra->hidden_by, extra_index(top))) {
2467  extra_names[set_count++] = extra_rule_name(top);
2468  }
2469  }
2471 
2472  if (set_count > 0) {
2473  secfile_insert_str_vec(sfile, extra_names, set_count, "%s.hidden_by",
2474  path);
2475  }
2476 
2477  set_count = 0;
2478  extra_type_iterate(top)
2479  {
2480  if (BV_ISSET(pextra->bridged_over, extra_index(top))) {
2481  extra_names[set_count++] = extra_rule_name(top);
2482  }
2483  }
2485 
2486  if (set_count > 0) {
2487  secfile_insert_str_vec(sfile, extra_names, set_count,
2488  "%s.bridged_over", path);
2489  }
2490 
2491  save_strvec(sfile, pextra->helptext, path, "helptext");
2492  }
2494 
2495  comment_bases(sfile);
2496 
2497  sect_idx = 0;
2498  extra_type_by_cause_iterate(EC_BASE, pextra)
2499  {
2500  if (!pextra->ruledit_disabled) {
2501  char path[512];
2502  struct base_type *pbase = extra_base_get(pextra);
2503  const char *flag_names[BF_COUNT];
2504  int flagi;
2505  int set_count;
2506 
2507  fc_snprintf(path, sizeof(path), "base_%d", sect_idx++);
2508 
2509  secfile_insert_str(sfile, extra_rule_name(pextra), "%s.extra", path);
2510 
2511  secfile_insert_str(sfile, base_gui_type_name(pbase->gui_type),
2512  "%s.gui_type", path);
2513 
2514  if (pbase->border_sq >= 0) {
2515  secfile_insert_int(sfile, pbase->border_sq, "%s.border_sq", path);
2516  }
2517  if (pbase->vision_main_sq >= 0) {
2518  secfile_insert_int(sfile, pbase->vision_main_sq, "%s.vision_main_sq",
2519  path);
2520  }
2521  if (pbase->vision_invis_sq >= 0) {
2522  secfile_insert_int(sfile, pbase->vision_invis_sq,
2523  "%s.vision_invis_sq", path);
2524  }
2525  if (pbase->vision_subs_sq >= 0) {
2526  secfile_insert_int(sfile, pbase->vision_subs_sq, "%s.vision_subs_sq",
2527  path);
2528  }
2529 
2530  set_count = 0;
2531  for (flagi = 0; flagi < BF_COUNT; flagi++) {
2532  if (base_has_flag(pbase, base_flag_id(flagi))) {
2533  flag_names[set_count++] = base_flag_id_name(base_flag_id(flagi));
2534  }
2535  }
2536 
2537  if (set_count > 0) {
2538  secfile_insert_str_vec(sfile, flag_names, set_count, "%s.flags",
2539  path);
2540  }
2541  }
2542  }
2544 
2545  comment_roads(sfile);
2546 
2547  sect_idx = 0;
2548  extra_type_by_cause_iterate(EC_ROAD, pextra)
2549  {
2550  if (!pextra->ruledit_disabled) {
2551  struct road_type *proad = extra_road_get(pextra);
2552  char path[512];
2553  const char *flag_names[RF_COUNT];
2554  int flagi;
2555  int set_count;
2556 
2557  fc_snprintf(path, sizeof(path), "road_%d", sect_idx++);
2558 
2559  secfile_insert_str(sfile, extra_rule_name(pextra), "%s.extra", path);
2560 
2561  secfile_insert_int(sfile, proad->move_cost, "%s.move_cost", path);
2562 
2563  if (proad->move_mode != RMM_FAST_ALWAYS) {
2564  secfile_insert_str(sfile, road_move_mode_name(proad->move_mode),
2565  "%s.move_mode", path);
2566  }
2567 
2569  {
2570  if (proad->tile_incr_const[o] != 0) {
2571  secfile_insert_int(sfile, proad->tile_incr_const[o],
2572  "%s.%s_incr_const", path,
2574  }
2575  if (proad->tile_incr[o] != 0) {
2576  secfile_insert_int(sfile, proad->tile_incr[o], "%s.%s_incr", path,
2578  }
2579  if (proad->tile_bonus[o] != 0) {
2580  secfile_insert_int(sfile, proad->tile_bonus[o], "%s.%s_bonus",
2581  path, get_output_identifier(o));
2582  }
2583  }
2585 
2586  switch (proad->compat) {
2587  case ROCO_ROAD:
2588  secfile_insert_str(sfile, "Road", "%s.compat_special", path);
2589  break;
2590  case ROCO_RAILROAD:
2591  secfile_insert_str(sfile, "Railroad", "%s.compat_special", path);
2592  break;
2593  case ROCO_RIVER:
2594  secfile_insert_str(sfile, "River", "%s.compat_special", path);
2595  break;
2596  case ROCO_NONE:
2597  secfile_insert_str(sfile, "None", "%s.compat_special", path);
2598  break;
2599  }
2600 
2601  set_count = 0;
2602  for (flagi = 0; flagi < RF_COUNT; flagi++) {
2603  if (road_has_flag(proad, road_flag_id(flagi))) {
2604  flag_names[set_count++] = road_flag_id_name(road_flag_id(flagi));
2605  }
2606  }
2607 
2608  if (set_count > 0) {
2609  secfile_insert_str_vec(sfile, flag_names, set_count, "%s.flags",
2610  path);
2611  }
2612  }
2613  }
2615 
2616  return save_ruleset_file(sfile, filename);
2617 }
2618 
2622 static bool save_veteran_system(struct section_file *sfile, const char *path,
2623  struct veteran_system *vsystem)
2624 {
2625  const char *vlist_name[vsystem->levels];
2626  int vlist_power[vsystem->levels];
2627  int vlist_raise[vsystem->levels];
2628  int vlist_wraise[vsystem->levels];
2629  int vlist_move[vsystem->levels];
2630  int i;
2631 
2632  for (i = 0; i < vsystem->levels; i++) {
2633  vlist_name[i] = rule_name_get(&(vsystem->definitions[i].name));
2634  vlist_power[i] = vsystem->definitions[i].power_fact;
2635  vlist_raise[i] = vsystem->definitions[i].base_raise_chance;
2636  vlist_wraise[i] = vsystem->definitions[i].work_raise_chance;
2637  vlist_move[i] = vsystem->definitions[i].move_bonus;
2638  }
2639 
2640  secfile_insert_str_vec(sfile, vlist_name, vsystem->levels,
2641  "%s.veteran_names", path);
2642  secfile_insert_int_vec(sfile, vlist_power, vsystem->levels,
2643  "%s.veteran_power_fact", path);
2644  secfile_insert_int_vec(sfile, vlist_raise, vsystem->levels,
2645  "%s.veteran_base_raise_chance", path);
2646  secfile_insert_int_vec(sfile, vlist_wraise, vsystem->levels,
2647  "%s.veteran_work_raise_chance", path);
2648  secfile_insert_int_vec(sfile, vlist_move, vsystem->levels,
2649  "%s.veteran_move_bonus", path);
2650 
2651  return true;
2652 }
2653 
2657 static bool save_combat_bonuses(struct section_file *sfile,
2658  struct unit_type *put, char *path)
2659 {
2660  int i;
2661  bool has_quiet = false;
2662 
2663  combat_bonus_list_iterate(put->bonuses, pbonus)
2664  {
2665  if (pbonus->quiet) {
2666  has_quiet = true;
2667  }
2668  }
2670 
2671  i = 0;
2672 
2673  combat_bonus_list_iterate(put->bonuses, pbonus)
2674  {
2675  secfile_insert_str(sfile, unit_type_flag_id_name(pbonus->flag),
2676  "%s.bonuses%d.flag", path, i);
2677  secfile_insert_str(sfile, combat_bonus_type_name(pbonus->type),
2678  "%s.bonuses%d.type", path, i);
2679  secfile_insert_int(sfile, pbonus->value, "%s.bonuses%d.value", path, i);
2680 
2681  if (has_quiet) {
2682  secfile_insert_bool(sfile, pbonus->quiet, "%s.bonuses%d.quiet", path,
2683  i);
2684  }
2685 
2686  i++;
2687  }
2689 
2690  return true;
2691 }
2692 
2696 static bool save_units_ruleset(const char *filename, const char *name)
2697 {
2698  struct section_file *sfile = create_ruleset_file(name, "unit");
2699  int i;
2700  int sect_idx;
2701 
2702  if (sfile == nullptr) {
2703  return false;
2704  }
2705 
2706  for (i = 0; i < MAX_NUM_USER_UNIT_FLAGS; i++) {
2707  const char *flagname =
2708  unit_type_flag_id_name_cb(unit_type_flag_id(i + UTYF_USER_FLAG_1));
2709  const char *helptxt =
2710  unit_type_flag_helptxt(unit_type_flag_id(i + UTYF_USER_FLAG_1));
2711 
2712  if (flagname != nullptr) {
2713  secfile_insert_str(sfile, flagname, "control.flags%d.name", i);
2714 
2715  /* Save the user flag help text even when it is undefined. That makes
2716  * the formatting code happy. The resulting "" is ignored when the
2717  * ruleset is loaded. */
2718  secfile_insert_str(sfile, helptxt, "control.flags%d.helptxt", i);
2719  }
2720  }
2721 
2722  for (i = 0; i < MAX_NUM_USER_UCLASS_FLAGS; i++) {
2723  const char *flagname =
2724  unit_class_flag_id_name_cb(unit_class_flag_id(i + UCF_USER_FLAG_1));
2725  const char *helptxt =
2726  unit_class_flag_helptxt(unit_class_flag_id(i + UCF_USER_FLAG_1));
2727 
2728  if (flagname != nullptr) {
2729  secfile_insert_str(sfile, flagname, "control.class_flags%d.name", i);
2730 
2731  /* Save the user flag help text even when it is undefined. That makes
2732  * the formatting code happy. The resulting "" is ignored when the
2733  * ruleset is loaded. */
2734  secfile_insert_str(sfile, helptxt, "control.class_flags%d.helptxt", i);
2735  }
2736  }
2737 
2738  save_veteran_system(sfile, "veteran_system", game.veteran);
2739 
2740  comment_uclasses(sfile);
2741 
2742  sect_idx = 0;
2744  {
2745  char path[512];
2746  const char *hut_str = nullptr;
2747  const char *flag_names[UCF_COUNT];
2748  int flagi;
2749  int set_count;
2750 
2751  fc_snprintf(path, sizeof(path), "unitclass_%d", sect_idx++);
2752 
2753  save_name_translation(sfile, &(puc->name), path);
2754 
2755  secfile_insert_int(sfile, puc->min_speed / SINGLE_MOVE, "%s.min_speed",
2756  path);
2757  secfile_insert_int(sfile, puc->hp_loss_pct, "%s.hp_loss_pct", path);
2758  if (puc->non_native_def_pct != 100) {
2759  secfile_insert_int(sfile, puc->non_native_def_pct,
2760  "%s.non_native_def_pct", path);
2761  }
2762  if (puc->hut_behavior != HUT_NORMAL) {
2763  switch (puc->hut_behavior) {
2764  case HUT_NORMAL:
2765  hut_str = "Normal";
2766  break;
2767  case HUT_NOTHING:
2768  hut_str = "Nothing";
2769  break;
2770  case HUT_FRIGHTEN:
2771  hut_str = "Frighten";
2772  break;
2773  }
2774  fc_assert(hut_str != nullptr);
2775  secfile_insert_str(sfile, hut_str, "%s.hut_behavior", path);
2776  }
2777 
2778  set_count = 0;
2779  for (flagi = 0; flagi < UCF_COUNT; flagi++) {
2780  if (uclass_has_flag(puc, unit_class_flag_id(flagi))) {
2781  flag_names[set_count++] =
2782  unit_class_flag_id_name(unit_class_flag_id(flagi));
2783  }
2784  }
2785 
2786  if (set_count > 0) {
2787  secfile_insert_str_vec(sfile, flag_names, set_count, "%s.flags", path);
2788  }
2789 
2790  save_strvec(sfile, puc->helptext, path, "helptext");
2791  }
2793 
2794  comment_utypes(sfile);
2795 
2796  sect_idx = 0;
2798  {
2799  if (!put->ruledit_disabled) {
2800  char path[512];
2801  const char *flag_names[UTYF_LAST_USER_FLAG + 1];
2802  int flagi;
2803  int set_count;
2804 
2805  fc_snprintf(path, sizeof(path), "unit_%d", sect_idx++);
2806 
2807  save_name_translation(sfile, &(put->name), path);
2808 
2809  secfile_insert_str(sfile, uclass_rule_name(put->uclass), "%s.class",
2810  path);
2811 
2812  save_tech_ref(sfile, put->require_advance, path, "tech_req");
2813 
2814  /* Extract the government requirement from the requirement vector so
2815  * it can be written in the old format.
2816  * The build_reqs requirement vector isn't ready to be exposed in the
2817  * ruleset yet. */
2818  requirement_vector_iterate(&put->build_reqs, preq)
2819  {
2820  if (preq->source.kind == VUT_GOVERNMENT) {
2821  fc_assert_msg(preq->range == REQ_RANGE_PLAYER,
2822  "can't convert non player range to the rs format");
2823  fc_assert_msg(preq->present == true,
2824  "can't convert not present reqs to the rs format");
2825  secfile_insert_str(sfile, universal_rule_name(&preq->source),
2826  "%s.gov_req", path);
2827  break;
2828  }
2829  }
2831 
2832  /* Extract the improvement requirement from the requirement vector so
2833  * it can be written in the old format.
2834  * The build_reqs requirement vector isn't ready to be exposed in the
2835  * ruleset yet. */
2836  requirement_vector_iterate(&put->build_reqs, preq)
2837  {
2838  if (preq->source.kind == VUT_IMPROVEMENT) {
2839  fc_assert_msg(preq->range == REQ_RANGE_CITY,
2840  "can't convert non player range to the rs format");
2841  fc_assert_msg(preq->present == true,
2842  "can't convert not present reqs to the rs format");
2843  secfile_insert_str(sfile, universal_rule_name(&preq->source),
2844  "%s.impr_req", path);
2845  break;
2846  }
2847  }
2849 
2850  if (put->obsoleted_by != nullptr) {
2851  secfile_insert_str(sfile, utype_rule_name(put->obsoleted_by),
2852  "%s.obsolete_by", path);
2853  }
2854 
2855  secfile_insert_str(sfile, put->graphic_str, "%s.graphic", path);
2856  if (strcmp("-", put->graphic_alt)) {
2857  secfile_insert_str(sfile, put->graphic_alt, "%s.graphic_alt", path);
2858  }
2859  if (strcmp("-", put->sound_move)) {
2860  secfile_insert_str(sfile, put->sound_move, "%s.sound_move", path);
2861  }
2862  if (strcmp("-", put->sound_move_alt)) {
2863  secfile_insert_str(sfile, put->sound_move_alt, "%s.sound_move_alt",
2864  path);
2865  }
2866  if (strcmp("-", put->sound_fight)) {
2867  secfile_insert_str(sfile, put->sound_fight, "%s.sound_fight", path);
2868  }
2869  if (strcmp("-", put->sound_fight_alt)) {
2870  secfile_insert_str(sfile, put->sound_fight_alt, "%s.sound_fight_alt",
2871  path);
2872  }
2873 
2874  secfile_insert_int(sfile, put->build_cost, "%s.build_cost", path);
2875  secfile_insert_int(sfile, put->pop_cost, "%s.pop_cost", path);
2876  secfile_insert_int(sfile, put->attack_strength, "%s.attack", path);
2877  secfile_insert_int(sfile, put->defense_strength, "%s.defense", path);
2878  secfile_insert_int(sfile, put->move_rate / SINGLE_MOVE, "%s.move_rate",
2879  path);
2880  secfile_insert_int(sfile, put->vision_radius_sq, "%s.vision_radius_sq",
2881  path);
2882  secfile_insert_int(sfile, put->transport_capacity, "%s.transport_cap",
2883  path);
2884 
2885  save_uclass_vec(sfile, &(put->cargo), path, "cargo", false);
2886  save_uclass_vec(sfile, &(put->embarks), path, "embarks", true);
2887  save_uclass_vec(sfile, &(put->disembarks), path, "disembarks", true);
2888 
2889  if (put->vlayer != V_MAIN) {
2890  secfile_insert_str(sfile, vision_layer_name(put->vlayer),
2891  "%s.vision_layer", path);
2892  }
2893 
2894  secfile_insert_int(sfile, put->hp, "%s.hitpoints", path);
2895  secfile_insert_int(sfile, put->firepower, "%s.firepower", path);
2896  secfile_insert_int(sfile, put->fuel, "%s.fuel", path);
2897  secfile_insert_int(sfile, put->happy_cost, "%s.uk_happy", path);
2898 
2900  {
2901  if (put->upkeep[o] != 0) {
2902  secfile_insert_int(sfile, put->upkeep[o], "%s.uk_%s", path,
2904  }
2905  }
2907 
2908  if (put->converted_to != nullptr) {
2909  secfile_insert_str(sfile, utype_rule_name(put->converted_to),
2910  "%s.convert_to", path);
2911  }
2912  if (put->convert_time != 1) {
2913  secfile_insert_int(sfile, put->convert_time, "%s.convert_time",
2914  path);
2915  }
2916 
2917  save_combat_bonuses(sfile, put, path);
2918  save_uclass_vec(sfile, &(put->targets), path, "targets", true);
2919 
2920  if (put->veteran != nullptr) {
2921  save_veteran_system(sfile, path, put->veteran);
2922  }
2923 
2924  if (put->paratroopers_range != 0) {
2925  secfile_insert_int(sfile, put->paratroopers_range,
2926  "%s.paratroopers_range", path);
2927  }
2928  if (put->bombard_rate != 0) {
2929  secfile_insert_int(sfile, put->bombard_rate, "%s.bombard_rate",
2930  path);
2931  }
2932  if (put->city_slots != 0) {
2933  secfile_insert_int(sfile, put->city_slots, "%s.city_slots", path);
2934  }
2935  if (put->city_size != 1) {
2936  secfile_insert_int(sfile, put->city_size, "%s.city_size", path);
2937  }
2938 
2939  set_count = 0;
2940  for (flagi = 0; flagi <= UTYF_LAST_USER_FLAG; flagi++) {
2941  if (utype_has_flag(put, flagi)) {
2942  flag_names[set_count++] =
2943  unit_type_flag_id_name(unit_type_flag_id(flagi));
2944  }
2945  }
2946 
2947  if (set_count > 0) {
2948  secfile_insert_str_vec(sfile, flag_names, set_count, "%s.flags",
2949  path);
2950  }
2951 
2952  set_count = 0;
2953  for (flagi = L_FIRST; flagi < L_LAST; flagi++) {
2954  if (utype_has_role(put, flagi)) {
2955  flag_names[set_count++] = unit_role_id_name(unit_role_id(flagi));
2956  }
2957  }
2958 
2959  if (set_count > 0) {
2960  secfile_insert_str_vec(sfile, flag_names, set_count, "%s.roles",
2961  path);
2962  }
2963 
2964  save_strvec(sfile, put->helptext, path, "helptext");
2965  }
2966  }
2968 
2969  return save_ruleset_file(sfile, filename);
2970 }
2971 
2975 static bool save_script_lua(const char *filename, const char *name,
2976  const char *buffer)
2977 {
2978  if (buffer != nullptr) {
2979  FILE *ffile = fc_fopen(filename, "w");
2980  int full_len = qstrlen(buffer);
2981  int len;
2982 
2983  if (ffile != nullptr) {
2984  len = fwrite(buffer, 1, full_len, ffile);
2985 
2986  fclose(ffile);
2987  if (len != full_len) {
2988  return false;
2989  }
2990  } else {
2991  return false;
2992  }
2993  }
2994 
2995  return true;
2996 }
2997 
3001 static bool save_luadata(const char *filename)
3002 {
3003  if (game.server.luadata != nullptr) {
3004  return secfile_save(game.server.luadata, filename);
3005  }
3006 
3007  return true;
3008 }
3009 
3013 bool save_ruleset(const char *path, const char *name, struct rule_data *data)
3014 {
3015  if (make_dir(path)) {
3016  bool success = true;
3017  char filename[500];
3018 
3019  if (success) {
3020  fc_snprintf(filename, sizeof(filename), "%s/buildings.ruleset", path);
3021  success = save_buildings_ruleset(filename, name);
3022  }
3023 
3024  if (success) {
3025  fc_snprintf(filename, sizeof(filename), "%s/styles.ruleset", path);
3026  success = save_styles_ruleset(filename, name);
3027  }
3028 
3029  if (success) {
3030  fc_snprintf(filename, sizeof(filename), "%s/cities.ruleset", path);
3031  success = save_cities_ruleset(filename, name);
3032  }
3033 
3034  if (success) {
3035  fc_snprintf(filename, sizeof(filename), "%s/effects.ruleset", path);
3036  success = save_effects_ruleset(filename, name);
3037  }
3038 
3039  if (success) {
3040  fc_snprintf(filename, sizeof(filename), "%s/game.ruleset", path);
3041  success = save_game_ruleset(filename, name);
3042  }
3043 
3044  if (success) {
3045  fc_snprintf(filename, sizeof(filename), "%s/governments.ruleset",
3046  path);
3047  success = save_governments_ruleset(filename, name);
3048  }
3049 
3050  if (success) {
3051  fc_snprintf(filename, sizeof(filename), "%s/nations.ruleset", path);
3052  success = save_nations_ruleset(filename, name, data);
3053  }
3054 
3055  if (success) {
3056  fc_snprintf(filename, sizeof(filename), "%s/techs.ruleset", path);
3057  success = save_techs_ruleset(filename, name);
3058  }
3059 
3060  if (success) {
3061  fc_snprintf(filename, sizeof(filename), "%s/terrain.ruleset", path);
3062  success = save_terrain_ruleset(filename, name);
3063  }
3064 
3065  if (success) {
3066  fc_snprintf(filename, sizeof(filename), "%s/units.ruleset", path);
3067  success = save_units_ruleset(filename, name);
3068  }
3069 
3070  if (success) {
3071  fc_snprintf(filename, sizeof(filename), "%s/script.lua", path);
3072  success = save_script_lua(filename, name, get_script_buffer());
3073  }
3074 
3075  if (success) {
3076  fc_snprintf(filename, sizeof(filename), "%s/parser.lua", path);
3077  success = save_script_lua(filename, name, get_parser_buffer());
3078  }
3079 
3080  if (success) {
3081  fc_snprintf(filename, sizeof(filename), "%s/luadata.txt", path);
3082  success = save_luadata(filename);
3083  }
3084 
3085  return success;
3086  } else {
3087  qCritical("Failed to create directory %s", path);
3088  return false;
3089  }
3090 
3091  return true;
3092 }
#define achievements_iterate_end
Definition: achievements.h:64
#define achievements_iterate(_ach_)
Definition: achievements.h:58
const char * action_max_range_ruleset_var_name(int act)
Return max range ruleset variable name for the action or nullptr if max range can't be set in the rul...
Definition: actions.cpp:6528
const char * action_ui_name_ruleset_var_name(int act)
Return ui_name ruleset variable name for the action.
Definition: actions.cpp:5919
const char * action_ui_name_default(int act)
Return default ui_name for the action.
Definition: actions.cpp:6087
int action_max_range_default(int act)
Return default max range for the action if it is ruleset settable.
Definition: actions.cpp:6633
const char * action_actor_consuming_always_ruleset_var_name(action_id act)
Return actor consuming always ruleset variable name for the action or nullptr if actor consuming alwa...
Definition: actions.cpp:6836
const char * action_min_range_ruleset_var_name(int act)
Return min range ruleset variable name for the action or nullptr if min range can't be set in the rul...
Definition: actions.cpp:6334
const struct action_auto_perf * action_auto_perf_by_number(const int num)
Returns action auto performer rule number num.
Definition: actions.cpp:5848
const char * action_target_kind_ruleset_var_name(int act)
Return target kind ruleset variable name for the action or nullptr if min range can't be set in the r...
Definition: actions.cpp:6736
struct action * action_by_number(action_id act_id)
Return the action with the given id.
Definition: actions.cpp:1149
int action_min_range_default(int act)
Return default min range for the action if it is ruleset settable.
Definition: actions.cpp:6430
const char * action_id_rule_name(action_id act_id)
Get the rule name of the action.
Definition: actions.cpp:1362
struct action_enabler_list * action_enablers_for_action(action_id action)
Get all enablers for an action in the current ruleset.
Definition: actions.cpp:1884
#define action_enablers_iterate_end
Definition: actions.h:425
#define ACTION_AUTO_MOVED_ADJ
Definition: actions.h:504
#define ACTION_AUTO_UPKEEP_GOLD
Definition: actions.h:502
#define NUM_ACTIONS
Definition: actions.h:224
#define ACTION_DISTANCE_UNLIMITED
Definition: actions.h:279
#define ACTION_AUTO_UPKEEP_SHIELD
Definition: actions.h:503
#define action_iterate_end
Definition: actions.h:383
#define MAX_NUM_ACTIONS
Definition: actions.h:223
#define action_id_would_be_blocked_by(blocked_id, blocker_id)
Definition: actions.h:575
#define action_enablers_iterate(_enabler_)
Definition: actions.h:417
#define action_iterate(_act_)
Definition: actions.h:378
#define ACTION_AUTO_UPKEEP_FOOD
Definition: actions.h:501
#define ACTION_NONE
Definition: actions.h:220
bool base_has_flag(const struct base_type *pbase, enum base_flag_id flag)
Check if base provides effect.
Definition: base.cpp:24
bool BV_ISSET(const BV &bv, int bit)
Definition: bitvector.h:37
struct citystyle * city_styles
Definition: city.cpp:78
const char * get_output_identifier(Output_type_id output)
Return an id string for the output type.
Definition: city.cpp:592
#define output_type_iterate(output)
Definition: city.h:764
#define output_type_iterate_end
Definition: city.h:771
void comment_roads(struct section_file *sfile)
Write roads header.
Definition: comments.cpp:244
void comment_uclasses(struct section_file *sfile)
Write unit classes header.
Definition: comments.cpp:196
void comment_citystyles(struct section_file *sfile)
Write city styles header.
Definition: comments.cpp:260
void comment_govs(struct section_file *sfile)
Write governments header.
Definition: comments.cpp:180
void comment_bases(struct section_file *sfile)
Write bases header.
Definition: comments.cpp:236
void comment_terrains(struct section_file *sfile)
Write terrains header.
Definition: comments.cpp:212
void comment_file_header(struct section_file *sfile)
Write file header.
Definition: comments.cpp:148
void comment_effects(struct section_file *sfile)
Write effects header.
Definition: comments.cpp:276
void comment_disasters(struct section_file *sfile)
Write disasters header.
Definition: comments.cpp:284
void comment_clauses(struct section_file *sfile)
Write clauses header.
Definition: comments.cpp:348
void comment_goods(struct section_file *sfile)
Write goods header.
Definition: comments.cpp:300
void comment_extras(struct section_file *sfile)
Write extras header.
Definition: comments.cpp:228
void comment_techs(struct section_file *sfile)
Write techs header.
Definition: comments.cpp:172
void comment_nations(struct section_file *sfile)
Write nations header.
Definition: comments.cpp:324
void comment_nationgroups(struct section_file *sfile)
Write nationgroups header.
Definition: comments.cpp:332
void comment_specialists(struct section_file *sfile)
Write specialists header.
Definition: comments.cpp:316
void comment_musicstyles(struct section_file *sfile)
Write music styles header.
Definition: comments.cpp:268
void comment_resources(struct section_file *sfile)
Write resources header.
Definition: comments.cpp:220
void comment_tech_classes(struct section_file *sfile)
Write tech classess header.
Definition: comments.cpp:164
void comment_utypes(struct section_file *sfile)
Write unit types header.
Definition: comments.cpp:204
void comment_policies(struct section_file *sfile)
Write policies header.
Definition: comments.cpp:188
void comment_achievements(struct section_file *sfile)
Write achievements header.
Definition: comments.cpp:292
void comment_styles(struct section_file *sfile)
Write styles header.
Definition: comments.cpp:252
void comment_buildings(struct section_file *sfile)
Write buildings header.
Definition: comments.cpp:156
void comment_enablers(struct section_file *sfile)
Write action enablers header.
Definition: comments.cpp:308
void comment_nationsets(struct section_file *sfile)
Write nationsets header.
Definition: comments.cpp:340
struct clause_info * clause_info_get(enum clause_type type)
Free memory associated with clause infos.
Definition: diptreaty.cpp:257
#define disaster_type_iterate(_p)
Definition: disaster.h:70
#define disaster_type_iterate_end
Definition: disaster.h:76
struct @19::@20 reqs
bool iterate_effect_cache(iec_cb cb, void *data)
Iterate through all the effects in cache, and call callback for each.
Definition: effects.cpp:1259
bool extra_has_flag(const struct extra_type *pextra, enum extra_flag_id flag)
Check if extra has given flag.
Definition: extras.cpp:779
const char * extra_flag_id_name_cb(enum extra_flag_id flag)
Extra flag name callback, called from specenum code.
Definition: extras.cpp:880
bool can_extras_coexist(const struct extra_type *pextra1, const struct extra_type *pextra2)
Can two extras coexist in same tile?
Definition: extras.cpp:902
const char * extra_flag_helptxt(enum extra_flag_id id)
Return the (untranslated) help text of the user extra flag.
Definition: extras.cpp:892
bool is_extra_removed_by(const struct extra_type *pextra, enum extra_rmcause rmcause)
Is given cause one of the removal causes for the given extra?
Definition: extras.cpp:307
const char * extra_rule_name(const struct extra_type *pextra)
Return the (untranslated) rule name of the extra type.
Definition: extras.cpp:174
#define extra_type_iterate(_p)
Definition: extras.h:279
#define extra_type_iterate_end
Definition: extras.h:285
#define is_extra_caused_by(e, c)
Definition: extras.h:182
#define extra_index(_e_)
Definition: extras.h:163
#define extra_type_re_active_iterate_end
Definition: extras.h:294
#define extra_base_get(_e_)
Definition: extras.h:170
#define extra_road_get(_e_)
Definition: extras.h:171
#define extra_type_re_active_iterate(_p)
Definition: extras.h:289
#define extra_type_by_cause_iterate_end
Definition: extras.h:307
#define MAX_NUM_USER_EXTRA_FLAGS
Definition: extras.h:70
#define extra_type_by_cause_iterate(_cause, _extra)
Definition: extras.h:299
@ ROCO_RAILROAD
Definition: fc_types.h:1067
@ ROCO_NONE
Definition: fc_types.h:1067
@ ROCO_RIVER
Definition: fc_types.h:1067
@ ROCO_ROAD
Definition: fc_types.h:1067
#define MAX_NUM_NATION_SETS
Definition: fc_types.h:51
#define MAX_NUM_BUILDING_LIST
Definition: fc_types.h:38
@ SETDEF_RULESET
Definition: fc_types.h:1149
int action_id
Definition: fc_types.h:306
#define MAX_CALENDAR_FRAGMENTS
Definition: fc_types.h:57
#define MAX_NUM_NATION_GROUPS
Definition: fc_types.h:53
#define MAX_NUM_UNIT_LIST
Definition: fc_types.h:37
#define MAX_EXTRA_TYPES
Definition: fc_types.h:42
#define MAX_LEN_NAME
Definition: fc_types.h:61
#define MAX_NUM_TECH_LIST
Definition: fc_types.h:36
#define UCL_LAST
Definition: fc_types.h:332
const char * skip_intl_qualifier_prefix(const char *str)
Some strings are ambiguous for translation.
Definition: fcintl.cpp:39
struct civ_game game
Definition: game.cpp:47
struct world wld
Definition: game.cpp:48
#define RS_DEFAULT_RANSOM_GOLD
Definition: game.h:802
#define RS_DEFAULT_CIVIL_WAR_UNHAPPY
Definition: game.h:787
#define RS_DEFAULT_NUKE_DEFENDER_SURVIVAL_CHANCE_PCT
Definition: game.h:794
#define RS_DEFAULT_NUKE_POP_LOSS_PCT
Definition: game.h:791
#define RS_DEFAULT_BASE_POLLUTION
Definition: game.h:773
#define RS_DEFAULT_INCITE_TOTAL_FCT
Definition: game.h:750
#define RS_DEFAULT_ILLNESS_BASE_FACTOR
Definition: game.h:708
#define RS_DEFAULT_NEG_YEAR_LABEL
Definition: game.h:704
#define RS_DEFAULT_FORCE_TRADE_ROUTE
Definition: game.h:820
#define RS_DEFAULT_INCITE_IMPROVEMENT_FCT
Definition: game.h:742
#define RS_ACTION_NO_MAX_DISTANCE
Definition: game.h:833
#define RS_DEFAULT_BASE_BRIBE_COST
Definition: game.h:798
#define RS_DEFAULT_TECH_UPKEEP_DIVIDER
Definition: game.h:812
#define RS_DEFAULT_HAPPY_COST
Definition: game.h:778
#define RS_DEFAULT_ONLY_KILLING_VETERAN
Definition: game.h:790
#define RS_DEFAULT_POISON_EMPTIES_FOOD_STOCK
Definition: game.h:825
#define RS_DEFAULT_GRANARY_FOOD_INC
Definition: game.h:756
#define RS_DEFAULT_ILLNESS_ON
Definition: game.h:706
#define GAME_DEFAULT_CELEBRATESIZE
Definition: game.h:461
#define RS_DEFAULT_STEAL_MAP_REVEALS_CITIES
Definition: game.h:826
#define RS_DEFAULT_CIVIL_WAR_CELEB
Definition: game.h:786
#define RS_DEFAULT_BASE_TECH_COST
Definition: game.h:816
#define RS_DEFAULT_USER_ACTION_TARGET_KIND
Definition: game.h:828
#define RS_DEFAULT_UPGRADE_VETERAN_LOSS
Definition: game.h:808
#define RS_DEFAULT_CALENDAR_SKIP_0
Definition: game.h:724
#define RS_DEFAULT_CITY_RADIUS_SQ
Definition: game.h:765
#define RS_DEFAULT_BORDER_SIZE_EFFECT
Definition: game.h:730
#define RS_DEFAULT_FORCE_EXPLODE_NUCLEAR
Definition: game.h:823
#define RS_DEFAULT_FORCE_CAPTURE_UNITS
Definition: game.h:821
#define RS_DEFAULT_PILLAGE_SELECT
Definition: game.h:806
#define GAME_START_YEAR
Definition: game.h:680
#define RS_DEFAULT_POS_YEAR_LABEL
Definition: game.h:702
#define RS_DEFAULT_VIS_RADIUS_SQ
Definition: game.h:769
#define RS_DEFAULT_BORDER_RADIUS_SQ_CITY_PERMANENT
Definition: game.h:734
#define RS_DEFAULT_TIRED_ATTACK
Definition: game.h:789
#define RS_DEFAULT_ACTION_ACTOR_CONSUMING_ALWAYS
Definition: game.h:827
#define RS_DEFAULT_ILLNESS_TRADE_INFECTION_PCT
Definition: game.h:716
#define RS_DEFAULT_FOOD_COST
Definition: game.h:782
#define RS_DEFAULT_INCITE_UNIT_FCT
Definition: game.h:746
#define RS_DEFAULT_INCITE_BASE_COST
Definition: game.h:738
#define RS_DEFAULT_FORCE_BOMBARD
Definition: game.h:822
#define GAME_DEFAULT_ANGRYCITIZEN
Definition: game.h:352
#define RS_DEFAULT_CITY_CENTER_OUTPUT
Definition: game.h:760
#define RS_DEFAULT_ILLNESS_POLLUTION_PCT
Definition: game.h:720
#define RS_DEFAULT_ILLNESS_MIN_SIZE
Definition: game.h:712
#define RS_DEFAULT_BORDER_RADIUS_SQ_CITY
Definition: game.h:726
const char * government_rule_name(const struct government *pgovern)
Return the (untranslated) rule name of the government.
Definition: government.cpp:126
const char * ruler_title_female_untranslated_name(const struct ruler_title *pruler_title)
Return the female rule title name.
Definition: government.cpp:358
const char * ruler_title_male_untranslated_name(const struct ruler_title *pruler_title)
Return the male rule title name.
Definition: government.cpp:349
std::vector< government > governments
Definition: government.cpp:28
const char * improvement_rule_name(const struct impr_type *pimprove)
Return the (untranslated) rule name of the improvement.
struct impr_type * improvement_by_number(const Impr_type_id id)
Returns the improvement type for the given index/ID.
bool improvement_has_flag(const struct impr_type *pimprove, enum impr_flag_id flag)
Return TRUE if the impr has this flag otherwise FALSE.
#define improvement_re_active_iterate_end
Definition: improvement.h:209
#define improvement_re_active_iterate(_p)
Definition: improvement.h:204
#define B_LAST
Definition: improvement.h:33
const char * name
Definition: inputfile.cpp:118
#define fc_assert_msg(condition, message,...)
Definition: log.h:96
#define fc_assert(condition)
Definition: log.h:89
struct terrain_misc terrain_control
Definition: map.cpp:40
#define SINGLE_MOVE
Definition: movement.h:17
#define multipliers_iterate(_mul_)
Definition: multipliers.h:45
#define multipliers_iterate_end
Definition: multipliers.h:51
static const char * untranslated_name(const struct name_translation *ptrans)
static const char * rule_name_get(const struct name_translation *ptrans)
const char * nation_set_untranslated_name(const struct nation_set *pset)
Return the untranslated name of a nation set (including qualifier, if any).
Definition: nation.cpp:672
bool nation_leader_is_male(const struct nation_leader *pleader)
Return the sex of the nation leader.
Definition: nation.cpp:266
enum nation_city_preference nation_city_terrain_preference(const struct nation_city *pncity, const struct terrain *pterrain)
Return the default nation city preference for the terrain.
Definition: nation.cpp:398
const char * nation_rule_name(const struct nation_type *pnation)
Return the (untranslated) rule name of the nation (adjective form).
Definition: nation.cpp:115
std::vector< nation_type > nations
Definition: nation.cpp:38
bool nation_is_in_group(const struct nation_type *pnation, const struct nation_group *pgroup)
Check if the given nation is in a given group.
Definition: nation.cpp:962
bool nation_is_in_set(const struct nation_type *pnation, const struct nation_set *pset)
Check if the given nation is in a given set.
Definition: nation.cpp:712
enum nation_city_preference nation_city_river_preference(const struct nation_city *pncity)
Return the default nation city preference for rivers.
Definition: nation.cpp:410
const char * nation_set_rule_name(const struct nation_set *pset)
Return the (untranslated) rule name of a nation set.
Definition: nation.cpp:682
const char * nation_set_description(const struct nation_set *pset)
Return the (untranslated) user description of a nation set.
Definition: nation.cpp:703
struct nation_type * nation_by_rule_name(const char *name)
Returns the nation that has the given (untranslated) rule name (adjective).
Definition: nation.cpp:98
const char * nation_leader_name(const struct nation_leader *pleader)
Return the name of the nation leader.
Definition: nation.cpp:257
const char * nation_city_name(const struct nation_city *pncity)
Return the name of the default nation city.
Definition: nation.cpp:388
const char * nation_group_rule_name(const struct nation_group *pgroup)
Return the (untranslated) rule name of a nation group.
Definition: nation.cpp:942
#define nation_leader_list_iterate(leaderlist, pleader)
Definition: nation.h:45
#define nation_list_iterate(nationlist, pnation)
Definition: nation.h:72
#define nation_sets_iterate_end
Definition: nation.h:286
#define nation_sets_iterate(NAME_pset)
Definition: nation.h:283
@ NCP_NONE
Definition: nation.h:31
@ NCP_DISLIKE
Definition: nation.h:31
@ NCP_LIKE
Definition: nation.h:31
#define nation_city_list_iterate(citylist, pncity)
Definition: nation.h:36
#define nation_list_iterate_end
Definition: nation.h:74
#define nation_city_list_iterate_end
Definition: nation.h:38
#define nation_leader_list_iterate_end
Definition: nation.h:47
#define nation_groups_iterate(NAME_pgroup)
Definition: nation.h:292
#define nation_groups_iterate_end
Definition: nation.h:296
int len
Definition: packhand.cpp:127
struct section_file * secfile_new(bool allow_duplicates)
Create a new empty section file.
bool secfile_save(const struct section_file *secfile, QString filename)
Save the previously filled in section_file to disk.
struct entry * secfile_insert_filereference(struct section_file *secfile, const char *filename, const char *path,...)
Insert a read-from-a-file string entry.
const char * entry_name(const struct entry *pentry)
Returns the name of this entry.
bool entry_str_set_gt_marking(struct entry *pentry, bool gt_marking)
Sets if the string should get gettext marking.
struct section * secfile_insert_include(struct section_file *secfile, const char *filename)
Insert a include entry.
#define secfile_insert_int(secfile, value, path,...)
Definition: registry_ini.h:116
#define secfile_insert_enum_vec(secfile, enumerators, dim, specenum_type, path,...)
Definition: registry_ini.h:296
#define secfile_insert_enum(secfile, enumerator, specenum_type, path,...)
Definition: registry_ini.h:257
#define secfile_insert_int_vec(secfile, values, dim, path,...)
Definition: registry_ini.h:131
#define secfile_insert_str_vec(secfile, strings, dim, path,...)
Definition: registry_ini.h:204
#define secfile_insert_str(secfile, string, path,...)
Definition: registry_ini.h:167
#define secfile_insert_bool(secfile, value, path,...)
Definition: registry_ini.h:79
#define secfile_insert_enum_data(secfile, value, bitwise, name_fn, data, path,...)
Definition: registry_ini.h:318
QString req_to_fstring(const struct requirement *req)
Returns the given requirement as a formatted string ready for printing.
const char * universal_rule_name(const struct universal *psource)
Return the (untranslated) rule name of the universal.
#define requirement_vector_iterate_end
Definition: requirements.h:80
#define requirement_vector_iterate(req_vec, preq)
Definition: requirements.h:78
void rgbcolor_save(struct section_file *file, const struct rgbcolor *prgbcolor, const char *path,...)
Save an RGB color definition ([colorpath].red, [colorpath].green and [colorpath].blue).
Definition: rgbcolor.cpp:109
#define rgbcolor_list_iterate_end
Definition: rgbcolor.h:37
#define rgbcolor_list_iterate(rgbcolorlist, prgbcolor)
Definition: rgbcolor.h:35
bool road_has_flag(const struct road_type *proad, enum road_flag_id flag)
Check if road provides effect.
Definition: road.cpp:367
static bool save_reqs_vector(struct section_file *sfile, const struct requirement_vector *reqs, const char *path, const char *entry)
Save vector of requirements.
Definition: rulesave.cpp:133
static bool save_tech_list(struct section_file *sfile, int *input, const char *path, const char *entry)
Save techs vector.
Definition: rulesave.cpp:191
static bool save_name_translation(struct section_file *sfile, struct name_translation *name, const char *path)
Save name of the object.
Definition: rulesave.cpp:113
static bool save_terrain_ref(struct section_file *sfile, const struct terrain *save, const struct terrain *pthis, const char *path, const char *entry)
Save terrain reference.
Definition: rulesave.cpp:230
static bool save_nations_ruleset(const char *filename, const char *name, struct rule_data *data)
Save nations.ruleset.
Definition: rulesave.cpp:1801
static bool save_action_kind(struct section_file *sfile, action_id act)
Save details of an action.
Definition: rulesave.cpp:834
static bool save_action_actor_consuming_always(struct section_file *sfile, action_id act)
Save if an action always will consume the actor.
Definition: rulesave.cpp:856
static bool save_action_max_range(struct section_file *sfile, action_id act)
Save max range of an action.
Definition: rulesave.cpp:796
static bool save_traits(struct trait_limits *traits, struct trait_limits *default_traits, struct section_file *sfile, const char *secname, const char *field_prefix)
Save list of AI traits.
Definition: rulesave.cpp:1552
#define FORMAT_VERSION
Definition: rulesave.cpp:46
static struct section_file * create_ruleset_file(const char *rsname, const char *rstype)
Create new ruleset section file with common header.
Definition: rulesave.cpp:51
bool save_ruleset(const char *path, const char *name, struct rule_data *data)
Save ruleset to directory given.
Definition: rulesave.cpp:3013
static bool save_strvec(struct section_file *sfile, QVector< QString > *to_save, const char *path, const char *entry)
Save strvec as ruleset vector of strings.
Definition: rulesave.cpp:341
static bool save_cities_ruleset(const char *filename, const char *name)
Save cities.ruleset.
Definition: rulesave.cpp:616
static bool save_techs_ruleset(const char *filename, const char *name)
Save techs.ruleset.
Definition: rulesave.cpp:1932
static bool save_uclass_vec(struct section_file *sfile, bv_unit_classes *bits, const char *path, const char *entry, bool unreachable_only)
Save vector of unit class names based on bitvector bits.
Definition: rulesave.cpp:314
static bool save_ruleset_file(struct section_file *sfile, const char *filename)
Save ruleset file.
Definition: rulesave.cpp:356
static bool save_veteran_system(struct section_file *sfile, const char *path, struct veteran_system *vsystem)
Save one veteran system.
Definition: rulesave.cpp:2622
static bool save_unit_list(struct section_file *sfile, const std::array< unit_type *, MAX_NUM_UNIT_LIST > &input, const char *path, const char *entry)
Save units vector.
Definition: rulesave.cpp:288
static bool save_default_bool(struct section_file *sfile, bool value, bool default_value, const char *path, const char *entry)
Save bool value that has default applied upon loading.
Definition: rulesave.cpp:95
static bool effect_save(struct effect *peffect, void *data)
Save one effect.
Definition: rulesave.cpp:738
static bool save_game_ruleset(const char *filename, const char *name)
Save game.ruleset.
Definition: rulesave.cpp:877
static bool save_buildings_ruleset(const char *filename, const char *name)
Save buildings.ruleset.
Definition: rulesave.cpp:365
static bool save_action_auto_uflag_block(struct section_file *sfile, const int aap, const char *uflags_path, bool(*unexpected_req)(const struct requirement *preq))
Save an action auto performer's !present utype reqs as a regular setting.
Definition: rulesave.cpp:510
static bool unexpected_non_otype(const struct requirement *req)
Missing unit upkeep should only contain output type and absence of blocking unit type flag requiremen...
Definition: rulesave.cpp:587
static bool save_building_list(struct section_file *sfile, int *input, const char *path, const char *entry)
Save buildings vector.
Definition: rulesave.cpp:262
static bool save_luadata(const char *filename)
Save luadata.txt.
Definition: rulesave.cpp:3001
static bool save_governments_ruleset(const char *filename, const char *name)
Save governments.ruleset.
Definition: rulesave.cpp:1469
static bool save_units_ruleset(const char *filename, const char *name)
Save units.ruleset.
Definition: rulesave.cpp:2696
static bool save_terrain_ruleset(const char *filename, const char *name)
Save terrain.ruleset.
Definition: rulesave.cpp:2036
static bool save_muuk_action_auto(struct section_file *sfile, const int aap, const char *item)
Save the action a unit should perform when its missing food, gold or shield upkeep.
Definition: rulesave.cpp:597
static bool save_action_range(struct section_file *sfile, action_id act)
Save range of an action.
Definition: rulesave.cpp:812
static bool save_gov_ref(struct section_file *sfile, const struct government *gov, const char *path, const char *entry)
Save government reference.
Definition: rulesave.cpp:249
static bool save_styles_ruleset(const char *filename, const char *name)
Save styles.ruleset.
Definition: rulesave.cpp:435
static bool save_combat_bonuses(struct section_file *sfile, struct unit_type *put, char *path)
Save unit combat bonuses list.
Definition: rulesave.cpp:2657
static bool save_effects_ruleset(const char *filename, const char *name)
Save effects.ruleset.
Definition: rulesave.cpp:757
static bool save_default_int(struct section_file *sfile, int value, int default_value, const char *path, const char *entry)
Save int value that has default applied upon loading.
Definition: rulesave.cpp:77
static bool save_nation(struct section_file *sfile, struct nation_type *pnat, int sect_idx)
Save a single nation.
Definition: rulesave.cpp:1594
static bool save_script_lua(const char *filename, const char *name, const char *buffer)
Save script.lua.
Definition: rulesave.cpp:2975
static bool save_action_auto_actions(struct section_file *sfile, const int aap, const char *actions_path)
Save an action auto performer's action list as a regular setting.
Definition: rulesave.cpp:556
static bool save_tech_ref(struct section_file *sfile, const struct advance *padv, const char *path, const char *entry)
Save tech reference.
Definition: rulesave.cpp:214
static bool save_action_ui_name(struct section_file *sfile, int act, const char *entry_name)
Save ui_name of one action.
Definition: rulesave.cpp:781
char * get_script_buffer()
Return current script.lua buffer.
Definition: ruleset.cpp:244
char * get_parser_buffer()
Return current parser.lua buffer.
Definition: ruleset.cpp:249
#define RS_DEFAULT_TECH_TRADE_LOSS_HOLES
Definition: ruleset.h:72
#define RS_DEFAULT_EXTRA_APPEARANCE
Definition: ruleset.h:88
#define RS_DEFAULT_TECH_PARASITE_HOLES
Definition: ruleset.h:73
#define GAME_DEFAULT_ACH_VALUE
Definition: ruleset.h:66
#define RS_DEFAULT_TECH_TRADE_HOLES
Definition: ruleset.h:71
#define RS_DEFAULT_CULTURE_VIC_POINTS
Definition: ruleset.h:83
#define RS_DEFAULT_CULTURE_MIGRATION_PML
Definition: ruleset.h:85
#define RS_DEFAULT_TECH_LOSS_HOLES
Definition: ruleset.h:74
#define RS_DEFAULT_HISTORY_INTEREST_PML
Definition: ruleset.h:86
#define RS_DEFAULT_PYTHAGOREAN_DIAGONAL
Definition: ruleset.h:75
#define RS_DEFAULT_TECH_STEAL_HOLES
Definition: ruleset.h:70
#define GAME_DEFAULT_ACH_UNIQUE
Definition: ruleset.h:65
#define RS_DEFAULT_MUUK_FOOD_WIPE
Definition: ruleset.h:67
#define RS_DEFAULT_MUUK_GOLD_WIPE
Definition: ruleset.h:68
#define RULESET_CAPABILITIES
Definition: ruleset.h:22
#define RS_DEFAULT_MUUK_SHIELD_WIPE
Definition: ruleset.h:69
#define RS_DEFAULT_GOLD_UPKEEP_STYLE
Definition: ruleset.h:78
#define GAME_DEFAULT_NATIONALITY
Definition: ruleset.h:62
#define GAME_DEFAULT_ADDTOSIZE
Definition: ruleset.h:59
#define RS_DEFAULT_EXTRA_DISAPPEARANCE
Definition: ruleset.h:89
#define GAME_DEFAULT_VISION_REVEAL_TILES
Definition: ruleset.h:61
#define RS_DEFAULT_CULTURE_VIC_LEAD
Definition: ruleset.h:84
#define GAME_DEFAULT_CHANGEABLE_BUDGET
Definition: ruleset.h:60
#define GAME_DEFAULT_DISASTER_FREQ
Definition: ruleset.h:64
#define GAME_DEFAULT_CONVERT_SPEED
Definition: ruleset.h:63
int setting_int_get(struct setting *pset)
Get value of integer setting.
Definition: settings.cpp:3502
bool setting_locked(const struct setting *pset)
Returns if the setting is locked by the ruleset.
Definition: settings.cpp:4283
enum sset_type setting_type(const struct setting *pset)
Access function for the setting type.
Definition: settings.cpp:3092
const char * setting_name(const struct setting *pset)
Access function for the setting name.
Definition: settings.cpp:3065
enum setting_default_level setting_get_setdef(const struct setting *pset)
Is the setting in changed state, or the default.
Definition: settings.cpp:5160
const char * setting_bitwise_secfile_str(secfile_data_t data, int bit)
Convert the integer to the long support string representation of an enumerator.
Definition: settings.cpp:3763
char * setting_str_get(struct setting *pset)
Get value of string setting.
Definition: settings.cpp:3572
int setting_bitwise_get(struct setting *pset)
Get value of bitwise setting.
Definition: settings.cpp:3936
bool setting_bool_get(struct setting *pset)
Get value of boolean setting.
Definition: settings.cpp:3391
int read_enum_value(const struct setting *pset)
Helper function to read value from enumerator setting.
Definition: settings.cpp:3692
const char * setting_enum_secfile_str(secfile_data_t data, int val)
Convert the integer to the long support string representation of an enumerator.
Definition: settings.cpp:3583
#define settings_iterate(_level, _pset)
Definition: settings.h:168
#define settings_iterate_end
Definition: settings.h:175
bool make_dir(const QString &pathname)
If the directory "pathname" does not exist, recursively create all directories until it does.
Definition: shared.cpp:1115
#define MAX(x, y)
Definition: shared.h:48
struct specialist * specialist_by_number(const Specialist_type_id id)
Return the specialist pointer for the given number.
Definition: specialist.cpp:92
#define specialist_type_iterate_end
Definition: specialist.h:73
#define specialist_type_iterate(sp)
Definition: specialist.h:67
struct requirement_vector reqs
Definition: actions.h:461
action_id alternatives[MAX_NUM_ACTIONS]
Definition: actions.h:465
char ui_name[MAX_LEN_NAME]
Definition: actions.h:323
Definition: tech.h:113
bool inherited_root_req
Definition: tech.h:121
Definition: base.h:43
int border_sq
Definition: base.h:46
int vision_main_sq
Definition: base.h:47
enum base_gui_type gui_type
Definition: base.h:45
int vision_invis_sq
Definition: base.h:48
int vision_subs_sq
Definition: base.h:49
struct civ_game::@28::@32 server
struct rgbcolor * plr_bg_color
Definition: game.h:93
struct packet_ruleset_control control
Definition: game.h:74
char * ruleset_summary
Definition: game.h:75
int global_init_techs[MAX_NUM_TECH_LIST]
Definition: game.h:98
struct packet_game_info info
Definition: game.h:80
int global_init_buildings[MAX_NUM_BUILDING_LIST]
Definition: game.h:99
char * ruleset_description
Definition: game.h:76
struct civ_game::@27 rgame
char * ruleset_capabilities
Definition: game.h:77
struct veteran_system * veteran
Definition: game.h:91
struct packet_calendar_info calendar
Definition: game.h:81
struct government * default_government
Definition: game.h:84
struct government * government_during_revolution
Definition: game.h:85
struct civ_map::@39::@41 server
struct requirement_vector receiver_reqs
Definition: diptreaty.h:50
struct requirement_vector giver_reqs
Definition: diptreaty.h:49
enum clause_type type
Definition: diptreaty.h:47
bool enabled
Definition: diptreaty.h:48
Effect saving callback data structure.
Definition: rulesave.cpp:730
struct section_file * sfile
Definition: rulesave.cpp:732
int value
Definition: effects.h:336
struct requirement_vector reqs
Definition: effects.h:340
enum effect_type type
Definition: effects.h:328
Definition: climisc.h:66
int init_buildings[MAX_NUM_BUILDING_LIST]
Definition: nation.h:102
struct name_translation noun_plural
Definition: nation.h:81
char flag_graphic_str[MAX_LEN_NAME]
Definition: nation.h:82
struct name_translation adjective
Definition: nation.h:80
char flag_graphic_alt[MAX_LEN_NAME]
Definition: nation.h:83
struct nation_leader_list * leaders
Definition: nation.h:84
struct nation_type::@48::@50 server
std::array< unit_type *, MAX_NUM_UNIT_LIST > init_units
Definition: nation.h:105
char * legend
Definition: nation.h:86
enum barbarian_type barb_type
Definition: nation.h:89
char * translation_domain
Definition: nation.h:79
struct nation_style * style
Definition: nation.h:85
int init_techs[MAX_NUM_TECH_LIST]
Definition: nation.h:101
government * init_government
Definition: nation.h:103
bool is_playable
Definition: nation.h:88
struct universal source
Definition: requirements.h:68
Definition: road.h:54
enum road_move_mode move_mode
Definition: road.h:58
int tile_bonus[O_LAST]
Definition: road.h:61
int tile_incr_const[O_LAST]
Definition: road.h:59
int tile_incr[O_LAST]
Definition: road.h:60
int move_cost
Definition: road.h:57
enum road_compat compat
Definition: road.h:62
char * nationlist
Definition: rulesave.h:15
Ruler titles.
Definition: government.cpp:181
struct requirement_vector reqs
Definition: specialist.h:32
char graphic_alt[MAX_LEN_NAME]
Definition: specialist.h:30
char graphic_str[MAX_LEN_NAME]
Definition: specialist.h:29
struct name_translation name
Definition: specialist.h:25
QVector< QString > * helptext
Definition: specialist.h:34
struct name_translation abbreviation
Definition: specialist.h:26
enum traderoute_bonus_type bonus_type
Definition: traderoutes.h:67
enum traderoute_illegal_cancelling cancelling
Definition: traderoutes.h:66
int min
Definition: traits.h:37
int max
Definition: traits.h:38
struct combat_bonus_list * bonuses
Definition: unittype.h:491
enum universals_n kind
Definition: fc_types.h:740
int power_fact
Definition: unittype.h:453
int base_raise_chance
Definition: unittype.h:455
struct name_translation name
Definition: unittype.h:452
int move_bonus
Definition: unittype.h:454
int work_raise_chance
Definition: unittype.h:456
struct veteran_level * definitions
Definition: unittype.h:462
struct civ_map map
Definition: world_object.h:21
const char * style_rule_name(const struct nation_style *pstyle)
Return the (untranslated) rule name of the style.
Definition: style.cpp:94
#define music_styles_iterate(_p)
Definition: style.h:68
#define music_styles_iterate_end
Definition: style.h:75
#define styles_re_active_iterate_end
Definition: style.h:55
#define styles_re_active_iterate(_p)
Definition: style.h:50
int fc_snprintf(char *str, size_t n, const char *format,...)
See also fc_utf8_snprintf_trunc(), fc_utf8_snprintf_rep().
Definition: support.cpp:537
int fc_strcasecmp(const char *str0, const char *str1)
Compare strings like strcmp(), but ignoring case.
Definition: support.cpp:89
FILE * fc_fopen(const char *filename, const char *opentype)
Wrapper function for fopen() with filename conversion to local encoding on Windows.
Definition: support.cpp:255
const char * team_slot_rule_name(const struct team_slot *tslot)
Returns the name (untranslated) of the slot.
Definition: team.cpp:217
struct team_slot * team_slot_by_number(int team_id)
Return the possibly unused and uninitialized team slot.
Definition: team.cpp:157
bool advance_has_flag(Tech_type_id tech, enum tech_flag_id flag)
Return TRUE if the tech has this flag otherwise FALSE.
Definition: tech.cpp:198
const char * advance_rule_name(const struct advance *padvance)
Return the (untranslated) rule name of the advance/technology.
Definition: tech.cpp:283
struct advance * advance_by_number(const Tech_type_id atype)
Return the advance for the given advance index.
Definition: tech.cpp:94
const char * tech_class_rule_name(const struct tech_class *ptclass)
Return the (untranslated) rule name of tech_class You must not free the return pointer.
Definition: tech.cpp:326
const char * tech_flag_helptxt(enum tech_flag_id id)
Return the (untranslated) helptxt of the user tech flag.
Definition: tech.cpp:413
Tech_type_id advance_index(const struct advance *padvance)
Return the advance index.
Definition: tech.cpp:76
const char * tech_flag_id_name_cb(enum tech_flag_id flag)
Tech flag name callback, called from specenum code.
Definition: tech.cpp:401
#define advance_re_active_iterate(_p)
Definition: tech.h:243
#define A_NEVER
Definition: tech.h:44
#define tech_class_iterate_end
Definition: tech.h:178
#define MAX_NUM_USER_TECH_FLAGS
Definition: tech.h:102
@ AR_TWO
Definition: tech.h:104
@ AR_ROOT
Definition: tech.h:104
@ AR_ONE
Definition: tech.h:104
#define advance_re_active_iterate_end
Definition: tech.h:248
#define A_NONE
Definition: tech.h:36
#define tech_class_iterate(_p)
Definition: tech.h:172
#define A_LAST
Definition: tech.h:38
const char * terrain_rule_name(const struct terrain *pterrain)
Return the (untranslated) rule name of the terrain.
Definition: terrain.cpp:184
const char * terrain_flag_id_name_cb(enum terrain_flag_id flag)
Terrain flag name callback, called from specenum code.
Definition: terrain.cpp:696
const char * terrain_flag_helptxt(enum terrain_flag_id id)
Return the (untranslated) helptxt of the user terrain flag.
Definition: terrain.cpp:708
#define terrain_type_iterate(_p)
Definition: terrain.h:331
#define terrain_type_iterate_end
Definition: terrain.h:337
#define MAX_NUM_TERRAINS
Definition: terrain.h:58
#define terrain_has_flag(terr, flag)
Definition: terrain.h:260
#define MAX_NUM_USER_TER_FLAGS
Definition: terrain.h:140
bool goods_has_flag(const struct goods_type *pgood, enum goods_flag_id flag)
Check if goods has given flag.
const char * trade_route_type_name(enum trade_route_type type)
Return human readable name of trade route type.
struct trade_route_settings * trade_route_settings_by_type(enum trade_route_type type)
Get trade route settings related to type.
const char * traderoute_cancelling_type_name(enum traderoute_illegal_cancelling type)
Return human readable name of traderoute cancelling type.
#define goods_type_re_active_iterate_end
Definition: traderoutes.h:233
#define goods_type_re_active_iterate(_p)
Definition: traderoutes.h:228
trade_route_type
Definition: traderoutes.h:30
@ TRT_LAST
Definition: traderoutes.h:41
#define TRAIT_DEFAULT_VALUE
Definition: traits.h:27
const char * unit_type_flag_id_name_cb(enum unit_type_flag_id flag)
Unit type flag name callback, called from specenum code.
Definition: unittype.cpp:1577
const char * unit_class_flag_helptxt(enum unit_class_flag_id id)
Return the (untranslated) help text of the user unit class flag.
Definition: unittype.cpp:1534
const char * utype_rule_name(const struct unit_type *punittype)
Return the (untranslated) rule name of the unit type.
Definition: unittype.cpp:1274
bool utype_has_role(const struct unit_type *punittype, int role)
Return whether the given unit type has the role.
Definition: unittype.cpp:186
const char * unit_type_flag_helptxt(enum unit_type_flag_id id)
Return the (untranslated) helptxt of the user unit flag.
Definition: unittype.cpp:1589
const char * unit_class_flag_id_name_cb(enum unit_class_flag_id flag)
Unit class flag name callback, called from specenum code.
Definition: unittype.cpp:1522
const char * uclass_rule_name(const struct unit_class *pclass)
Return the (untranslated) rule name of the unit class.
Definition: unittype.cpp:1333
static bool uclass_has_flag(const struct unit_class *punitclass, enum unit_class_flag_id flag)
Definition: unittype.h:704
#define unit_type_re_active_iterate(_p)
Definition: unittype.h:796
#define combat_bonus_list_iterate_end
Definition: unittype.h:447
#define L_FIRST
Definition: unittype.h:319
#define combat_bonus_list_iterate(bonuslist, pbonus)
Definition: unittype.h:445
@ HUT_FRIGHTEN
Definition: unittype.h:113
@ HUT_NOTHING
Definition: unittype.h:113
@ HUT_NORMAL
Definition: unittype.h:113
#define unit_class_iterate(_p)
Definition: unittype.h:823
#define unit_class_re_active_iterate_end
Definition: unittype.h:839
#define MAX_NUM_USER_UNIT_FLAGS
Definition: unittype.h:303
static bool utype_has_flag(const struct unit_type *punittype, int flag)
Definition: unittype.h:584
#define UTYF_LAST_USER_FLAG
Definition: unittype.h:302
#define L_LAST
Definition: unittype.h:406
#define unit_class_re_active_iterate(_p)
Definition: unittype.h:834
#define uclass_index(_c_)
Definition: unittype.h:684
#define unit_class_iterate_end
Definition: unittype.h:829
#define MAX_NUM_USER_UCLASS_FLAGS
Definition: unittype.h:98
#define unit_type_re_active_iterate_end
Definition: unittype.h:801
const char * freeciv21_version()
Returns the raw version string.
Definition: version.cpp:29