Freeciv21
Develop your civilization from humble roots to a global empire
ruleset.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 #include <cstdarg>
15 #include <cstdlib>
16 #include <cstring>
17 
18 #include "bitvector.h"
19 #include "deprecations.h"
20 #include "fcintl.h"
21 #include "registry.h"
22 #include "registry_ini.h"
23 #include "shared.h"
24 #include "support.h"
25 
26 // common
27 #include "achievements.h"
28 #include "actions.h"
29 #include "ai.h"
30 #include "base.h"
31 #include "city.h"
32 #include "effects.h"
33 #include "extras.h"
34 #include "fc_types.h"
35 #include "featured_text.h"
36 #include "game.h"
37 #include "government.h"
38 #include "map.h"
39 #include "movement.h"
40 #include "multipliers.h"
41 #include "name_translation.h"
42 #include "nation.h"
43 #include "packets.h"
44 #include "player.h"
45 #include "requirements.h"
46 #include "rgbcolor.h"
47 #include "road.h"
48 #include "specialist.h"
49 #include "style.h"
50 #include "tech.h"
51 #include "traderoutes.h"
52 
53 // server
54 #include "notify.h"
55 #include "plrhand.h"
56 #include "rscompat.h"
57 #include "rssanity.h"
58 #include "settings.h"
59 #include "srv_main.h"
60 
61 /* server/advisors */
62 #include "advruleset.h"
63 
64 /* server/scripting */
65 #include "script_server.h"
66 
67 #include "ruleset.h"
68 #include "unittype.h"
69 
70 // RULESET_SUFFIX already used, no leading dot here
71 #define RULES_SUFFIX "ruleset"
72 #define SCRIPT_SUFFIX "lua"
73 
74 #define ADVANCE_SECTION_PREFIX "advance_"
75 #define TECH_CLASS_SECTION_PREFIX "techclass_"
76 #define BUILDING_SECTION_PREFIX "building_"
77 #define CITYSTYLE_SECTION_PREFIX "citystyle_"
78 #define MUSICSTYLE_SECTION_PREFIX "musicstyle_"
79 #define EFFECT_SECTION_PREFIX "effect_"
80 #define GOVERNMENT_SECTION_PREFIX "government_"
81 #define NATION_SET_SECTION_PREFIX "nset" // without underscore?
82 #define NATION_GROUP_SECTION_PREFIX "ngroup" // without underscore?
83 #define NATION_SECTION_PREFIX "nation" // without underscore?
84 #define STYLE_SECTION_PREFIX "style_"
85 #define CLAUSE_SECTION_PREFIX "clause_"
86 #define EXTRA_SECTION_PREFIX "extra_"
87 #define BASE_SECTION_PREFIX "base_"
88 #define ROAD_SECTION_PREFIX "road_"
89 #define RESOURCE_SECTION_PREFIX "resource_"
90 #define GOODS_SECTION_PREFIX "goods_"
91 #define SPECIALIST_SECTION_PREFIX "specialist_"
92 #define TERRAIN_SECTION_PREFIX "terrain_"
93 #define UNIT_CLASS_SECTION_PREFIX "unitclass_"
94 #define UNIT_SECTION_PREFIX "unit_"
95 #define DISASTER_SECTION_PREFIX "disaster_"
96 #define ACHIEVEMENT_SECTION_PREFIX "achievement_"
97 #define ACTION_ENABLER_SECTION_PREFIX "actionenabler_"
98 #define MULTIPLIER_SECTION_PREFIX "multiplier_"
99 
100 #define check_name(name) (check_strlen(name, MAX_LEN_NAME, nullptr))
101 #define check_cityname(name) (check_strlen(name, MAX_LEN_CITYNAME, nullptr))
102 
103 // avoid re-reading files
104 static const char name_too_long[] = "Name \"%s\" too long; truncating.";
105 #define MAX_SECTION_LABEL 64
106 #define section_strlcpy(dst, src) \
107  (void) loud_strlcpy(dst, src, MAX_SECTION_LABEL, name_too_long)
108 static char (*resource_sections)[MAX_SECTION_LABEL] = nullptr;
109 static char (*terrain_sections)[MAX_SECTION_LABEL] = nullptr;
110 static char (*extra_sections)[MAX_SECTION_LABEL] = nullptr;
111 static char (*base_sections)[MAX_SECTION_LABEL] = nullptr;
112 static char (*road_sections)[MAX_SECTION_LABEL] = nullptr;
113 
114 static struct requirement_vector reqs_list;
115 
116 static bool load_rulesetdir(const char *rsdir, bool compat_mode,
117  rs_conversion_logger logger, bool act,
118  bool buffer_script, bool load_luadata);
119 static struct section_file *openload_ruleset_file(const char *whichset,
120  const char *rsdir);
121 
122 static bool load_game_names(struct section_file *file,
123  struct rscompat_info *compat);
124 static bool load_tech_names(struct section_file *file,
125  struct rscompat_info *compat);
126 static bool load_unit_names(struct section_file *file,
127  struct rscompat_info *compat);
128 static bool load_building_names(struct section_file *file,
129  struct rscompat_info *compat);
130 static bool load_government_names(struct section_file *file,
131  struct rscompat_info *compat);
132 static bool load_terrain_names(struct section_file *file,
133  struct rscompat_info *compat);
134 static bool load_style_names(struct section_file *file,
135  struct rscompat_info *compat);
136 static bool load_nation_names(struct section_file *file,
137  struct rscompat_info *compat);
138 static bool
139 load_city_name_list(struct section_file *file, struct nation_type *pnation,
140  const char *secfile_str1, const char *secfile_str2,
141  const char **allowed_terrains, size_t atcount);
142 
143 static bool load_ruleset_techs(struct section_file *file,
144  struct rscompat_info *compat);
145 static bool load_ruleset_units(struct section_file *file,
146  struct rscompat_info *compat);
147 static bool load_ruleset_buildings(struct section_file *file,
148  struct rscompat_info *compat);
149 static bool load_ruleset_governments(struct section_file *file,
150  struct rscompat_info *compat);
151 static bool load_ruleset_terrain(struct section_file *file,
152  struct rscompat_info *compat);
153 static bool load_ruleset_styles(struct section_file *file,
154  struct rscompat_info *compat);
155 static bool load_ruleset_cities(struct section_file *file,
156  struct rscompat_info *compat);
157 static bool load_ruleset_effects(struct section_file *file,
158  struct rscompat_info *compat);
159 static bool load_ruleset_game(struct section_file *file, bool act,
160  struct rscompat_info *compat);
161 
162 static void send_ruleset_tech_classes(struct conn_list *dest);
163 static void send_ruleset_techs(struct conn_list *dest);
164 static void send_ruleset_unit_classes(struct conn_list *dest);
165 static void send_ruleset_units(struct conn_list *dest);
166 static void send_ruleset_buildings(struct conn_list *dest);
167 static void send_ruleset_terrain(struct conn_list *dest);
168 static void send_ruleset_resources(struct conn_list *dest);
169 static void send_ruleset_extras(struct conn_list *dest);
170 static void send_ruleset_bases(struct conn_list *dest);
171 static void send_ruleset_roads(struct conn_list *dest);
172 static void send_ruleset_goods(struct conn_list *dest);
173 static void send_ruleset_governments(struct conn_list *dest);
174 static void send_ruleset_styles(struct conn_list *dest);
175 static void send_ruleset_clauses(struct conn_list *dest);
176 static void send_ruleset_musics(struct conn_list *dest);
177 static void send_ruleset_cities(struct conn_list *dest);
178 static void send_ruleset_game(struct conn_list *dest);
179 static void send_ruleset_team_names(struct conn_list *dest);
180 
181 static bool load_ruleset_veteran(struct section_file *file, const char *path,
182  struct veteran_system **vsystem, char *err,
183  size_t err_len, bool compat);
184 
185 static int secfile_lookup_int_default_min_max(struct section_file *file,
186  int def, int min, int max,
187  const char *path, ...)
188  fc__attribute((__format__(__printf__, 5, 6)));
189 
190 Q_LOGGING_CATEGORY(ruleset_category, "freeciv.ruleset")
191 
192 char *script_buffer = nullptr;
193 char *parser_buffer = nullptr;
194 
200 static QString valid_ruleset_filename(const char *subdir, const char *name,
201  const char *extension, bool optional)
202 {
203  char filename[512];
204  QString dfilename;
205 
206  fc_assert_ret_val(subdir && name && extension, nullptr);
207 
208  fc_snprintf(filename, sizeof(filename), "%s/%s.%s", subdir, name,
209  extension);
210  qCDebug(ruleset_category, "Trying \"%s\".", filename);
211  dfilename = fileinfoname(get_data_dirs(), filename);
212  if (!dfilename.isEmpty()) {
213  return dfilename;
214  }
215 
216  fc_snprintf(filename, sizeof(filename), "default/%s.%s", name, extension);
217  qCDebug(ruleset_category, "Trying \"%s\": default ruleset directory.",
218  filename);
219  dfilename = fileinfoname(get_data_dirs(), filename);
220  if (!dfilename.isEmpty()) {
221  return dfilename;
222  }
223 
224  fc_snprintf(filename, sizeof(filename), "%s_%s.%s", subdir, name,
225  extension);
226  qCDebug(ruleset_category,
227  "Trying \"%s\": alternative ruleset filename syntax.", filename);
228  dfilename = fileinfoname(get_data_dirs(), filename);
229  if (!dfilename.isEmpty()) {
230  return dfilename;
231  } else if (!optional) {
232  qCCritical(ruleset_category,
233  // TRANS: message about an installation error.
234  _("Could not find a readable \"%s.%s\" ruleset file."), name,
235  extension);
236  }
237 
238  return nullptr;
239 }
240 
244 char *get_script_buffer() { return script_buffer; }
245 
249 char *get_parser_buffer() { return parser_buffer; }
250 
255 static struct section_file *openload_ruleset_file(const char *whichset,
256  const char *rsdir)
257 {
258  QString sfilename;
259  QString dfilename =
260  valid_ruleset_filename(rsdir, whichset, RULES_SUFFIX, false);
261  struct section_file *secfile;
262 
263  if (dfilename.isEmpty()) {
264  return nullptr;
265  }
266 
267  /* Need to save a copy of the filename for following message, since
268  section_file_load() may call datafilename() for includes. */
269  sfilename = dfilename;
270  secfile = secfile_load(sfilename, false);
271 
272  if (secfile == nullptr) {
273  qCCritical(ruleset_category, "Could not load ruleset '%s':\n%s",
274  qUtf8Printable(sfilename), secfile_error());
275  }
276 
277  return secfile;
278 }
279 
283 static enum fc_tristate openload_script_file(const char *whichset,
284  const char *rsdir,
285  char **buffer, bool optional)
286 {
287  QString dfilename =
288  valid_ruleset_filename(rsdir, whichset, SCRIPT_SUFFIX, optional);
289 
290  if (dfilename.isEmpty()) {
291  return optional ? TRI_MAYBE : TRI_NO;
292  }
293 
294  if (buffer == nullptr) {
295  if (!script_server_do_file(nullptr, qUtf8Printable(dfilename))) {
296  qCCritical(ruleset_category, "\"%s\": could not load ruleset script.",
297  qUtf8Printable(dfilename));
298 
299  return TRI_NO;
300  }
301  } else {
302  script_server_load_file(qUtf8Printable(dfilename), buffer);
303  }
304 
305  return TRI_YES;
306 }
307 
311 static struct section_file *openload_luadata_file(const char *rsdir)
312 {
313  struct section_file *secfile;
314  QString sfilename;
315  QString dfilename = valid_ruleset_filename(rsdir, "luadata", "txt", true);
316 
317  if (dfilename.isEmpty()) {
318  return nullptr;
319  }
320 
321  /* Need to save a copy of the filename for following message, since
322  section_file_load() may call datafilename() for includes. */
323  sfilename = dfilename;
324  secfile = secfile_load(sfilename, false);
325 
326  if (secfile == nullptr) {
327  qCCritical(ruleset_category, "Could not load luadata '%s':\n%s",
328  qUtf8Printable(sfilename), secfile_error());
329  }
330 
331  return secfile;
332 }
333 
338 struct requirement_vector *lookup_req_list(struct section_file *file,
339  struct rscompat_info *compat,
340  const char *sec, const char *sub,
341  const char *rfor)
342 {
343  const char *type, *name;
344  int j;
345  const char *filename;
346 
347  filename = secfile_name(file);
348 
349  requirement_vector_reserve(&reqs_list, 0);
350 
351  for (j = 0; (type = secfile_lookup_str_default(
352  file, nullptr, "%s.%s%d.type", sec, sub, j));
353  j++) {
354  char buf[MAX_LEN_NAME];
355  const char *range;
356  bool survives, present, quiet;
357  struct entry *pentry;
358  struct requirement req;
359 
360  if (!(pentry =
361  secfile_entry_lookup(file, "%s.%s%d.name", sec, sub, j))) {
362  qCCritical(ruleset_category, "%s", secfile_error());
363 
364  return nullptr;
365  }
366  name = nullptr;
367  switch (entry_type_get(pentry)) {
368  case ENTRY_BOOL: {
369  bool val;
370 
371  if (entry_bool_get(pentry, &val)) {
372  fc_snprintf(buf, sizeof(buf), "%d", val);
373  name = buf;
374  }
375  } break;
376  case ENTRY_INT: {
377  int val;
378 
379  if (entry_int_get(pentry, &val)) {
380  fc_snprintf(buf, sizeof(buf), "%d", val);
381  name = buf;
382  }
383  } break;
384  case ENTRY_STR:
385  (void) entry_str_get(pentry, &name);
386  break;
387  case ENTRY_FLOAT:
389  qCCritical(ruleset_category,
390  "\"%s\": trying to have an floating point entry as a "
391  "requirement name in '%s.%s%d'.",
392  filename, sec, sub, j);
393  break;
394  case ENTRY_FILEREFERENCE:
396  break;
397  case ENTRY_ILLEGAL:
399  break;
400  }
401  if (nullptr == name) {
402  qCCritical(ruleset_category,
403  "\"%s\": error in handling requirement name for '%s.%s%d'.",
404  filename, sec, sub, j);
405  return nullptr;
406  }
407 
408  if (!(range = secfile_lookup_str(file, "%s.%s%d.range", sec, sub, j))) {
409  qCCritical(ruleset_category, "%s", secfile_error());
410 
411  return nullptr;
412  }
413 
414  survives = false;
415  if ((pentry =
416  secfile_entry_lookup(file, "%s.%s%d.survives", sec, sub, j))
417  && !entry_bool_get(pentry, &survives)) {
418  qCCritical(ruleset_category,
419  "\"%s\": invalid boolean value for survives for "
420  "'%s.%s%d'.",
421  filename, sec, sub, j);
422  }
423 
424  present = true;
425  if ((pentry = secfile_entry_lookup(file, "%s.%s%d.present", sec, sub, j))
426  && !entry_bool_get(pentry, &present)) {
427  qCCritical(ruleset_category,
428  "\"%s\": invalid boolean value for present for "
429  "'%s.%s%d'.",
430  filename, sec, sub, j);
431  }
432  quiet = false;
433  if ((pentry = secfile_entry_lookup(file, "%s.%s%d.quiet", sec, sub, j))
434  && !entry_bool_get(pentry, &quiet)) {
435  qCCritical(ruleset_category,
436  "\"%s\": invalid boolean value for quiet for "
437  "'%s.%s%d'.",
438  filename, sec, sub, j);
439  }
440 
441  if (compat->compat_mode) {
442  if (!fc_strcasecmp(type, universals_n_name(VUT_UTFLAG))) {
444  }
445  }
446 
447  if (compat->compat_mode) {
449  }
450 
451  req = req_from_str(type, range, survives, present, quiet, name);
452  if (req.source.kind == universals_n_invalid()) {
453  qCCritical(ruleset_category,
454  "\"%s\" [%s] has invalid or unknown req: "
455  "\"%s\" \"%s\".",
456  filename, sec, type, name);
457 
458  return nullptr;
459  }
460 
461  requirement_vector_append(&reqs_list, req);
462  }
463 
464  if (j > MAX_NUM_REQS) {
465  qCCritical(ruleset_category,
466  "Too many (%d) requirements for %s. Max is %d", j, rfor,
467  MAX_NUM_REQS);
468 
469  return nullptr;
470  }
471 
472  return &reqs_list;
473 }
474 
479  struct combat_bonus_list *list,
480  struct section_file *file, const char *sec,
481  const char *sub)
482 {
483  const char *flag;
484  int j;
485  const char *filename;
486  bool success = true;
487 
488  filename = secfile_name(file);
489 
490  for (j = 0; (flag = secfile_lookup_str_default(
491  file, nullptr, "%s.%s%d.flag", sec, sub, j));
492  j++) {
493  auto *bonus = new combat_bonus;
494  const char *type;
495 
496  bonus->flag = unit_type_flag_id_by_name(
498  if (!unit_type_flag_id_is_valid(bonus->flag)) {
499  qCritical("\"%s\": unknown flag name \"%s\" in '%s.%s'.", filename,
500  flag, sec, sub);
501  delete bonus;
502  bonus = nullptr;
503  success = false;
504  continue;
505  }
506  type = secfile_lookup_str(file, "%s.%s%d.type", sec, sub, j);
507  bonus->type = combat_bonus_type_by_name(type, fc_strcasecmp);
508  if (!combat_bonus_type_is_valid(bonus->type)) {
509  qCritical("\"%s\": unknown bonus type \"%s\" in '%s.%s'.", filename,
510  type, sec, sub);
511  delete bonus;
512  bonus = nullptr;
513  success = false;
514  continue;
515  }
516  if (!secfile_lookup_int(file, &bonus->value, "%s.%s%d.value", sec, sub,
517  j)) {
518  qCritical("\"%s\": failed to get value from '%s.%s%d'.", filename, sec,
519  sub, j);
520  delete bonus;
521  bonus = nullptr;
522  success = false;
523  continue;
524  }
525  bonus->quiet = secfile_lookup_bool_default(file, false, "%s.%s%d.quiet",
526  sec, sub, j);
527  combat_bonus_list_append(list, bonus);
528  }
529 
530  return success;
531 }
532 
541 static bool lookup_tech(struct section_file *file, struct advance **result,
542  const char *prefix, const char *entry,
543  const char *filename, const char *description)
544 {
545  const char *sval;
546 
547  sval = secfile_lookup_str_default(file, nullptr, "%s.%s", prefix, entry);
548  if (!sval || !strcmp(sval, "Never")) {
549  *result = A_NEVER;
550  } else {
551  *result = advance_by_rule_name(sval);
552 
553  if (A_NEVER == *result) {
554  qCCritical(ruleset_category, "\"%s\" %s %s: couldn't match \"%s\".",
555  filename, (description ? description : prefix), entry,
556  sval);
557  return false;
558  }
559  }
560 
561  return true;
562 }
563 
571 static bool lookup_building(struct section_file *file, const char *prefix,
572  const char *entry, struct impr_type **result,
573  const char *filename, const char *description)
574 {
575  const char *sval;
576  bool ok = true;
577 
578  sval = secfile_lookup_str_default(file, nullptr, "%s.%s", prefix, entry);
579  if (!sval || strcmp(sval, "None") == 0) {
580  *result = B_NEVER;
581  } else {
582  *result = improvement_by_rule_name(sval);
583 
584  if (B_NEVER == *result) {
585  qCCritical(ruleset_category, "\"%s\" %s %s: couldn't match \"%s\".",
586  filename, (description ? description : prefix), entry,
587  sval);
588  ok = false;
589  }
590  }
591 
592  return ok;
593 }
594 
602 static bool lookup_unit_list(
603  struct section_file *file, const char *prefix, const char *entry,
604  std::array<unit_type *, MAX_NUM_UNIT_LIST> &output, const char *filename)
605 {
606  const char **slist;
607  size_t nval;
608  int i;
609  bool ok = true;
610 
611  output.fill(nullptr);
612  slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
613  if (nval == 0) {
614  // 'No vector' is considered same as empty vector
615  delete[] slist;
616  return true;
617  }
618  if (nval > MAX_NUM_UNIT_LIST) {
619  qCCritical(ruleset_category,
620  "\"%s\": string vector %s.%s too long (%d, max %d)", filename,
621  prefix, entry, (int) nval, MAX_NUM_UNIT_LIST);
622  ok = false;
623  } else if (nval == 1 && strcmp(slist[0], "") == 0) {
624  delete[] slist;
625  return true;
626  }
627  if (ok) {
628  for (i = 0; i < nval; i++) {
629  const char *sval = slist[i];
630  struct unit_type *punittype = unit_type_by_rule_name(sval);
631 
632  if (!punittype) {
633  qCCritical(ruleset_category,
634  "\"%s\" %s.%s (%d): couldn't match \"%s\".", filename,
635  prefix, entry, i, sval);
636  ok = false;
637  break;
638  }
639  output[i] = punittype;
640  log_debug("\"%s\" %s.%s (%d): %s (%d)", filename, prefix, entry, i,
641  sval, utype_number(punittype));
642  }
643  }
644  delete[] slist;
645  slist = nullptr;
646 
647  return ok;
648 }
649 
657 static bool lookup_tech_list(struct section_file *file, const char *prefix,
658  const char *entry, int *output,
659  const char *filename)
660 {
661  const char **slist;
662  size_t nval;
663  int i;
664  bool ok = true;
665 
666  // pre-fill with A_LAST:
667  for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
668  output[i] = A_LAST;
669  }
670  slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
671  if (slist == nullptr) {
672  return true;
673  } else if (nval == 0) {
674  delete[] slist;
675  slist = nullptr;
676  return true;
677  } else if (nval > MAX_NUM_TECH_LIST) {
678  qCCritical(ruleset_category,
679  "\"%s\": string vector %s.%s too long (%d, max %d)", filename,
680  prefix, entry, (int) nval, MAX_NUM_TECH_LIST);
681  ok = false;
682  }
683 
684  if (ok) {
685  if (nval == 1 && strcmp(slist[0], "") == 0) {
686  delete[] slist;
687  slist = nullptr;
688  return true;
689  }
690  for (i = 0; i < nval && ok; i++) {
691  const char *sval = slist[i];
692  struct advance *padvance = advance_by_rule_name(sval);
693 
694  if (nullptr == padvance) {
695  qCCritical(ruleset_category,
696  "\"%s\" %s.%s (%d): couldn't match \"%s\".", filename,
697  prefix, entry, i, sval);
698  ok = false;
699  }
700  if (!valid_advance(padvance)) {
701  qCCritical(ruleset_category, "\"%s\" %s.%s (%d): \"%s\" is removed.",
702  filename, prefix, entry, i, sval);
703  ok = false;
704  }
705 
706  if (ok) {
707  output[i] = advance_number(padvance);
708  log_debug("\"%s\" %s.%s (%d): %s (%d)", filename, prefix, entry, i,
709  sval, advance_number(padvance));
710  }
711  }
712  }
713  delete[] slist;
714  slist = nullptr;
715 
716  return ok;
717 }
718 
726 static bool lookup_building_list(struct section_file *file,
727  const char *prefix, const char *entry,
728  int *output, const char *filename)
729 {
730  const char **slist;
731  size_t nval;
732  int i;
733  bool ok = true;
734 
735  // pre-fill with B_LAST:
736  for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
737  output[i] = B_LAST;
738  }
739  slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
740  if (nval > MAX_NUM_BUILDING_LIST) {
741  qCCritical(ruleset_category,
742  "\"%s\": string vector %s.%s too long (%d, max %d)", filename,
743  prefix, entry, (int) nval, MAX_NUM_BUILDING_LIST);
744  ok = false;
745  } else if (nval == 0 || (nval == 1 && strcmp(slist[0], "") == 0)) {
746  if (slist != nullptr) {
747  delete[] slist;
748  slist = nullptr;
749  }
750  return true;
751  }
752  if (ok) {
753  for (i = 0; i < nval; i++) {
754  const char *sval = slist[i];
755  struct impr_type *pimprove = improvement_by_rule_name(sval);
756 
757  if (nullptr == pimprove) {
758  qCCritical(ruleset_category,
759  "\"%s\" %s.%s (%d): couldn't match \"%s\".", filename,
760  prefix, entry, i, sval);
761  ok = false;
762  break;
763  }
764  output[i] = improvement_number(pimprove);
765  log_debug("%s.%s,%d %s %d", prefix, entry, i, sval, output[i]);
766  }
767  }
768  delete[] slist;
769  slist = nullptr;
770 
771  return ok;
772 }
773 
780 static bool lookup_unit_type(struct section_file *file, const char *prefix,
781  const char *entry,
782  const struct unit_type **result,
783  const char *filename, const char *description)
784 {
785  const char *sval;
786 
787  sval = secfile_lookup_str_default(file, "None", "%s.%s", prefix, entry);
788 
789  if (strcmp(sval, "None") == 0) {
790  *result = nullptr;
791  } else {
792  *result = unit_type_by_rule_name(sval);
793  if (*result == nullptr) {
794  qCCritical(ruleset_category, "\"%s\" %s %s: couldn't match \"%s\".",
795  filename, (description ? description : prefix), entry,
796  sval);
797 
798  return false;
799  }
800  }
801 
802  return true;
803 }
804 
809 static struct government *lookup_government(struct section_file *file,
810  const char *entry,
811  const char *filename,
812  struct government *fallback)
813 {
814  const char *sval;
815  struct government *gov;
816 
817  sval = secfile_lookup_str_default(file, nullptr, "%s", entry);
818  if (!sval) {
819  gov = fallback;
820  } else {
821  gov = government_by_rule_name(sval);
822  }
823  if (!gov) {
824  qCCritical(ruleset_category, "\"%s\" %s: couldn't match \"%s\".",
825  filename, entry, sval);
826  }
827  return gov;
828 }
829 
833 static char *lookup_string(struct section_file *file, const char *prefix,
834  const char *suffix)
835 {
836  const char *sval = secfile_lookup_str(file, "%s.%s", prefix, suffix);
837 
838  if (nullptr != sval) {
839  char copy[strlen(sval) + 1];
840 
841  qstrcpy(copy, sval);
843  if (strlen(copy) > 0) {
844  return fc_strdup(copy);
845  }
846  }
847  return nullptr;
848 }
849 
854 static void strvec_store(QVector<QString> *psv, const char *const *vec,
855  size_t size)
856 {
857  if (size == static_cast<size_t>(-1)) {
858  psv->clear();
859  for (; *vec; vec++) {
860  psv->append(*vec);
861  }
862  } else {
863  size_t i;
864  psv->resize(size);
865  for (i = 0; i < size; i++, vec++) {
866  psv->replace(i, *vec);
867  }
868  }
869 }
870 
875  const char *prefix,
876  const char *suffix)
877 {
878  size_t dim;
879  const char **vec =
880  secfile_lookup_str_vec(file, &dim, "%s.%s", prefix, suffix);
881 
882  if (nullptr != vec) {
884  strvec_store(dest, vec, dim);
885 
886  delete[] vec;
887  vec = nullptr;
888  return dest;
889  }
890  return nullptr;
891 }
892 
896 static struct extra_type *
897 lookup_resource(const char *filename, const char *name, const char *jsection)
898 {
899  struct extra_type *pres;
900 
902 
903  if (pres == nullptr) {
904  qCCritical(ruleset_category, "\"%s\" [%s] has unknown \"%s\".", filename,
905  jsection, name);
906  }
907 
908  return pres;
909 }
910 
915 static bool lookup_terrain(struct section_file *file, const char *entry,
916  const char *filename, struct terrain *pthis,
917  struct terrain **result)
918 {
919  const int j = terrain_index(pthis);
920  const char *jsection = terrain_sections[j];
921  const char *name = secfile_lookup_str(file, "%s.%s", jsection, entry);
922  struct terrain *pterr;
923 
924  if (nullptr == name || *name == '\0' || (0 == strcmp(name, "none"))
925  || (0 == strcmp(name, "no"))) {
926  *result = T_NONE;
927 
928  return true;
929  }
930  if (0 == strcmp(name, "yes")) {
931  *result = pthis;
932 
933  return true;
934  }
935 
936  pterr = terrain_by_rule_name(name);
937  *result = pterr;
938 
939  if (pterr == nullptr) {
940  qCCritical(ruleset_category, "\"%s\" [%s] has unknown \"%s\".",
941  secfile_name(file), jsection, name);
942  return false;
943  }
944 
945  return true;
946 }
947 
955 static bool lookup_time(const struct section_file *secfile, int *turns,
956  const char *sec_name, const char *property_name,
957  const char *filename, const char *item_name,
958  bool *ok)
959 {
960  // Assumes that PACKET_UNIT_INFO.activity_count in packets.def is UINT16
961  const int max_turns = 65535 / ACTIVITY_FACTOR;
962 
963  if (!secfile_lookup_int(secfile, turns, "%s.%s", sec_name,
964  property_name)) {
965  return false;
966  }
967 
968  if (*turns > max_turns) {
969  qCCritical(ruleset_category,
970  "\"%s\": \"%s\": \"%s\" value %d too large (max %d)",
971  filename, item_name ? item_name : sec_name, property_name,
972  *turns, max_turns);
973  *ok = false;
974  }
975 
976  return true; // we found _something
977 }
978 
982 static bool ruleset_load_names(struct name_translation *pname,
983  const char *domain, struct section_file *file,
984  const char *sec_name)
985 {
986  const char *name = secfile_lookup_str(file, "%s.name", sec_name);
987  const char *rule_name = secfile_lookup_str(file, "%s.rule_name", sec_name);
988 
989  if (!name) {
990  qCCritical(ruleset_category, "\"%s\" [%s]: no \"name\" specified.",
991  secfile_name(file), sec_name);
992  return false;
993  }
994 
995  names_set(pname, domain, name, rule_name);
996 
997  return true;
998 }
999 
1003 static void ruleset_load_traits(struct trait_limits *out,
1004  struct section_file *file,
1005  const char *secname,
1006  const char *field_prefix)
1007 {
1008  enum trait tr;
1009 
1010  /* FIXME: Use specenum trait names without duplicating them here.
1011  * Just needs to take care of case. */
1012  const char *trait_names[] = {"expansionist", "trader", "aggressive",
1013  "builder", nullptr};
1014 
1015  for (tr = trait_begin(); tr != trait_end() && trait_names[tr] != nullptr;
1016  tr = trait_next(tr)) {
1017  out[tr].min = secfile_lookup_int_default(
1018  file, -1, "%s.%s%s_min", secname, field_prefix, trait_names[tr]);
1019  out[tr].max = secfile_lookup_int_default(
1020  file, -1, "%s.%s%s_max", secname, field_prefix, trait_names[tr]);
1022  file, -1, "%s.%s%s_default", secname, field_prefix, trait_names[tr]);
1023  }
1024 
1025  fc_assert(tr == trait_end()); // number of trait_names correct
1026 }
1027 
1032 static bool load_game_names(struct section_file *file,
1033  struct rscompat_info *compat)
1034 {
1035  struct section_list *sec;
1036  int nval;
1037  const char *filename = secfile_name(file);
1038  bool ok = true;
1039 
1040  // section: datafile
1041  compat->ver_game = rscompat_check_capabilities(file, filename, compat);
1042  if (compat->ver_game <= 0) {
1043  return false;
1044  }
1045 
1046  (void) secfile_entry_by_path(file, "datafile.description"); // unused
1047  (void) secfile_entry_by_path(file, "datafile.ruledit"); // unused
1048 
1050  nval = (nullptr != sec ? section_list_size(sec) : 0);
1051  if (nval > MAX_ACHIEVEMENT_TYPES) {
1052  int num = nval; // No "size_t" to printf
1053 
1054  qCCritical(ruleset_category,
1055  "\"%s\": Too many achievement types (%d, max %d)", filename,
1056  num, MAX_ACHIEVEMENT_TYPES);
1057  ok = false;
1058  } else {
1059  game.control.num_achievement_types = nval;
1060  }
1061 
1062  if (ok) {
1063  achievements_iterate(pach)
1064  {
1065  const char *sec_name =
1066  section_name(section_list_get(sec, achievement_index(pach)));
1067 
1068  if (!ruleset_load_names(&pach->name, nullptr, file, sec_name)) {
1069  qCCritical(ruleset_category, "\"%s\": Cannot load achievement names",
1070  filename);
1071  ok = false;
1072  break;
1073  }
1074  }
1076  }
1077 
1078  section_list_destroy(sec);
1079 
1080  if (compat->ver_game >= 10) {
1081  if (ok) {
1083 
1084  nval = (nullptr != sec ? section_list_size(sec) : 0);
1085  if (nval > MAX_GOODS_TYPES) {
1086  int num = nval; // No "size_t" to printf
1087  qCCritical(ruleset_category,
1088  "\"%s\": Too many goods types (%d, max %d)", filename,
1089  num, MAX_GOODS_TYPES);
1090  ok = false;
1091  } else if (nval < 1) {
1092  qCCritical(ruleset_category,
1093  "\"%s\": At least one goods type needed", filename);
1094  ok = false;
1095  } else {
1096  game.control.num_goods_types = nval;
1097  }
1098 
1099  if (ok) {
1100  goods_type_iterate(pgood)
1101  {
1102  const char *sec_name =
1103  section_name(section_list_get(sec, goods_index(pgood)));
1104 
1105  if (!ruleset_load_names(&pgood->name, nullptr, file, sec_name)) {
1106  qCCritical(ruleset_category, "\"%s\": Cannot load goods names",
1107  filename);
1108  ok = false;
1109  break;
1110  }
1111  }
1113  }
1114  section_list_destroy(sec);
1115  }
1116  }
1117 
1118  return ok;
1119 }
1120 
1125 static bool load_tech_names(struct section_file *file,
1126  struct rscompat_info *compat)
1127 {
1128  struct section_list *sec = nullptr;
1129  // Number of techs in the ruleset (means without A_NONE).
1130  int num_techs = 0;
1131  int i;
1132  const char *filename = secfile_name(file);
1133  bool ok = true;
1134  const char *flag;
1135 
1136  compat->ver_techs = rscompat_check_capabilities(file, filename, compat);
1137  if (compat->ver_techs <= 0) {
1138  return false;
1139  }
1140 
1141  (void) secfile_entry_by_path(file, "datafile.description"); // unused
1142  (void) secfile_entry_by_path(file, "datafile.ruledit"); // unused
1143 
1144  // User tech flag names
1145  for (i = 0; (flag = secfile_lookup_str_default(file, nullptr,
1146  "control.flags%d.name", i));
1147  i++) {
1148  const char *helptxt = secfile_lookup_str_default(
1149  file, nullptr, "control.flags%d.helptxt", i);
1150  if (tech_flag_id_by_name(flag, fc_strcasecmp)
1151  != tech_flag_id_invalid()) {
1152  qCCritical(ruleset_category, "\"%s\": Duplicate tech flag name '%s'",
1153  filename, flag);
1154  ok = false;
1155  break;
1156  }
1157  if (i > MAX_NUM_USER_TECH_FLAGS) {
1158  qCCritical(ruleset_category, "\"%s\": Too many user tech flags!",
1159  filename);
1160  ok = false;
1161  break;
1162  }
1163 
1164  set_user_tech_flag_name(tech_flag_id(TECH_USER_1 + i), flag, helptxt);
1165  }
1166 
1167  if (ok) {
1168  size_t nval;
1169 
1170  for (; i < MAX_NUM_USER_TECH_FLAGS; i++) {
1171  set_user_tech_flag_name(tech_flag_id(TECH_USER_1 + i), nullptr,
1172  nullptr);
1173  }
1174 
1175  // Tech classes
1177 
1178  nval = (nullptr != sec ? section_list_size(sec) : 0);
1179  if (nval > MAX_NUM_TECH_CLASSES) {
1180  int num = nval; // No "size_t" to printf
1181 
1182  qCCritical(ruleset_category,
1183  "\"%s\": Too many tech classes (%d, max %d)", filename, num,
1185  ok = false;
1186  } else {
1187  game.control.num_tech_classes = nval;
1188  }
1189 
1190  if (ok) {
1191  tech_class_iterate(ptclass)
1192  {
1193  const char *sec_name =
1194  section_name(section_list_get(sec, tech_class_index(ptclass)));
1195 
1196  if (!ruleset_load_names(&ptclass->name, nullptr, file, sec_name)) {
1197  qCCritical(ruleset_category,
1198  "\"%s\": Cannot load tech class names", filename);
1199  ok = false;
1200  break;
1201  }
1202  }
1204  }
1205  }
1206 
1207  if (ok) {
1208  // The techs:
1209  if (sec) {
1210  section_list_destroy(sec);
1211  }
1213  if (nullptr == sec || 0 == (num_techs = section_list_size(sec))) {
1214  qCCritical(ruleset_category, "\"%s\": No Advances?!?", filename);
1215  ok = false;
1216  } else {
1217  qCDebug(ruleset_category, "%d advances (including possibly unused)",
1218  num_techs);
1219  if (num_techs + A_FIRST > A_LAST) {
1220  qCCritical(ruleset_category,
1221  "\"%s\": Too many advances (%d, max %d)", filename,
1222  num_techs, A_LAST - A_FIRST);
1223  ok = false;
1224  }
1225  }
1226  }
1227 
1228  if (ok) {
1229  game.control.num_tech_types = num_techs + A_FIRST; // includes A_NONE
1230 
1231  i = 0;
1233  {
1234  if (!ruleset_load_names(&a->name, nullptr, file,
1235  section_name(section_list_get(sec, i)))) {
1236  ok = false;
1237  break;
1238  }
1239  i++;
1240  }
1242  }
1243  section_list_destroy(sec);
1244 
1245  return ok;
1246 }
1247 
1251 static bool load_ruleset_techs(struct section_file *file,
1252  struct rscompat_info *compat)
1253 {
1254  struct section_list *sec;
1255  const char **slist;
1256  int i;
1257  size_t nval;
1258  struct advance *a_none = advance_by_number(A_NONE);
1259  const char *filename = secfile_name(file);
1260  bool ok = true;
1261 
1263 
1264  i = 0;
1265  tech_class_iterate(ptclass)
1266  {
1267  const char *sec_name = section_name(section_list_get(sec, i));
1268 
1269  ptclass->cost_pct =
1270  secfile_lookup_int_default(file, 100, "%s.%s", sec_name, "cost_pct");
1271 
1272  i++;
1273  }
1275  if (sec) {
1276  section_list_destroy(sec);
1277  }
1279 
1280  i = 0;
1282  {
1283  const char *sec_name = section_name(section_list_get(sec, i));
1284  const char *sval;
1285  int j, ival;
1286  struct requirement_vector *research_reqs;
1287 
1288  if (!lookup_tech(file, &a->require[AR_ONE], sec_name, "req1", filename,
1289  rule_name_get(&a->name))
1290  || !lookup_tech(file, &a->require[AR_TWO], sec_name, "req2",
1291  filename, rule_name_get(&a->name))
1292  || !lookup_tech(file, &a->require[AR_ROOT], sec_name, "root_req",
1293  filename, rule_name_get(&a->name))) {
1294  ok = false;
1295  break;
1296  }
1297 
1298  if ((A_NEVER == a->require[AR_ONE] && A_NEVER != a->require[AR_TWO])
1299  || (A_NEVER != a->require[AR_ONE]
1300  && A_NEVER == a->require[AR_TWO])) {
1301  qCCritical(ruleset_category,
1302  "\"%s\" [%s] \"%s\": \"Never\" with non-\"Never\".",
1303  filename, sec_name, rule_name_get(&a->name));
1304  ok = false;
1305  break;
1306  }
1307  if (a_none == a->require[AR_ONE] && a_none != a->require[AR_TWO]) {
1308  qCCritical(ruleset_category,
1309  "\"%s\" [%s] \"%s\": should have \"None\" second.",
1310  filename, sec_name, rule_name_get(&a->name));
1311  ok = false;
1312  break;
1313  }
1314 
1315  if (game.control.num_tech_classes == 0) {
1316  a->tclass = nullptr;
1317  } else {
1318  const char *classname;
1319 
1320  classname = lookup_string(file, sec_name, "class");
1321  if (classname != nullptr) {
1322  classname = Q_(classname);
1323  a->tclass = tech_class_by_rule_name(classname);
1324  if (a->tclass == nullptr) {
1325  qCCritical(ruleset_category,
1326  "\"%s\" [%s] \"%s\": Uknown tech class \"%s\".",
1327  filename, sec_name, rule_name_get(&a->name), classname);
1328  ok = false;
1329  break;
1330  }
1331  } else {
1332  a->tclass = nullptr; // Default
1333  }
1334  }
1335 
1336  research_reqs = lookup_req_list(file, compat, sec_name, "research_reqs",
1337  rule_name_get(&a->name));
1338  if (research_reqs == nullptr) {
1339  ok = false;
1340  break;
1341  }
1342 
1343  requirement_vector_copy(&a->research_reqs, research_reqs);
1344 
1345  BV_CLR_ALL(a->flags);
1346 
1347  slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name);
1348  for (j = 0; j < nval; j++) {
1349  sval = slist[j];
1350  if (strcmp(sval, "") == 0) {
1351  continue;
1352  }
1353  ival = tech_flag_id_by_name(sval, fc_strcasecmp);
1354  if (!tech_flag_id_is_valid(tech_flag_id(ival))) {
1355  qCCritical(ruleset_category,
1356  "\"%s\" [%s] \"%s\": bad flag name \"%s\".", filename,
1357  sec_name, rule_name_get(&a->name), sval);
1358  ok = false;
1359  break;
1360  } else {
1361  BV_SET(a->flags, ival);
1362  }
1363  }
1364  delete[] slist;
1365  slist = nullptr;
1366 
1367  if (!ok) {
1368  break;
1369  }
1370 
1371  sz_strlcpy(a->graphic_str, secfile_lookup_str_default(
1372  file, "-", "%s.graphic", sec_name));
1373  sz_strlcpy(a->graphic_alt, secfile_lookup_str_default(
1374  file, "-", "%s.graphic_alt", sec_name));
1375 
1376  a->helptext = lookup_strvec(file, sec_name, "helptext");
1377  a->bonus_message = lookup_string(file, sec_name, "bonus_message");
1378  a->cost =
1379  secfile_lookup_int_default(file, -1, "%s.%s", sec_name, "cost");
1380  a->num_reqs = 0;
1381 
1382  i++;
1383  }
1385 
1386  /* Propagate a root tech up into the tech tree. If a technology
1387  * X has Y has a root tech, then any technology requiring X (in the
1388  * normal way or as a root tech) also has Y as a root tech.
1389  * Later techs may gain a whole set of root techs in this way. The one
1390  * we store in AR_ROOT is a more or less arbitrary one of these,
1391  * also signalling that the set is non-empty; after this, you'll still
1392  * have to walk the tech tree to find them all. */
1393 restart:
1394 
1395  if (ok) {
1397  {
1398  if (valid_advance(a) && A_NEVER != a->require[AR_ROOT]) {
1399  bool out_of_order = false;
1400 
1401  /* Now find any tech depending on this technology and update its
1402  * root_req. */
1404  {
1405  if (valid_advance(b) && A_NEVER == b->require[AR_ROOT]
1406  && (a == b->require[AR_ONE] || a == b->require[AR_TWO])) {
1407  b->require[AR_ROOT] = a->require[AR_ROOT];
1408  b->inherited_root_req = true;
1409  if (b < a) {
1410  out_of_order = true;
1411  }
1412  }
1413  }
1415 
1416  if (out_of_order) {
1417  /* HACK: If we just changed the root_tech of a lower-numbered
1418  * technology, we need to go back so that we can propagate the
1419  * root_tech up to that technology's parents... */
1420  goto restart;
1421  }
1422  }
1423  }
1425 
1426  // Now rename A_NEVER to A_NONE for consistency
1428  {
1429  if (A_NEVER == a->require[AR_ROOT]) {
1430  a->require[AR_ROOT] = a_none;
1431  }
1432  }
1434 
1435  /* Some more consistency checking:
1436  Non-removed techs depending on removed techs is too
1437  broken to fix by default, so die.
1438  */
1440  {
1441  if (valid_advance(a)) {
1442  /* We check for recursive tech loops later,
1443  * in build_required_techs_helper. */
1444  if (!valid_advance(a->require[AR_ONE])) {
1445  qCCritical(ruleset_category,
1446  "\"%s\" tech \"%s\": req1 leads to removed tech.",
1447  filename, advance_rule_name(a));
1448  ok = false;
1449  break;
1450  }
1451  if (!valid_advance(a->require[AR_TWO])) {
1452  qCCritical(ruleset_category,
1453  "\"%s\" tech \"%s\": req2 leads to removed tech.",
1454  filename, advance_rule_name(a));
1455  ok = false;
1456  break;
1457  }
1458  }
1459  }
1461  }
1462 
1463  section_list_destroy(sec);
1464  if (ok) {
1465  secfile_check_unused(file);
1466  }
1467 
1468  return ok;
1469 }
1470 
1475 static bool load_unit_names(struct section_file *file,
1476  struct rscompat_info *compat)
1477 {
1478  struct section_list *sec = nullptr;
1479  int nval = 0;
1480  int i;
1481  const char *filename = secfile_name(file);
1482  const char *flag;
1483  bool ok = true;
1484 
1485  compat->ver_units = rscompat_check_capabilities(file, filename, compat);
1486  if (compat->ver_units <= 0) {
1487  return false;
1488  }
1489 
1490  (void) secfile_entry_by_path(file, "datafile.description"); // unused
1491  (void) secfile_entry_by_path(file, "datafile.ruledit"); // unused
1492 
1493  // User unit flag names
1494  for (i = 0; (flag = secfile_lookup_str_default(file, nullptr,
1495  "control.flags%d.name", i));
1496  i++) {
1497  const char *helptxt = secfile_lookup_str_default(
1498  file, nullptr, "control.flags%d.helptxt", i);
1499 
1500  if (unit_type_flag_id_by_name(rscompat_utype_flag_name_3_1(compat, flag),
1501  fc_strcasecmp)
1502  != unit_type_flag_id_invalid()) {
1503  qCCritical(ruleset_category, "\"%s\": Duplicate unit flag name '%s'",
1504  filename, flag);
1505  ok = false;
1506  break;
1507  }
1508  if (i > MAX_NUM_USER_UNIT_FLAGS) {
1509  qCCritical(ruleset_category, "\"%s\": Too many user unit type flags!",
1510  filename);
1511  ok = false;
1512  break;
1513  }
1514 
1515  set_user_unit_type_flag_name(unit_type_flag_id(UTYF_USER_FLAG_1 + i),
1516  flag, helptxt);
1517  }
1518 
1519  if (ok) {
1520  // Blank the remaining unit type user flags.
1521  for (; i < MAX_NUM_USER_UNIT_FLAGS; i++) {
1522  set_user_unit_type_flag_name(unit_type_flag_id(UTYF_USER_FLAG_1 + i),
1523  nullptr, nullptr);
1524  }
1525  }
1526 
1527  if (ok) {
1528  // User unit class flag names
1529  for (i = 0; (flag = secfile_lookup_str_default(
1530  file, nullptr, "control.class_flags%d.name", i));
1531  i++) {
1532  const char *helptxt = secfile_lookup_str_default(
1533  file, nullptr, "control.class_flags%d.helptxt", i);
1534 
1535  if (unit_class_flag_id_by_name(flag, fc_strcasecmp)
1536  != unit_class_flag_id_invalid()) {
1537  qCCritical(ruleset_category,
1538  "\"%s\": Duplicate unit class flag name "
1539  "'%s'",
1540  filename, flag);
1541  ok = false;
1542  break;
1543  }
1544  if (i > MAX_NUM_USER_UCLASS_FLAGS) {
1545  qCCritical(ruleset_category,
1546  "\"%s\": Too many user unit class flags!", filename);
1547  ok = false;
1548  break;
1549  }
1550 
1551  set_user_unit_class_flag_name(unit_class_flag_id(UCF_USER_FLAG_1 + i),
1552  flag, helptxt);
1553  }
1554  }
1555 
1556  if (ok) {
1557  // Blank the remaining unit class user flags.
1558  for (; i < MAX_NUM_USER_UCLASS_FLAGS; i++) {
1559  set_user_unit_class_flag_name(unit_class_flag_id(UCF_USER_FLAG_1 + i),
1560  nullptr, nullptr);
1561  }
1562  }
1563 
1564  if (ok) {
1565  // Sentry range
1567  file, 3, 1, 15, "control.sentry_range");
1568  }
1569 
1570  if (ok) {
1571  // Unit classes
1573  if (nullptr == sec || 0 == (nval = section_list_size(sec))) {
1574  qCCritical(ruleset_category, "\"%s\": No unit classes?!?", filename);
1575  ok = false;
1576  } else {
1577  qCDebug(ruleset_category, "%d unit classes", nval);
1578  if (nval > UCL_LAST) {
1579  qCCritical(ruleset_category,
1580  "\"%s\": Too many unit classes (%d, max %d)", filename,
1581  nval, UCL_LAST);
1582  ok = false;
1583  }
1584  }
1585  }
1586 
1587  if (ok) {
1588  game.control.num_unit_classes = nval;
1589 
1590  unit_class_iterate(punitclass)
1591  {
1592  const int pci = uclass_index(punitclass);
1593 
1594  if (!ruleset_load_names(&punitclass->name, nullptr, file,
1595  section_name(section_list_get(sec, pci)))) {
1596  ok = false;
1597  break;
1598  }
1599  }
1601  }
1602  section_list_destroy(sec);
1603  sec = nullptr;
1604 
1605  // The names:
1606  if (ok) {
1608  if (nullptr == sec || 0 == (nval = section_list_size(sec))) {
1609  qCCritical(ruleset_category, "\"%s\": No unit types?!?", filename);
1610  ok = false;
1611  } else {
1612  qCDebug(ruleset_category, "%d unit types (including possibly unused)",
1613  nval);
1614  if (nval > U_LAST) {
1615  qCCritical(ruleset_category,
1616  "\"%s\": Too many unit types (%d, max %d)", filename,
1617  nval, U_LAST);
1618  ok = false;
1619  }
1620  }
1621  }
1622 
1623  if (ok) {
1624  game.control.num_unit_types = nval;
1625 
1626  unit_type_iterate(punittype)
1627  {
1628  const int utypei = utype_index(punittype);
1629  if (!ruleset_load_names(&punittype->name, nullptr, file,
1630  section_name(section_list_get(sec, utypei)))) {
1631  ok = false;
1632  break;
1633  }
1634  }
1636  }
1637  section_list_destroy(sec);
1638 
1639  return ok;
1640 }
1641 
1645 static bool load_ruleset_veteran(struct section_file *file, const char *path,
1646  struct veteran_system **vsystem, char *err,
1647  size_t err_len, bool compat)
1648 {
1649  const char **vlist_name;
1650  int *vlist_power, *vlist_raise, *vlist_wraise, *vlist_move;
1651  size_t count_name, count_power, count_raise, count_wraise, count_move;
1652  int i;
1653  bool ret = true;
1654 
1655  // The pointer should be uninitialised.
1656  if (*vsystem != nullptr) {
1657  fc_snprintf(err, err_len, "Veteran system is defined?!");
1658  return false;
1659  }
1660 
1661  // Load data.
1662  vlist_name =
1663  secfile_lookup_str_vec(file, &count_name, "%s.veteran_names", path);
1664  vlist_power = secfile_lookup_int_vec(file, &count_power,
1665  "%s.veteran_power_fact", path);
1666  vlist_raise = secfile_lookup_int_vec(file, &count_raise,
1667  "%s.veteran_base_raise_chance", path);
1668  if (vlist_raise == nullptr && compat) {
1669  vlist_raise = secfile_lookup_int_vec(file, &count_raise,
1670  "%s.veteran_raise_chance", path);
1671  }
1672  vlist_wraise = secfile_lookup_int_vec(
1673  file, &count_wraise, "%s.veteran_work_raise_chance", path);
1674  vlist_move = secfile_lookup_int_vec(file, &count_move,
1675  "%s.veteran_move_bonus", path);
1676 
1677  if (count_name > MAX_VET_LEVELS) {
1678  ret = false;
1679  fc_snprintf(err, err_len,
1680  "\"%s\": Too many veteran levels (section "
1681  "'%s': %lu, max %d)",
1682  secfile_name(file), path,
1683  static_cast<long unsigned>(count_name), MAX_VET_LEVELS);
1684  } else if (count_name != count_power || count_name != count_raise
1685  || count_name != count_wraise || count_name != count_move) {
1686  ret = false;
1687  fc_snprintf(err, err_len,
1688  "\"%s\": Different lengths for the veteran "
1689  "settings in section '%s'",
1690  secfile_name(file), path);
1691  } else if (count_name == 0) {
1692  // Nothing defined.
1693  *vsystem = nullptr;
1694  } else {
1695  // Generate the veteran system.
1696  *vsystem = veteran_system_new(static_cast<int>(count_name));
1697 
1698 #define rs_sanity_veteran(_path, _entry, _i, _condition, _action) \
1699  if (_condition) { \
1700  qCritical("Invalid veteran definition '%s.%s[%d]'!", _path, _entry, \
1701  _i); \
1702  log_debug("Failed check: '%s'. Update value: '%s'.", #_condition, \
1703  #_action); \
1704  _action; \
1705  }
1706  for (i = 0; i < count_name; i++) {
1707  // Some sanity checks.
1708  rs_sanity_veteran(path, "veteran_power_fact", i, (vlist_power[i] < 0),
1709  vlist_power[i] = 0);
1710  rs_sanity_veteran(path, "veteran_base_raise_chance", i,
1711  (vlist_raise[i] < 0), vlist_raise[i] = 0);
1712  rs_sanity_veteran(path, "veteran_work_raise_chance", i,
1713  (vlist_wraise[i] < 0), vlist_wraise[i] = 0);
1714  rs_sanity_veteran(path, "veteran_move_bonus", i, (vlist_move[i] < 0),
1715  vlist_move[i] = 0);
1716  if (i == 0) {
1717  /* First element.*/
1718  rs_sanity_veteran(path, "veteran_power_fact", i,
1719  (vlist_power[i] != 100), vlist_power[i] = 100);
1720  } else if (i == count_name - 1) {
1721  // Last element.
1722  rs_sanity_veteran(path, "veteran_power_fact", i,
1723  (vlist_power[i] < vlist_power[i - 1]),
1724  vlist_power[i] = vlist_power[i - 1]);
1725  rs_sanity_veteran(path, "veteran_base_raise_chance", i,
1726  (vlist_raise[i] != 0), vlist_raise[i] = 0);
1727  rs_sanity_veteran(path, "veteran_work_raise_chance", i,
1728  (vlist_wraise[i] != 0), vlist_wraise[i] = 0);
1729  } else {
1730  // All elements inbetween.
1731  rs_sanity_veteran(path, "veteran_power_fact", i,
1732  (vlist_power[i] < vlist_power[i - 1]),
1733  vlist_power[i] = vlist_power[i - 1]);
1734  rs_sanity_veteran(path, "veteran_base_raise_chance", i,
1735  (vlist_raise[i] > 100), vlist_raise[i] = 100);
1736  rs_sanity_veteran(path, "veteran_work_raise_chance", i,
1737  (vlist_wraise[i] > 100), vlist_wraise[i] = 100);
1738  }
1739 
1740  veteran_system_definition(*vsystem, i, vlist_name[i], vlist_power[i],
1741  vlist_move[i], vlist_raise[i],
1742  vlist_wraise[i]);
1743  }
1744 #undef rs_sanity_veteran
1745  }
1746 
1747  delete[] vlist_name;
1748  delete[] vlist_power;
1749  delete[] vlist_raise;
1750  delete[] vlist_wraise;
1751  delete[] vlist_move;
1752 
1753  vlist_name = nullptr;
1754  vlist_power = nullptr;
1755  vlist_raise = nullptr;
1756  vlist_wraise = nullptr;
1757  vlist_move = nullptr;
1758 
1759  return ret;
1760 }
1761 
1765 static bool load_ruleset_units(struct section_file *file,
1766  struct rscompat_info *compat)
1767 {
1768  int j, ival;
1769  size_t nval;
1770  struct section_list *sec, *csec;
1771  const char *sval, **slist;
1772  const char *filename = secfile_name(file);
1773  char msg[MAX_LEN_MSG];
1774  bool ok = true;
1775 
1776  if (!load_ruleset_veteran(file, "veteran_system", &game.veteran, msg,
1777  sizeof(msg), compat->compat_mode)
1778  || game.veteran == nullptr) {
1779  qCCritical(ruleset_category,
1780  "Error loading the default veteran system: %s", msg);
1781  ok = false;
1782  }
1783 
1785  nval = (nullptr != sec ? section_list_size(sec) : 0);
1786 
1788  nval = (nullptr != csec ? section_list_size(csec) : 0);
1789 
1790  if (ok) {
1791  unit_class_iterate(uc)
1792  {
1793  int i = uclass_index(uc);
1794  const char *hut_str;
1795  const char *sec_name = section_name(section_list_get(csec, i));
1796 
1797  if (secfile_lookup_int(file, &uc->min_speed, "%s.min_speed",
1798  sec_name)) {
1799  uc->min_speed *= SINGLE_MOVE;
1800  } else {
1801  qCCritical(ruleset_category, "%s", secfile_error());
1802  ok = false;
1803  break;
1804  }
1805  if (!secfile_lookup_int(file, &uc->hp_loss_pct, "%s.hp_loss_pct",
1806  sec_name)) {
1807  qCCritical(ruleset_category, "%s", secfile_error());
1808  ok = false;
1809  break;
1810  }
1811 
1812  uc->non_native_def_pct = secfile_lookup_int_default(
1813  file, 100, "%s.non_native_def_pct", sec_name);
1814 
1815  hut_str = secfile_lookup_str_default(file, "Normal", "%s.hut_behavior",
1816  sec_name);
1817  if (fc_strcasecmp(hut_str, "Normal") == 0) {
1818  uc->hut_behavior = HUT_NORMAL;
1819  } else if (fc_strcasecmp(hut_str, "Nothing") == 0) {
1820  uc->hut_behavior = HUT_NOTHING;
1821  } else if (fc_strcasecmp(hut_str, "Frighten") == 0) {
1822  uc->hut_behavior = HUT_FRIGHTEN;
1823  } else {
1824  qCCritical(ruleset_category,
1825  "\"%s\" unit_class \"%s\":"
1826  " Illegal hut behavior \"%s\".",
1827  filename, uclass_rule_name(uc), hut_str);
1828  ok = false;
1829  break;
1830  }
1831 
1832  BV_CLR_ALL(uc->flags);
1833  slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name);
1834  for (j = 0; j < nval; j++) {
1835  sval = slist[j];
1836  if (strcmp(sval, "") == 0) {
1837  continue;
1838  }
1839  ival = unit_class_flag_id_by_name(sval, fc_strcasecmp);
1840  if (!unit_class_flag_id_is_valid(unit_class_flag_id(ival))) {
1841  ok = false;
1842  ival = unit_type_flag_id_by_name(
1844  if (unit_type_flag_id_is_valid(unit_type_flag_id(ival))) {
1845  qCCritical(ruleset_category,
1846  "\"%s\" unit_class \"%s\": unit_type flag \"%s\"!",
1847  filename, uclass_rule_name(uc), sval);
1848  } else {
1849  qCCritical(ruleset_category,
1850  "\"%s\" unit_class \"%s\": bad flag name \"%s\".",
1851  filename, uclass_rule_name(uc), sval);
1852  }
1853  break;
1854  } else {
1855  BV_SET(uc->flags, ival);
1856  }
1857  }
1858  delete[] slist;
1859  slist = nullptr;
1860 
1861  uc->helptext = lookup_strvec(file, sec_name, "helptext");
1862 
1863  if (!ok) {
1864  break;
1865  }
1866  }
1868  }
1869 
1870  if (ok) {
1871  // Tech and Gov requirements; per unit veteran system
1873  {
1874  const int i = utype_index(u);
1875  const struct section *psection = section_list_get(sec, i);
1876  const char *sec_name = section_name(psection);
1877 
1878  if (!lookup_tech(file, &u->require_advance, sec_name, "tech_req",
1879  filename, rule_name_get(&u->name))) {
1880  ok = false;
1881  break;
1882  }
1883  if (u->require_advance == A_NEVER) {
1884  qCCritical(ruleset_category, "%s lacks valid tech_req.",
1885  rule_name_get(&u->name));
1886  ok = false;
1887  break;
1888  }
1889 
1890  /* Read the government build requirement from the old ruleset format
1891  * and put it in unit_type's build_reqs requirement vector.
1892  * The build_reqs requirement vector isn't ready to be exposed in the
1893  * ruleset yet.
1894  * Barbarians can build certain units as long as anyone in the world
1895  * has the required tech. Regular players must have the required tech
1896  * them self to build the same unit. One way to solve this is to make
1897  * unit building an action enabler controlled action with a city (not
1898  * unit) actor.
1899  * Putting a requirement vector on unit types in the ruleset will
1900  * force ruleset authors to change all their unit type build
1901  * requirements to a requirement vector. Forcing them to convert their
1902  * unit type requirements again in the next version (should building be
1903  * switched to an action enabler with a city actor) is not good. */
1904  if (nullptr != section_entry_by_name(psection, "gov_req")) {
1905  char tmp[200] = "\0";
1906  struct government *need_government;
1907  fc_strlcat(tmp, section_name(psection), sizeof(tmp));
1908  fc_strlcat(tmp, ".gov_req", sizeof(tmp));
1909  need_government = lookup_government(file, tmp, filename, nullptr);
1910  if (need_government == nullptr) {
1911  ok = false;
1912  break;
1913  }
1914  requirement_vector_append(
1915  &u->build_reqs,
1916  req_from_values(VUT_GOVERNMENT, REQ_RANGE_PLAYER, false, true,
1917  false, government_number(need_government)));
1918  }
1919 
1920  if (!load_ruleset_veteran(file, sec_name, &u->veteran, msg,
1921  sizeof(msg), compat->compat_mode)) {
1922  qCCritical(ruleset_category, "Error loading the veteran system: %s",
1923  msg);
1924  ok = false;
1925  break;
1926  }
1927 
1928  if (!lookup_unit_type(file, sec_name, "obsolete_by", &u->obsoleted_by,
1929  filename, rule_name_get(&u->name))
1930  || !lookup_unit_type(file, sec_name, "convert_to",
1931  &u->converted_to, filename,
1932  rule_name_get(&u->name))) {
1933  ok = false;
1934  break;
1935  }
1936  u->convert_time = 1; // default
1937  lookup_time(file, &u->convert_time, sec_name, "convert_time", filename,
1938  rule_name_get(&u->name), &ok);
1939  }
1941  }
1942 
1943  if (ok) {
1944  // main stats:
1946  {
1947  const int i = utype_index(u);
1948  struct unit_class *pclass;
1949  const char *sec_name = section_name(section_list_get(sec, i));
1950  const char *string;
1951  struct impr_type *impr_req = nullptr;
1952 
1953  /* Read the building build requirement from the old ruleset format
1954  * and put it in unit_type's build_reqs requirement vector.
1955  * The build_reqs requirement vector isn't ready to be exposed in the
1956  * ruleset yet.
1957  * See the comment for gov_req above for why. */
1958  if (!lookup_building(file, sec_name, "impr_req", &impr_req, filename,
1959  rule_name_get(&u->name))) {
1960  ok = false;
1961  break;
1962  }
1963  if (impr_req) {
1964  requirement_vector_append(
1965  &u->build_reqs,
1966  req_from_values(VUT_IMPROVEMENT, REQ_RANGE_CITY, false, true,
1967  false, improvement_number(impr_req)));
1968  }
1969 
1970  sval = secfile_lookup_str(file, "%s.class", sec_name);
1971  pclass = unit_class_by_rule_name(sval);
1972  if (!pclass) {
1973  qCCritical(ruleset_category,
1974  "\"%s\" unit_type \"%s\":"
1975  " bad class \"%s\".",
1976  filename, utype_rule_name(u), sval);
1977  ok = false;
1978  break;
1979  }
1980  u->uclass = pclass;
1981 
1982  sz_strlcpy(u->sound_move, secfile_lookup_str_default(
1983  file, "-", "%s.sound_move", sec_name));
1984  sz_strlcpy(u->sound_move_alt,
1985  secfile_lookup_str_default(file, "-", "%s.sound_move_alt",
1986  sec_name));
1987  sz_strlcpy(u->sound_fight, secfile_lookup_str_default(
1988  file, "-", "%s.sound_fight", sec_name));
1989  sz_strlcpy(u->sound_fight_alt,
1990  secfile_lookup_str_default(file, "-", "%s.sound_fight_alt",
1991  sec_name));
1992 
1993  if ((string = secfile_lookup_str(file, "%s.graphic", sec_name))) {
1994  sz_strlcpy(u->graphic_str, string);
1995  } else {
1996  qCCritical(ruleset_category, "%s", secfile_error());
1997  ok = false;
1998  break;
1999  }
2000  sz_strlcpy(u->graphic_alt, secfile_lookup_str_default(
2001  file, "-", "%s.graphic_alt", sec_name));
2002 
2003  if (!secfile_lookup_int(file, &u->build_cost, "%s.build_cost",
2004  sec_name)
2005  || !secfile_lookup_int(file, &u->pop_cost, "%s.pop_cost", sec_name)
2006  || !secfile_lookup_int(file, &u->attack_strength, "%s.attack",
2007  sec_name)
2008  || !secfile_lookup_int(file, &u->defense_strength, "%s.defense",
2009  sec_name)
2010  || !secfile_lookup_int(file, &u->move_rate, "%s.move_rate",
2011  sec_name)
2012  || !secfile_lookup_int(file, &u->vision_radius_sq,
2013  "%s.vision_radius_sq", sec_name)
2014  || !secfile_lookup_int(file, &u->transport_capacity,
2015  "%s.transport_cap", sec_name)
2016  || !secfile_lookup_int(file, &u->hp, "%s.hitpoints", sec_name)
2017  || !secfile_lookup_int(file, &u->firepower, "%s.firepower",
2018  sec_name)
2019  || !secfile_lookup_int(file, &u->fuel, "%s.fuel", sec_name)
2020  || !secfile_lookup_int(file, &u->happy_cost, "%s.uk_happy",
2021  sec_name)) {
2022  qCCritical(ruleset_category, "%s", secfile_error());
2023  ok = false;
2024  break;
2025  }
2026  u->move_rate *= SINGLE_MOVE;
2027 
2028  lookup_cbonus_list(compat, u->bonuses, file, sec_name, "bonuses");
2029 
2031  {
2032  u->upkeep[o] = secfile_lookup_int_default(
2033  file, 0, "%s.uk_%s", sec_name, get_output_identifier(o));
2034  }
2036 
2037  slist = secfile_lookup_str_vec(file, &nval, "%s.cargo", sec_name);
2038  if (u->transport_capacity > 0) {
2039  if (nval == 0) {
2040  qCCritical(ruleset_category,
2041  "\"%s\" unit type \"%s\" "
2042  "has transport_cap %d, but no cargo unit classes.",
2043  filename, utype_rule_name(u), u->transport_capacity);
2044  ok = false;
2045  break;
2046  }
2047  } else {
2048  if (nval > 0) {
2049  qCCritical(ruleset_category,
2050  "\"%s\" unit type \"%s\" "
2051  "has cargo defined, but transport_cap is 0.",
2052  filename, utype_rule_name(u));
2053  ok = false;
2054  break;
2055  }
2056  }
2057 
2058  BV_CLR_ALL(u->cargo);
2059  for (j = 0; j < nval; j++) {
2060  struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
2061 
2062  if (!uclass) {
2063  qCCritical(ruleset_category,
2064  "\"%s\" unit_type \"%s\":"
2065  "has unknown unit class %s as cargo.",
2066  filename, utype_rule_name(u), slist[j]);
2067  ok = false;
2068  break;
2069  }
2070 
2071  BV_SET(u->cargo, uclass_index(uclass));
2072  }
2073  delete[] slist;
2074  slist = nullptr;
2075 
2076  if (!ok) {
2077  break;
2078  }
2079 
2080  slist = secfile_lookup_str_vec(file, &nval, "%s.targets", sec_name);
2081  BV_CLR_ALL(u->targets);
2082  for (j = 0; j < nval; j++) {
2083  struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
2084 
2085  if (!uclass) {
2086  qCCritical(ruleset_category,
2087  "\"%s\" unit_type \"%s\":"
2088  "has unknown unit class %s as target.",
2089  filename, utype_rule_name(u), slist[j]);
2090  ok = false;
2091  break;
2092  }
2093 
2094  BV_SET(u->targets, uclass_index(uclass));
2095  }
2096  delete[] slist;
2097  slist = nullptr;
2098 
2099  if (!ok) {
2100  break;
2101  }
2102 
2103  slist = secfile_lookup_str_vec(file, &nval, "%s.embarks", sec_name);
2104  BV_CLR_ALL(u->embarks);
2105  for (j = 0; j < nval; j++) {
2106  struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
2107 
2108  if (!uclass) {
2109  qCCritical(ruleset_category,
2110  "\"%s\" unit_type \"%s\":"
2111  "has unknown unit class %s as embarkable.",
2112  filename, utype_rule_name(u), slist[j]);
2113  ok = false;
2114  break;
2115  }
2116 
2117  BV_SET(u->embarks, uclass_index(uclass));
2118  }
2119  delete[] slist;
2120  slist = nullptr;
2121 
2122  if (!ok) {
2123  break;
2124  }
2125 
2126  slist = secfile_lookup_str_vec(file, &nval, "%s.disembarks", sec_name);
2127  BV_CLR_ALL(u->disembarks);
2128  for (j = 0; j < nval; j++) {
2129  struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
2130 
2131  if (!uclass) {
2132  qCCritical(ruleset_category,
2133  "\"%s\" unit_type \"%s\":"
2134  "has unknown unit class %s as disembarkable.",
2135  filename, utype_rule_name(u), slist[j]);
2136  ok = false;
2137  break;
2138  }
2139 
2140  BV_SET(u->disembarks, uclass_index(uclass));
2141  }
2142  delete[] slist;
2143  slist = nullptr;
2144 
2145  if (!ok) {
2146  break;
2147  }
2148 
2149  /* Set also all classes that are never unreachable as targets,
2150  * embarks, and disembarks. */
2151  unit_class_iterate(preachable)
2152  {
2153  if (!uclass_has_flag(preachable, UCF_UNREACHABLE)) {
2154  BV_SET(u->targets, uclass_index(preachable));
2155  BV_SET(u->embarks, uclass_index(preachable));
2156  BV_SET(u->disembarks, uclass_index(preachable));
2157  }
2158  }
2160 
2161  u->vlayer = vision_layer_by_name(
2162  secfile_lookup_str_default(file, "Main", "%s.vision_layer",
2163  sec_name),
2164  fc_strcasecmp);
2165  if (!vision_layer_is_valid(u->vlayer)) {
2166  qCCritical(ruleset_category,
2167  "\"%s\" unit_type \"%s\":"
2168  "has unknown vision layer %s.",
2169  filename, utype_rule_name(u), slist[j]);
2170  ok = false;
2171  break;
2172  }
2173 
2174  u->helptext = lookup_strvec(file, sec_name, "helptext");
2175 
2176  u->paratroopers_range = secfile_lookup_int_default(
2177  file, 0, "%s.paratroopers_range", sec_name);
2178  if (compat->compat_mode && compat->ver_units < 20) {
2179  u->rscompat_cache.paratroopers_mr_req =
2180  SINGLE_MOVE
2181  * secfile_lookup_int_default(file, 0, "%s.paratroopers_mr_req",
2182  sec_name);
2183  u->rscompat_cache.paratroopers_mr_sub =
2184  SINGLE_MOVE
2185  * secfile_lookup_int_default(file, 0, "%s.paratroopers_mr_sub",
2186  sec_name);
2187  } else {
2188  u->rscompat_cache.paratroopers_mr_req = 0;
2189  u->rscompat_cache.paratroopers_mr_sub = 0;
2190  }
2191  u->bombard_rate =
2192  secfile_lookup_int_default(file, 0, "%s.bombard_rate", sec_name);
2193  u->city_slots =
2194  secfile_lookup_int_default(file, 0, "%s.city_slots", sec_name);
2195  u->city_size =
2196  secfile_lookup_int_default(file, 1, "%s.city_size", sec_name);
2197  }
2199  }
2200 
2201  if (ok) {
2202  // flags
2204  {
2205  const int i = utype_index(u);
2206 
2207  BV_CLR_ALL(u->flags);
2209 
2210  slist = secfile_lookup_str_vec(file, &nval, "%s.flags",
2211  section_name(section_list_get(sec, i)));
2212  for (j = 0; j < nval; j++) {
2213  sval = slist[j];
2214  if (0 == strcmp(sval, "")) {
2215  continue;
2216  }
2217  if (compat->compat_mode && !fc_strcasecmp("Partial_Invis", sval)) {
2218  u->vlayer = V_INVIS;
2219  } else {
2220  ival = unit_type_flag_id_by_name(
2222  if (!unit_type_flag_id_is_valid(unit_type_flag_id(ival))) {
2223  ok = false;
2224  ival = unit_class_flag_id_by_name(sval, fc_strcasecmp);
2225  if (unit_class_flag_id_is_valid(unit_class_flag_id(ival))) {
2226  qCCritical(ruleset_category,
2227  "\"%s\" unit_type \"%s\": unit_class flag!",
2228  filename, utype_rule_name(u));
2229  } else {
2230  qCCritical(ruleset_category,
2231  "\"%s\" unit_type \"%s\": bad flag name \"%s\".",
2232  filename, utype_rule_name(u), sval);
2233  }
2234  break;
2235  } else {
2236  BV_SET(u->flags, ival);
2237  }
2238  fc_assert(utype_has_flag(u, ival));
2239  }
2240  }
2241  delete[] slist;
2242  slist = nullptr;
2243 
2244  if (!ok) {
2245  break;
2246  }
2247  }
2249  }
2250 
2251  // roles
2252  if (ok) {
2254  {
2255  const int i = utype_index(u);
2256 
2257  BV_CLR_ALL(u->roles);
2258 
2259  slist = secfile_lookup_str_vec(file, &nval, "%s.roles",
2260  section_name(section_list_get(sec, i)));
2261  for (j = 0; j < nval; j++) {
2262  sval = slist[j];
2263  if (strcmp(sval, "") == 0) {
2264  continue;
2265  }
2266  ival = unit_role_id_by_name(sval, fc_strcasecmp);
2267  if (!unit_role_id_is_valid(unit_role_id(ival))) {
2268  qCCritical(ruleset_category,
2269  "\"%s\" unit_type \"%s\": bad role name \"%s\".",
2270  filename, utype_rule_name(u), sval);
2271  ok = false;
2272  break;
2273  } else {
2274  BV_SET(u->roles, ival - L_FIRST);
2275  }
2276  fc_assert(utype_has_role(u, ival));
2277  }
2278  delete[] slist;
2279  slist = nullptr;
2280  }
2282  }
2283 
2284  if (ok) {
2285  // Some more consistency checking:
2287  {
2288  if (!valid_advance(u->require_advance)) {
2289  qCCritical(
2290  ruleset_category,
2291  "\"%s\" unit_type \"%s\": depends on removed tech \"%s\".",
2292  filename, utype_rule_name(u),
2293  advance_rule_name(u->require_advance));
2294  u->require_advance = A_NEVER;
2295  ok = false;
2296  break;
2297  }
2298 
2299  if (utype_has_flag(u, UTYF_SETTLERS) && u->city_size <= 0) {
2300  qCCritical(ruleset_category,
2301  "\"%s\": Unit %s would build size %d cities", filename,
2302  utype_rule_name(u), u->city_size);
2303  u->city_size = 1;
2304  ok = false;
2305  break;
2306  }
2307 
2308  // L_FERRYBOAT makes the AI consider the unit as a transport.
2309  // Ensure it can actually transport something.
2310  if (utype_has_role(u, L_FERRYBOAT) && u->transport_capacity == 0) {
2311  qCWarning(ruleset_category,
2312  "\"%s\": Unit %s has FerryBoat flag but cannot transport",
2313  filename, utype_rule_name(u));
2314  BV_CLR(u->roles, L_FERRYBOAT - L_FIRST);
2315  }
2316  }
2318  }
2319 
2320  section_list_destroy(csec);
2321  section_list_destroy(sec);
2322 
2323  if (ok) {
2324  secfile_check_unused(file);
2325  }
2326 
2327  return ok;
2328 }
2329 
2334 static bool load_building_names(struct section_file *file,
2335  struct rscompat_info *compat)
2336 {
2337  struct section_list *sec;
2338  int i, nval = 0;
2339  const char *filename = secfile_name(file);
2340  bool ok = true;
2341 
2342  compat->ver_buildings =
2343  rscompat_check_capabilities(file, filename, compat);
2344  if (compat->ver_buildings <= 0) {
2345  return false;
2346  }
2347 
2348  (void) secfile_entry_by_path(file, "datafile.description"); // unused
2349  (void) secfile_entry_by_path(file, "datafile.ruledit"); // unused
2350 
2351  // The names:
2353  if (nullptr == sec || 0 == (nval = section_list_size(sec))) {
2354  qCCritical(ruleset_category, "\"%s\": No improvements?!?", filename);
2355  ok = false;
2356  } else {
2357  qCDebug(ruleset_category,
2358  "%d improvement types (including possibly unused)", nval);
2359  if (nval > B_LAST) {
2360  qCCritical(ruleset_category,
2361  "\"%s\": Too many improvements (%d, max %d)", filename,
2362  nval, B_LAST);
2363  ok = false;
2364  }
2365  }
2366 
2367  if (ok) {
2368  game.control.num_impr_types = nval;
2369 
2370  for (i = 0; i < nval; i++) {
2371  struct impr_type *b = improvement_by_number(i);
2372 
2373  if (!ruleset_load_names(&b->name, nullptr, file,
2374  section_name(section_list_get(sec, i)))) {
2375  ok = false;
2376  break;
2377  }
2378  }
2379  }
2380 
2381  section_list_destroy(sec);
2382 
2383  return ok;
2384 }
2385 
2389 static bool load_ruleset_buildings(struct section_file *file,
2390  struct rscompat_info *compat)
2391 {
2392  struct section_list *sec;
2393  const char *item;
2394  int i, nval;
2395  const char *filename = secfile_name(file);
2396  bool ok = true;
2397 
2399  nval = (nullptr != sec ? section_list_size(sec) : 0);
2400 
2401  for (i = 0; i < nval && ok; i++) {
2402  struct impr_type *b = improvement_by_number(i);
2403  const char *sec_name = section_name(section_list_get(sec, i));
2404  struct requirement_vector *reqs = lookup_req_list(
2405  file, compat, sec_name, "reqs", improvement_rule_name(b));
2406 
2407  if (reqs == nullptr) {
2408  ok = false;
2409  break;
2410  } else {
2411  const char *sval, **slist;
2412  int j, ival;
2413  size_t nflags;
2414 
2415  item = secfile_lookup_str(file, "%s.genus", sec_name);
2416  b->genus = impr_genus_id_by_name(item, fc_strcasecmp);
2417  if (!impr_genus_id_is_valid(b->genus)) {
2418  qCCritical(ruleset_category,
2419  "\"%s\" improvement \"%s\": couldn't match "
2420  "genus \"%s\".",
2421  filename, improvement_rule_name(b), item);
2422  ok = false;
2423  break;
2424  }
2425 
2426  slist = secfile_lookup_str_vec(file, &nflags, "%s.flags", sec_name);
2427  BV_CLR_ALL(b->flags);
2428 
2429  for (j = 0; j < nflags; j++) {
2430  sval = slist[j];
2431  if (strcmp(sval, "") == 0) {
2432  continue;
2433  }
2434  ival = impr_flag_id_by_name(sval, fc_strcasecmp);
2435  if (!impr_flag_id_is_valid(impr_flag_id(ival))) {
2436  qCCritical(ruleset_category,
2437  "\"%s\" improvement \"%s\": bad flag name \"%s\".",
2438  filename, improvement_rule_name(b), sval);
2439  ok = false;
2440  break;
2441  } else {
2442  BV_SET(b->flags, ival);
2443  }
2444  }
2445  delete[] slist;
2446  slist = nullptr;
2447 
2448  if (!ok) {
2449  break;
2450  }
2451 
2452  requirement_vector_copy(&b->reqs, reqs);
2453 
2454  {
2455  struct requirement_vector *obs_reqs = lookup_req_list(
2456  file, compat, sec_name, "obsolete_by", improvement_rule_name(b));
2457 
2458  if (obs_reqs == nullptr) {
2459  ok = false;
2460  break;
2461  } else {
2462  requirement_vector_copy(&b->obsolete_by, obs_reqs);
2463  }
2464  }
2465 
2466  if (!secfile_lookup_int(file, &b->build_cost, "%s.build_cost",
2467  sec_name)
2468  || !secfile_lookup_int(file, &b->upkeep, "%s.upkeep", sec_name)
2469  || !secfile_lookup_int(file, &b->sabotage, "%s.sabotage",
2470  sec_name)) {
2471  qCCritical(ruleset_category, "%s", secfile_error());
2472  ok = false;
2473  break;
2474  }
2475 
2477  file, "-", "%s.graphic", sec_name));
2479  file, "-", "%s.graphic_alt", sec_name));
2480 
2482  file, "-", "%s.sound", sec_name));
2484  file, "-", "%s.sound_alt", sec_name));
2485  b->helptext = lookup_strvec(file, sec_name, "helptext");
2486  }
2487  }
2488 
2489  section_list_destroy(sec);
2490  if (ok) {
2491  secfile_check_unused(file);
2492  }
2493 
2494  return ok;
2495 }
2496 
2501 static bool load_terrain_names(struct section_file *file,
2502  struct rscompat_info *compat)
2503 {
2504  int nval = 0;
2505  struct section_list *sec = nullptr;
2506  const char *flag;
2507  int i;
2508  const char *filename = secfile_name(file);
2509  bool ok = true;
2510 
2511  compat->ver_terrain = rscompat_check_capabilities(file, filename, compat);
2512  if (compat->ver_terrain <= 0) {
2513  return false;
2514  }
2515 
2516  (void) secfile_entry_by_path(file, "datafile.description"); // unused
2517  (void) secfile_entry_by_path(file, "datafile.ruledit"); // unused
2518 
2519  // User terrain flag names
2520  for (i = 0; (flag = secfile_lookup_str_default(file, nullptr,
2521  "control.flags%d.name", i));
2522  i++) {
2523  const char *helptxt = secfile_lookup_str_default(
2524  file, nullptr, "control.flags%d.helptxt", i);
2525 
2526  if (terrain_flag_id_by_name(flag, fc_strcasecmp)
2527  != terrain_flag_id_invalid()) {
2528  qCCritical(ruleset_category,
2529  "\"%s\": Duplicate terrain flag name '%s'", filename, flag);
2530  ok = false;
2531  break;
2532  }
2533  if (i > MAX_NUM_USER_TER_FLAGS) {
2534  qCCritical(ruleset_category, "\"%s\": Too many user terrain flags!",
2535  filename);
2536  ok = false;
2537  break;
2538  }
2539 
2540  set_user_terrain_flag_name(terrain_flag_id(TER_USER_1 + i), flag,
2541  helptxt);
2542  }
2543 
2544  if (ok) {
2545  // Blank the remaining terrain user flag slots.
2546  for (; i < MAX_NUM_USER_TER_FLAGS; i++) {
2547  set_user_terrain_flag_name(terrain_flag_id(TER_USER_1 + i), nullptr,
2548  nullptr);
2549  }
2550  }
2551 
2552  // User extra flag names
2553  for (i = 0; (flag = secfile_lookup_str_default(
2554  file, nullptr, "control.extra_flags%d.name", i));
2555  i++) {
2556  const char *helptxt = secfile_lookup_str_default(
2557  file, nullptr, "control.extra_flags%d.helptxt", i);
2558 
2559  if (extra_flag_id_by_name(flag, fc_strcasecmp)
2560  != extra_flag_id_invalid()) {
2561  qCCritical(ruleset_category, "\"%s\": Duplicate extra flag name '%s'",
2562  filename, flag);
2563  ok = false;
2564  break;
2565  }
2566  if (i > MAX_NUM_USER_EXTRA_FLAGS) {
2567  qCCritical(ruleset_category, "\"%s\": Too many user extra flags!",
2568  filename);
2569  ok = false;
2570  break;
2571  }
2572 
2573  set_user_extra_flag_name(extra_flag_id(EF_USER_FLAG_1 + i), flag,
2574  helptxt);
2575  }
2576 
2577  if (ok) {
2578  // Blank the remaining extra user flag slots.
2579  for (; i < MAX_NUM_USER_EXTRA_FLAGS; i++) {
2580  set_user_extra_flag_name(extra_flag_id(EF_USER_FLAG_1 + i), nullptr,
2581  nullptr);
2582  }
2583 
2584  // terrain names
2585 
2587  if (nullptr == sec || 0 == (nval = section_list_size(sec))) {
2588  qCCritical(ruleset_category,
2589  "\"%s\": ruleset doesn't have any terrains.", filename);
2590  ok = false;
2591  } else {
2592  if (nval > MAX_NUM_TERRAINS) {
2593  qCCritical(ruleset_category,
2594  "\"%s\": Too many terrains (%d, max %d)", filename, nval,
2596  ok = false;
2597  }
2598  }
2599  }
2600 
2601  if (ok) {
2602  game.control.terrain_count = nval;
2603 
2604  // avoid re-reading files
2605  delete[] terrain_sections;
2606  terrain_sections = new char[nval][MAX_SECTION_LABEL]{};
2607 
2608  terrain_type_iterate(pterrain)
2609  {
2610  const int terri = terrain_index(pterrain);
2611  const char *sec_name = section_name(section_list_get(sec, terri));
2612 
2613  if (!ruleset_load_names(&pterrain->name, nullptr, file, sec_name)) {
2614  ok = false;
2615  break;
2616  }
2617 
2618  section_strlcpy(terrain_sections[terri], sec_name);
2619  }
2621  }
2622 
2623  section_list_destroy(sec);
2624  sec = nullptr;
2625 
2626  // extra names
2627 
2628  if (ok) {
2630  nval = (nullptr != sec ? section_list_size(sec) : 0);
2631  if (nval > MAX_EXTRA_TYPES) {
2632  qCCritical(ruleset_category,
2633  "\"%s\": Too many extra types (%d, max %d)", filename, nval,
2634  MAX_EXTRA_TYPES);
2635  ok = false;
2636  }
2637  }
2638 
2639  if (ok) {
2640  int idx;
2641 
2642  game.control.num_extra_types = nval;
2643 
2644  delete[] extra_sections;
2645  extra_sections = new char[nval][MAX_SECTION_LABEL]{};
2646 
2647  if (ok) {
2648  for (idx = 0; idx < nval; idx++) {
2649  const char *sec_name = section_name(section_list_get(sec, idx));
2650  struct extra_type *pextra = extra_by_number(idx);
2651 
2652  if (!ruleset_load_names(&pextra->name, nullptr, file, sec_name)) {
2653  ok = false;
2654  break;
2655  }
2656  section_strlcpy(extra_sections[idx], sec_name);
2657  }
2658  }
2659  }
2660 
2661  section_list_destroy(sec);
2662  sec = nullptr;
2663 
2664  // base names
2665 
2666  if (ok) {
2668  nval = (nullptr != sec ? section_list_size(sec) : 0);
2669  if (nval > MAX_BASE_TYPES) {
2670  qCCritical(ruleset_category,
2671  "\"%s\": Too many base types (%d, max %d)", filename, nval,
2672  MAX_BASE_TYPES);
2673  ok = false;
2674  }
2675 
2676  game.control.num_base_types = nval;
2677  }
2678 
2679  if (ok) {
2680  int idx;
2681 
2682  delete[] base_sections;
2683  base_sections = new char[nval][MAX_SECTION_LABEL]{};
2684 
2685  /* Cannot use base_type_iterate() before bases are added to
2686  * EC_BASE caused_by list. Have to get them by extra_type_by_rule_name()
2687  */
2688  for (idx = 0; idx < nval; idx++) {
2689  const char *sec_name = section_name(section_list_get(sec, idx));
2690  const char *base_name = secfile_lookup_str(file, "%s.extra", sec_name);
2691 
2692  if (base_name != nullptr) {
2693  struct extra_type *pextra = extra_type_by_rule_name(base_name);
2694 
2695  if (pextra != nullptr) {
2696  base_type_init(pextra, idx);
2697  section_strlcpy(base_sections[idx], sec_name);
2698  } else {
2699  qCCritical(ruleset_category,
2700  "No extra definition matching base definition \"%s\"",
2701  base_name);
2702  ok = false;
2703  }
2704  } else {
2705  qCCritical(
2706  ruleset_category,
2707  "Base section \"%s\" does not associate base with any extra",
2708  sec_name);
2709  ok = false;
2710  }
2711  }
2712  }
2713 
2714  section_list_destroy(sec);
2715  sec = nullptr;
2716 
2717  // road names
2718 
2719  if (ok) {
2721  nval = (nullptr != sec ? section_list_size(sec) : 0);
2722  if (nval > MAX_ROAD_TYPES) {
2723  qCCritical(ruleset_category,
2724  "\"%s\": Too many road types (%d, max %d)", filename, nval,
2725  MAX_ROAD_TYPES);
2726  ok = false;
2727  }
2728 
2729  game.control.num_road_types = nval;
2730  }
2731 
2732  if (ok) {
2733  int idx;
2734 
2735  delete[] road_sections;
2736  road_sections = new char[nval][MAX_SECTION_LABEL]{};
2737 
2738  /* Cannot use extra_type_by_cause_iterate(EC_ROAD) before roads are added
2739  * to EC_ROAD caused_by list. Have to get them by
2740  * extra_type_by_rule_name() */
2741  for (idx = 0; idx < nval; idx++) {
2742  const char *sec_name = section_name(section_list_get(sec, idx));
2743  const char *road_name = secfile_lookup_str(file, "%s.extra", sec_name);
2744 
2745  if (road_name != nullptr) {
2746  struct extra_type *pextra = extra_type_by_rule_name(road_name);
2747 
2748  if (pextra != nullptr) {
2749  road_type_init(pextra, idx);
2750  section_strlcpy(road_sections[idx], sec_name);
2751  } else {
2752  qCCritical(ruleset_category,
2753  "No extra definition matching road definition \"%s\"",
2754  road_name);
2755  ok = false;
2756  }
2757  } else {
2758  qCCritical(
2759  ruleset_category,
2760  "Road section \"%s\" does not associate road with any extra",
2761  sec_name);
2762  ok = false;
2763  }
2764  }
2765  }
2766 
2767  section_list_destroy(sec);
2768  sec = nullptr;
2769 
2770  // resource names
2771 
2772  if (ok) {
2774  nval = (nullptr != sec ? section_list_size(sec) : 0);
2775  if (nval > MAX_RESOURCE_TYPES) {
2776  qCCritical(ruleset_category,
2777  "\"%s\": Too many resource types (%d, max %d)", filename,
2778  nval, MAX_RESOURCE_TYPES);
2779  ok = false;
2780  }
2781 
2782  game.control.num_resource_types = nval;
2783  }
2784 
2785  if (ok) {
2786  int idx;
2787 
2788  delete[] resource_sections;
2789  resource_sections = new char[nval][MAX_SECTION_LABEL]{};
2790 
2791  /* Cannot use resource_type_iterate() before resource are added to
2792  * EC_RESOURCE caused_by list. Have to get them by
2793  * extra_type_by_rule_name() */
2794  for (idx = 0; idx < nval; idx++) {
2795  const char *sec_name = section_name(section_list_get(sec, idx));
2796  const char *resource_name;
2797  struct extra_type *pextra = nullptr;
2798 
2799  resource_name =
2800  secfile_lookup_str_default(file, nullptr, "%s.extra", sec_name);
2801 
2802  if (resource_name != nullptr) {
2803  pextra = extra_type_by_rule_name(resource_name);
2804 
2805  if (pextra != nullptr) {
2806  resource_type_init(pextra);
2807  section_strlcpy(resource_sections[idx], sec_name);
2808  } else {
2809  qCCritical(
2810  ruleset_category,
2811  "No extra definition matching resource definition \"%s\"",
2812  resource_name);
2813  ok = false;
2814  }
2815  } else {
2816  qCCritical(ruleset_category,
2817  "Resource section %s does not list extra this "
2818  "resource belongs to.",
2819  sec_name);
2820  ok = false;
2821  }
2822  }
2823  }
2824 
2825  section_list_destroy(sec);
2826 
2827  return ok;
2828 }
2829 
2833 static bool load_ruleset_terrain(struct section_file *file,
2834  struct rscompat_info *compat)
2835 {
2836  size_t nval;
2837  int j;
2838  bool compat_road = false;
2839  bool compat_rail = false;
2840  bool compat_river = false;
2841  const char **res;
2842  const char *filename = secfile_name(file);
2843  const char *text;
2844  bool ok = true;
2845 
2846  // parameters
2847 
2848  terrain_control.ocean_reclaim_requirement_pct = secfile_lookup_int_default(
2849  file, 101, "parameters.ocean_reclaim_requirement");
2850  terrain_control.land_channel_requirement_pct = secfile_lookup_int_default(
2851  file, 101, "parameters.land_channel_requirement");
2852  terrain_control.terrain_thaw_requirement_pct =
2853  secfile_lookup_int_default(file, 101, "parameters.thaw_requirement");
2854  terrain_control.terrain_freeze_requirement_pct =
2855  secfile_lookup_int_default(file, 101, "parameters.freeze_requirement");
2856  terrain_control.lake_max_size =
2857  secfile_lookup_int_default(file, 0, "parameters.lake_max_size");
2858  terrain_control.min_start_native_area = secfile_lookup_int_default(
2859  file, 0, "parameters.min_start_native_area");
2860  terrain_control.move_fragments =
2861  secfile_lookup_int_default(file, 3, "parameters.move_fragments");
2862  if (terrain_control.move_fragments < 1) {
2863  qCCritical(ruleset_category, "\"%s\": move_fragments must be at least 1",
2864  filename);
2865  ok = false;
2866  }
2868  terrain_control.igter_cost =
2869  secfile_lookup_int_default(file, 1, "parameters.igter_cost");
2870  if (terrain_control.igter_cost < 1) {
2871  qCCritical(ruleset_category, "\"%s\": igter_cost must be at least 1",
2872  filename);
2873  ok = false;
2874  }
2875 
2876  terrain_control.pythagorean_diagonal =
2878  "parameters.pythagorean_diagonal");
2879 
2880  wld.map.server.ocean_resources =
2881  secfile_lookup_bool_default(file, false, "parameters.ocean_resources");
2882 
2883  text = secfile_lookup_str_default(file, N_("?gui_type:Build Type A Base"),
2884  "extraui.ui_name_base_fortress");
2885  sz_strlcpy(terrain_control.gui_type_base0, text);
2886 
2887  text = secfile_lookup_str_default(file, N_("?gui_type:Build Type B Base"),
2888  "extraui.ui_name_base_airbase");
2889  sz_strlcpy(terrain_control.gui_type_base1, text);
2890 
2891  if (ok) {
2892  // terrain details
2893 
2894  terrain_type_iterate(pterrain)
2895  {
2896  const char **slist;
2897  const int i = terrain_index(pterrain);
2898  const char *tsection = terrain_sections[i];
2899  const char *cstr;
2900 
2901  sz_strlcpy(pterrain->graphic_str,
2902  secfile_lookup_str(file, "%s.graphic", tsection));
2903  sz_strlcpy(pterrain->graphic_alt,
2904  secfile_lookup_str(file, "%s.graphic_alt", tsection));
2905 
2906  pterrain->identifier =
2907  secfile_lookup_str(file, "%s.identifier", tsection)[0];
2908  if ('\0' == pterrain->identifier) {
2909  qCCritical(ruleset_category, "\"%s\" [%s] identifier missing value.",
2910  filename, tsection);
2911  ok = false;
2912  break;
2913  }
2914  if (TERRAIN_UNKNOWN_IDENTIFIER == pterrain->identifier) {
2915  qCCritical(ruleset_category,
2916  "\"%s\" [%s] cannot use '%c' as an identifier;"
2917  " it is reserved for unknown terrain.",
2918  filename, tsection, pterrain->identifier);
2919  ok = false;
2920  break;
2921  }
2922  for (j = T_FIRST; j < i; j++) {
2923  if (pterrain->identifier == terrain_by_number(j)->identifier) {
2924  qCCritical(ruleset_category,
2925  "\"%s\" [%s] has the same identifier as [%s].",
2926  filename, tsection, terrain_sections[j]);
2927  ok = false;
2928  break;
2929  }
2930  }
2931 
2932  if (!ok) {
2933  break;
2934  }
2935 
2936  cstr = secfile_lookup_str(file, "%s.class", tsection);
2937  pterrain->tclass = terrain_class_by_name(cstr, fc_strcasecmp);
2938  if (!terrain_class_is_valid(pterrain->tclass)) {
2939  qCCritical(ruleset_category, "\"%s\": [%s] unknown class \"%s\"",
2940  filename, tsection, cstr);
2941  ok = false;
2942  break;
2943  }
2944 
2945  if (!secfile_lookup_int(file, &pterrain->movement_cost,
2946  "%s.movement_cost", tsection)
2947  || !secfile_lookup_int(file, &pterrain->defense_bonus,
2948  "%s.defense_bonus", tsection)) {
2949  qCCritical(ruleset_category, "%s", secfile_error());
2950  ok = false;
2951  break;
2952  }
2953 
2955  {
2956  pterrain->output[o] = secfile_lookup_int_default(
2957  file, 0, "%s.%s", tsection, get_output_identifier(o));
2958  }
2960 
2961  res = secfile_lookup_str_vec(file, &nval, "%s.resources", tsection);
2962  pterrain->resources = new extra_type *[nval + 1]();
2963  for (j = 0; j < nval; j++) {
2964  pterrain->resources[j] = lookup_resource(filename, res[j], tsection);
2965  if (pterrain->resources[j] == nullptr) {
2966  ok = false;
2967  break;
2968  }
2969  }
2970  pterrain->resources[nval] = nullptr;
2971  delete[] res;
2972  res = nullptr;
2973 
2974  if (!ok) {
2975  break;
2976  }
2977 
2979  {
2980  pterrain->road_output_incr_pct[o] =
2981  secfile_lookup_int_default(file, 0, "%s.road_%s_incr_pct",
2982  tsection, get_output_identifier(o));
2983  }
2985 
2986  if (!lookup_time(file, &pterrain->base_time, tsection, "base_time",
2987  filename, nullptr, &ok)
2988  || !lookup_time(file, &pterrain->road_time, tsection, "road_time",
2989  filename, nullptr, &ok)) {
2990  qCCritical(ruleset_category, "%s", secfile_error());
2991  ok = false;
2992  break;
2993  }
2994 
2995  if (!lookup_terrain(file, "irrigation_result", filename, pterrain,
2996  &pterrain->irrigation_result)) {
2997  ok = false;
2998  break;
2999  }
3000  if (!secfile_lookup_int(file, &pterrain->irrigation_food_incr,
3001  "%s.irrigation_food_incr", tsection)
3002  || !lookup_time(file, &pterrain->irrigation_time, tsection,
3003  "irrigation_time", filename, nullptr, &ok)) {
3004  qCCritical(ruleset_category, "%s", secfile_error());
3005  ok = false;
3006  break;
3007  }
3008 
3009  if (!lookup_terrain(file, "mining_result", filename, pterrain,
3010  &pterrain->mining_result)) {
3011  ok = false;
3012  break;
3013  }
3014  if (!secfile_lookup_int(file, &pterrain->mining_shield_incr,
3015  "%s.mining_shield_incr", tsection)
3016  || !lookup_time(file, &pterrain->mining_time, tsection,
3017  "mining_time", filename, nullptr, &ok)) {
3018  qCCritical(ruleset_category, "%s", secfile_error());
3019  ok = false;
3020  break;
3021  }
3022 
3023  if (!lookup_time(file, &pterrain->cultivate_time, tsection,
3024  "cultivate_time", filename, nullptr, &ok)) {
3025  if (compat->compat_mode) {
3026  if (pterrain->irrigation_result != pterrain) {
3027  pterrain->cultivate_time = pterrain->irrigation_time;
3028  pterrain->irrigation_time = 0;
3029  } else {
3030  pterrain->cultivate_time = 0;
3031  }
3032  } else {
3033  qCCritical(ruleset_category, "%s", secfile_error());
3034  ok = false;
3035  break;
3036  }
3037  }
3038 
3039  if (!lookup_time(file, &pterrain->plant_time, tsection, "plant_time",
3040  filename, nullptr, &ok)) {
3041  if (compat->compat_mode) {
3042  if (pterrain->mining_result != pterrain) {
3043  pterrain->plant_time = pterrain->mining_time;
3044  pterrain->mining_time = 0;
3045  } else {
3046  pterrain->plant_time = 0;
3047  }
3048  } else {
3049  qCCritical(ruleset_category, "%s", secfile_error());
3050  ok = false;
3051  break;
3052  }
3053  }
3054 
3055  if (!lookup_unit_type(file, tsection, "animal", &pterrain->animal,
3056  filename, rule_name_get(&pterrain->name))) {
3057  ok = false;
3058  break;
3059  }
3060 
3061  if (!lookup_terrain(file, "transform_result", filename, pterrain,
3062  &pterrain->transform_result)) {
3063  ok = false;
3064  break;
3065  }
3066  if (!lookup_time(file, &pterrain->transform_time, tsection,
3067  "transform_time", filename, nullptr, &ok)) {
3068  qCCritical(ruleset_category, "%s", secfile_error());
3069  ok = false;
3070  break;
3071  }
3072 
3073  pterrain->placing_time = 1; // default
3074  lookup_time(file, &pterrain->placing_time, tsection, "placing_time",
3075  filename, nullptr, &ok);
3076 
3077  pterrain->pillage_time = 1; // default
3078  lookup_time(file, &pterrain->pillage_time, tsection, "pillage_time",
3079  filename, nullptr, &ok);
3080  pterrain->clean_pollution_time = 3; // default
3081  lookup_time(file, &pterrain->clean_pollution_time, tsection,
3082  "clean_pollution_time", filename, nullptr, &ok);
3083  pterrain->clean_fallout_time = 3; // default
3084  lookup_time(file, &pterrain->clean_fallout_time, tsection,
3085  "clean_fallout_time", filename, nullptr, &ok);
3086 
3087  if (!lookup_terrain(file, "warmer_wetter_result", filename, pterrain,
3088  &pterrain->warmer_wetter_result)
3089  || !lookup_terrain(file, "warmer_drier_result", filename, pterrain,
3090  &pterrain->warmer_drier_result)
3091  || !lookup_terrain(file, "cooler_wetter_result", filename,
3092  pterrain, &pterrain->cooler_wetter_result)
3093  || !lookup_terrain(file, "cooler_drier_result", filename, pterrain,
3094  &pterrain->cooler_drier_result)) {
3095  ok = false;
3096  break;
3097  }
3098 
3099  slist = secfile_lookup_str_vec(file, &nval, "%s.flags", tsection);
3100  BV_CLR_ALL(pterrain->flags);
3101  for (j = 0; j < nval; j++) {
3102  const char *sval = slist[j];
3103  enum terrain_flag_id flag =
3104  terrain_flag_id_by_name(sval, fc_strcasecmp);
3105 
3106  if (!terrain_flag_id_is_valid(flag)) {
3107  qCCritical(ruleset_category,
3108  "\"%s\" [%s] has unknown flag \"%s\".", filename,
3109  tsection, sval);
3110  ok = false;
3111  break;
3112  } else {
3113  BV_SET(pterrain->flags, flag);
3114  }
3115  }
3116  delete[] slist;
3117  slist = nullptr;
3118 
3119  if (!ok) {
3120  break;
3121  }
3122 
3123  {
3124  enum mapgen_terrain_property mtp;
3125  for (mtp = mapgen_terrain_property_begin();
3126  mtp != mapgen_terrain_property_end();
3127  mtp = mapgen_terrain_property_next(mtp)) {
3128  pterrain->property[mtp] =
3129  secfile_lookup_int_default(file, 0, "%s.property_%s", tsection,
3130  mapgen_terrain_property_name(mtp));
3131  }
3132  }
3133 
3134  slist = secfile_lookup_str_vec(file, &nval, "%s.native_to", tsection);
3135  BV_CLR_ALL(pterrain->native_to);
3136  for (j = 0; j < nval; j++) {
3137  struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
3138 
3139  if (!uclass) {
3140  qCCritical(ruleset_category,
3141  "\"%s\" [%s] is native to unknown unit class \"%s\".",
3142  filename, tsection, slist[j]);
3143  ok = false;
3144  break;
3145  } else {
3146  BV_SET(pterrain->native_to, uclass_index(uclass));
3147  }
3148  }
3149  delete[] slist;
3150  slist = nullptr;
3151 
3152  if (!ok) {
3153  break;
3154  }
3155 
3156  // get terrain color
3157  {
3158  fc_assert_ret_val(pterrain->rgb == nullptr, false);
3159  if (!rgbcolor_load(file, &pterrain->rgb, "%s.color", tsection)) {
3160  qCCritical(ruleset_category,
3161  "Missing terrain color definition: %s",
3162  secfile_error());
3163  ok = false;
3164  break;
3165  }
3166  }
3167 
3168  pterrain->helptext = lookup_strvec(file, tsection, "helptext");
3169  }
3171  }
3172 
3173  if (ok) {
3174  // extra details
3175  extra_type_iterate(pextra) { BV_CLR_ALL(pextra->conflicts); }
3177 
3178  extra_type_iterate(pextra)
3179  {
3180  if (!compat->compat_mode || compat->ver_terrain >= 10
3181  || pextra->category != ECAT_RESOURCE) {
3182  const char *section = extra_sections[extra_index(pextra)];
3183  const char **slist;
3184  struct requirement_vector *reqs;
3185  const char *catname;
3186  int cj;
3187  enum extra_cause cause;
3188  enum extra_rmcause rmcause;
3189  const char *eus_name;
3190  const char *vis_req_name;
3191  const struct advance *vis_req;
3192 
3193  catname = secfile_lookup_str(file, "%s.category", section);
3194  if (catname == nullptr) {
3195  qCCritical(ruleset_category,
3196  "\"%s\" extra \"%s\" has no category.", filename,
3197  extra_rule_name(pextra));
3198  ok = false;
3199  break;
3200  }
3201  pextra->category = extra_category_by_name(catname, fc_strcasecmp);
3202  if (!extra_category_is_valid(pextra->category)) {
3203  qCCritical(ruleset_category,
3204  "\"%s\" extra \"%s\" has invalid category \"%s\".",
3205  filename, extra_rule_name(pextra), catname);
3206  ok = false;
3207  break;
3208  }
3209 
3210  slist = secfile_lookup_str_vec(file, &nval, "%s.causes", section);
3211  pextra->causes = 0;
3212  for (cj = 0; cj < nval; cj++) {
3213  const char *sval = slist[cj];
3214  cause = extra_cause_by_name(sval, fc_strcasecmp);
3215 
3216  if (!extra_cause_is_valid(cause)) {
3217  qCCritical(ruleset_category,
3218  "\"%s\" extra \"%s\": unknown cause \"%s\".",
3219  filename, extra_rule_name(pextra), sval);
3220  ok = false;
3221  break;
3222  } else {
3223  pextra->causes |= (1 << cause);
3224  extra_to_caused_by_list(pextra, cause);
3225  }
3226  }
3227 
3228  if (pextra->causes == 0) {
3229  // Extras that do not have any causes added to EC_NONE list
3231  }
3232 
3233  if (!is_extra_caused_by(pextra, EC_BASE)
3234  && !is_extra_caused_by(pextra, EC_ROAD)
3235  && !is_extra_caused_by(pextra, EC_RESOURCE)) {
3236  // Not a base, road, nor resource, so special
3237  pextra->data.special_idx =
3238  extra_type_list_size(extra_type_list_by_cause(EC_SPECIAL));
3240  }
3241 
3242  delete[] slist;
3243  slist = nullptr;
3244 
3245  slist = secfile_lookup_str_vec(file, &nval, "%s.rmcauses", section);
3246  pextra->rmcauses = 0;
3247  for (j = 0; j < nval; j++) {
3248  const char *sval = slist[j];
3249  rmcause = extra_rmcause_by_name(sval, fc_strcasecmp);
3250 
3251  if (!extra_rmcause_is_valid(rmcause)) {
3252  qCCritical(ruleset_category,
3253  "\"%s\" extra \"%s\": unknown rmcause \"%s\".",
3254  filename, extra_rule_name(pextra), sval);
3255  ok = false;
3256  break;
3257  } else {
3258  pextra->rmcauses |= (1 << rmcause);
3259  extra_to_removed_by_list(pextra, rmcause);
3260  }
3261  }
3262 
3263  delete[] slist;
3264  slist = nullptr;
3265 
3266  sz_strlcpy(pextra->activity_gfx,
3267  secfile_lookup_str_default(file, "-", "%s.activity_gfx",
3268  section));
3269  sz_strlcpy(pextra->act_gfx_alt,
3270  secfile_lookup_str_default(file, "-", "%s.act_gfx_alt",
3271  section));
3272  sz_strlcpy(pextra->act_gfx_alt2,
3273  secfile_lookup_str_default(file, "-", "%s.act_gfx_alt2",
3274  section));
3275  sz_strlcpy(
3276  pextra->rmact_gfx,
3277  secfile_lookup_str_default(file, "-", "%s.rmact_gfx", section));
3278  sz_strlcpy(pextra->rmact_gfx_alt,
3279  secfile_lookup_str_default(file, "-", "%s.rmact_gfx_alt",
3280  section));
3281  sz_strlcpy(
3282  pextra->graphic_str,
3283  secfile_lookup_str_default(file, "-", "%s.graphic", section));
3284  sz_strlcpy(pextra->graphic_alt,
3285  secfile_lookup_str_default(file, "-", "%s.graphic_alt",
3286  section));
3287 
3288  reqs = lookup_req_list(file, compat, section, "reqs",
3289  extra_rule_name(pextra));
3290  if (reqs == nullptr) {
3291  ok = false;
3292  break;
3293  }
3294  requirement_vector_copy(&pextra->reqs, reqs);
3295 
3296  reqs = lookup_req_list(file, compat, section, "rmreqs",
3297  extra_rule_name(pextra));
3298  if (reqs == nullptr) {
3299  ok = false;
3300  break;
3301  }
3302  requirement_vector_copy(&pextra->rmreqs, reqs);
3303 
3304  reqs = lookup_req_list(file, compat, section, "appearance_reqs",
3305  extra_rule_name(pextra));
3306  if (reqs == nullptr) {
3307  ok = false;
3308  break;
3309  }
3310  requirement_vector_copy(&pextra->appearance_reqs, reqs);
3311 
3312  reqs = lookup_req_list(file, compat, section, "disappearance_reqs",
3313  extra_rule_name(pextra));
3314  if (reqs == nullptr) {
3315  ok = false;
3316  break;
3317  }
3318  requirement_vector_copy(&pextra->disappearance_reqs, reqs);
3319 
3320  pextra->buildable = secfile_lookup_bool_default(
3321  file, is_extra_caused_by_worker_action(pextra), "%s.buildable",
3322  section);
3323  pextra->generated =
3324  secfile_lookup_bool_default(file, true, "%s.generated", section);
3325 
3326  pextra->build_time = 0; // default
3327  lookup_time(file, &pextra->build_time, section, "build_time",
3328  filename, extra_rule_name(pextra), &ok);
3329  pextra->build_time_factor = secfile_lookup_int_default(
3330  file, 1, "%s.build_time_factor", section);
3331  pextra->removal_time = 0; // default
3332  lookup_time(file, &pextra->removal_time, section, "removal_time",
3333  filename, extra_rule_name(pextra), &ok);
3334  pextra->removal_time_factor = secfile_lookup_int_default(
3335  file, 1, "%s.removal_time_factor", section);
3336 
3337  pextra->defense_bonus =
3338  secfile_lookup_int_default(file, 0, "%s.defense_bonus", section);
3339  if (pextra->defense_bonus != 0) {
3340  if (extra_has_flag(pextra, EF_NATURAL_DEFENSE)) {
3342  } else {
3344  }
3345  }
3346 
3347  eus_name = secfile_lookup_str_default(file, "Normal", "%s.unit_seen",
3348  section);
3349  pextra->eus = extra_unit_seen_type_by_name(eus_name, fc_strcasecmp);
3350  if (!extra_unit_seen_type_is_valid(pextra->eus)) {
3351  qCCritical(
3352  ruleset_category,
3353  "\"%s\" extra \"%s\" has illegal unit_seen value \"%s\".",
3354  filename, extra_rule_name(pextra), eus_name);
3355  ok = false;
3356  break;
3357  }
3358  if (pextra->eus == EUS_HIDDEN) {
3359  extra_type_list_append(extra_type_list_of_unit_hiders(), pextra);
3360  }
3361 
3362  pextra->appearance_chance =
3364  "%s.appearance_chance", section);
3365  pextra->disappearance_chance =
3367  "%s.disappearance_chance", section);
3368 
3369  slist = secfile_lookup_str_vec(file, &nval, "%s.native_to", section);
3370  BV_CLR_ALL(pextra->native_to);
3371  for (j = 0; j < nval; j++) {
3372  struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
3373 
3374  if (uclass == nullptr) {
3375  qCCritical(ruleset_category,
3376  "\"%s\" extra \"%s\" is native to unknown unit "
3377  "class \"%s\".",
3378  filename, extra_rule_name(pextra), slist[j]);
3379  ok = false;
3380  break;
3381  } else {
3382  BV_SET(pextra->native_to, uclass_index(uclass));
3383  }
3384  }
3385  delete[] slist;
3386  slist = nullptr;
3387 
3388  if (!ok) {
3389  break;
3390  }
3391 
3392  slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
3393  BV_CLR_ALL(pextra->flags);
3394  for (j = 0; j < nval; j++) {
3395  const char *sval = slist[j];
3396  enum extra_flag_id flag =
3397  extra_flag_id_by_name(sval, fc_strcasecmp);
3398 
3399  if (!extra_flag_id_is_valid(flag)) {
3400  qCCritical(ruleset_category,
3401  "\"%s\" extra \"%s\": unknown flag \"%s\".", filename,
3402  extra_rule_name(pextra), sval);
3403  ok = false;
3404  break;
3405  } else {
3406  BV_SET(pextra->flags, flag);
3407  }
3408  }
3409  delete[] slist;
3410  slist = nullptr;
3411 
3412  if (!ok) {
3413  break;
3414  }
3415 
3416  slist = secfile_lookup_str_vec(file, &nval, "%s.conflicts", section);
3417  for (j = 0; j < nval; j++) {
3418  const char *sval = slist[j];
3419  struct extra_type *pextra2 = extra_type_by_rule_name(sval);
3420 
3421  if (pextra2 == nullptr) {
3422  qCCritical(ruleset_category,
3423  "\"%s\" extra \"%s\": unknown conflict extra \"%s\".",
3424  filename, extra_rule_name(pextra), sval);
3425  ok = false;
3426  break;
3427  } else {
3428  BV_SET(pextra->conflicts, extra_index(pextra2));
3429  BV_SET(pextra2->conflicts, extra_index(pextra));
3430  }
3431  }
3432 
3433  delete[] slist;
3434  slist = nullptr;
3435 
3436  if (!ok) {
3437  break;
3438  }
3439 
3440  slist = secfile_lookup_str_vec(file, &nval, "%s.hidden_by", section);
3441  BV_CLR_ALL(pextra->hidden_by);
3442  for (j = 0; j < nval; j++) {
3443  const char *sval = slist[j];
3444  const struct extra_type *top = extra_type_by_rule_name(sval);
3445 
3446  if (top == nullptr) {
3447  qCCritical(ruleset_category,
3448  "\"%s\" extra \"%s\" hidden by unknown extra \"%s\".",
3449  filename, extra_rule_name(pextra), sval);
3450  ok = false;
3451  break;
3452  } else {
3453  BV_SET(pextra->hidden_by, extra_index(top));
3454  }
3455  }
3456  delete[] slist;
3457  slist = nullptr;
3458 
3459  if (!ok) {
3460  break;
3461  }
3462 
3463  slist =
3464  secfile_lookup_str_vec(file, &nval, "%s.bridged_over", section);
3465  BV_CLR_ALL(pextra->bridged_over);
3466  for (j = 0; j < nval; j++) {
3467  const char *sval = slist[j];
3468  const struct extra_type *top = extra_type_by_rule_name(sval);
3469 
3470  if (top == nullptr) {
3471  qCCritical(
3472  ruleset_category,
3473  "\"%s\" extra \"%s\" bridged over unknown extra \"%s\".",
3474  filename, extra_rule_name(pextra), sval);
3475  ok = false;
3476  break;
3477  } else {
3478  BV_SET(pextra->bridged_over, extra_index(top));
3479  }
3480  }
3481  delete[] slist;
3482  slist = nullptr;
3483 
3484  if (!ok) {
3485  break;
3486  }
3487 
3488  vis_req_name = secfile_lookup_str_default(
3489  file, "None", "%s.visibility_req", section);
3490  vis_req = advance_by_rule_name(vis_req_name);
3491 
3492  if (vis_req == nullptr) {
3493  qCCritical(ruleset_category,
3494  "\"%s\" %s: unknown visibility_req %s.", filename,
3495  section, vis_req_name);
3496  ok = false;
3497  break;
3498  }
3499 
3500  pextra->visibility_req = advance_number(vis_req);
3501 
3502  pextra->helptext = lookup_strvec(file, section, "helptext");
3503  }
3504 
3506  }
3508  }
3509 
3510  if (ok) {
3511  int i = 0;
3512  // resource details
3513 
3514  extra_type_by_cause_iterate(EC_RESOURCE, presource)
3515  {
3516  char identifier[MAX_LEN_NAME];
3517  const char *rsection = resource_sections[i];
3518 
3519  if (!presource->data.resource) {
3520  qCCritical(ruleset_category,
3521  "\"%s\" extra \"%s\" has \"Resource\" cause but no "
3522  "corresponding [resource_*] section",
3523  filename, extra_rule_name(presource));
3524  ok = false;
3525  break;
3526  }
3527 
3529  {
3530  presource->data.resource->output[o] = secfile_lookup_int_default(
3531  file, 0, "%s.%s", rsection, get_output_identifier(o));
3532  }
3534 
3535  sz_strlcpy(identifier,
3536  secfile_lookup_str(file, "%s.identifier", rsection));
3537  presource->data.resource->id_old_save = identifier[0];
3539  == presource->data.resource->id_old_save) {
3540  qCCritical(ruleset_category, "\"%s\" [%s] identifier missing value.",
3541  filename, rsection);
3542  ok = false;
3543  break;
3544  }
3546  == presource->data.resource->id_old_save) {
3547  qCCritical(ruleset_category,
3548  "\"%s\" [%s] cannot use '%c' as an identifier;"
3549  " it is reserved.",
3550  filename, rsection,
3551  presource->data.resource->id_old_save);
3552  ok = false;
3553  break;
3554  }
3555  i++;
3556  }
3558 
3559  for (j = 0; ok && j < game.control.num_resource_types; j++) {
3560  const char *section = resource_sections[j];
3561  const char *extra_name = secfile_lookup_str(file, "%s.extra", section);
3562  struct extra_type *pextra = extra_type_by_rule_name(extra_name);
3563 
3564  if (!is_extra_caused_by(pextra, EC_RESOURCE)) {
3565  qCCritical(ruleset_category,
3566  "\"%s\" resource section [%s]: extra \"%s\" does not "
3567  "have \"Resource\" in its causes",
3568  filename, section, extra_name);
3569  ok = false;
3570  }
3571  }
3572  }
3573 
3574  if (ok) {
3575  /* This can't be part of previous loop as we don't want random data from
3576  * previous ruleset to play havoc on us when we have only some resource
3577  * identifiers loaded from the new ruleset. */
3578  extra_type_by_cause_iterate(EC_RESOURCE, pres)
3579  {
3580  extra_type_by_cause_iterate(EC_RESOURCE, pres2)
3581  {
3582  if (pres->data.resource->id_old_save
3583  == pres2->data.resource->id_old_save
3584  && pres != pres2) {
3585  qCCritical(ruleset_category,
3586  "\"%s\" [%s] has the same identifier as [%s].",
3587  filename, extra_rule_name(pres),
3588  extra_rule_name(pres2));
3589  ok = false;
3590  break;
3591  }
3592  }
3594 
3595  if (!ok) {
3596  break;
3597  }
3598  }
3600  }
3601 
3602  if (ok) {
3603  // base details
3604  extra_type_by_cause_iterate(EC_BASE, pextra)
3605  {
3606  struct base_type *pbase = extra_base_get(pextra);
3607  const char *section;
3608  int bj;
3609  const char **slist;
3610  const char *gui_str;
3611 
3612  if (!pbase) {
3613  qCCritical(ruleset_category,
3614  "\"%s\" extra \"%s\" has \"Base\" cause but no "
3615  "corresponding [base_*] section",
3616  filename, extra_rule_name(pextra));
3617  ok = false;
3618  break;
3619  }
3620  section = base_sections[base_number(pbase)];
3621 
3622  gui_str = secfile_lookup_str(file, "%s.gui_type", section);
3623  pbase->gui_type = base_gui_type_by_name(gui_str, fc_strcasecmp);
3624  if (!base_gui_type_is_valid(pbase->gui_type)) {
3625  qCCritical(ruleset_category,
3626  "\"%s\" base \"%s\": unknown gui_type \"%s\".", filename,
3627  extra_rule_name(pextra), gui_str);
3628  ok = false;
3629  break;
3630  }
3631 
3632  pbase->border_sq =
3633  secfile_lookup_int_default(file, -1, "%s.border_sq", section);
3634  pbase->vision_main_sq =
3635  secfile_lookup_int_default(file, -1, "%s.vision_main_sq", section);
3637  file, -1, "%s.vision_invis_sq", section);
3638  pbase->vision_subs_sq =
3639  secfile_lookup_int_default(file, -1, "%s.vision_subs_sq", section);
3640 
3641  slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
3642  BV_CLR_ALL(pbase->flags);
3643  for (bj = 0; bj < nval; bj++) {
3644  const char *sval = slist[bj];
3645  enum base_flag_id flag = base_flag_id_by_name(sval, fc_strcasecmp);
3646 
3647  if (!base_flag_id_is_valid(flag)) {
3648  qCCritical(ruleset_category,
3649  "\"%s\" base \"%s\": unknown flag \"%s\".", filename,
3650  extra_rule_name(pextra), sval);
3651  ok = false;
3652  break;
3653  } else if ((!compat->compat_mode || compat->ver_terrain >= 20)
3654  && base_flag_is_retired(flag)) {
3655  qCCritical(ruleset_category,
3656  "\"%s\" base \"%s\": retired flag "
3657  "\"%s\". Please update the ruleset.",
3658  filename, extra_rule_name(pextra), sval);
3659  ok = false;
3660  } else {
3661  BV_SET(pbase->flags, flag);
3662  }
3663  }
3664 
3665  delete[] slist;
3666  slist = nullptr;
3667 
3668  if (!ok) {
3669  break;
3670  }
3671 
3672  if (territory_claiming_base(pbase)) {
3673  extra_type_by_cause_iterate(EC_BASE, pextra2)
3674  {
3675  struct base_type *pbase2;
3676 
3677  if (pextra == pextra2) {
3678  // End of the fully initialized bases iteration.
3679  break;
3680  }
3681 
3682  pbase2 = extra_base_get(pextra2);
3683  if (territory_claiming_base(pbase2)) {
3684  BV_SET(pextra->conflicts, extra_index(pextra2));
3685  BV_SET(pextra2->conflicts, extra_index(pextra));
3686  }
3687  }
3689  }
3690  }
3692 
3693  for (j = 0; ok && j < game.control.num_base_types; j++) {
3694  const char *section = base_sections[j];
3695  const char *extra_name = secfile_lookup_str(file, "%s.extra", section);
3696  struct extra_type *pextra = extra_type_by_rule_name(extra_name);
3697 
3698  if (!is_extra_caused_by(pextra, EC_BASE)) {
3699  qCCritical(ruleset_category,
3700  "\"%s\" base section [%s]: extra \"%s\" does not have "
3701  "\"Base\" in its causes",
3702  filename, section, extra_name);
3703  ok = false;
3704  }
3705  }
3706  }
3707 
3708  if (ok) {
3709  bv_extras compat_bridged;
3710 
3711  if (compat->compat_mode) {
3712  BV_CLR_ALL(compat_bridged);
3713  extra_type_by_cause_iterate(EC_ROAD, pextra)
3714  {
3715  struct road_type *proad = extra_road_get(pextra);
3716  const char *section = road_sections[road_number(proad)];
3717  const char **slist;
3718 
3719  slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
3720 
3721  for (j = 0; j < nval; j++) {
3722  if (!fc_strcasecmp("PreventsOtherRoads", slist[j])) {
3723  BV_SET(compat_bridged, pextra->id);
3724  }
3725  }
3726 
3727  delete[] slist;
3728  slist = nullptr;
3729  }
3731  }
3732  extra_type_by_cause_iterate(EC_ROAD, pextra)
3733  {
3734  struct road_type *proad = extra_road_get(pextra);
3735  const char *section;
3736  const char **slist;
3737  const char *special;
3738  const char *modestr;
3739  struct requirement_vector *reqs;
3740 
3741  if (!proad) {
3742  qCCritical(ruleset_category,
3743  "\"%s\" extra \"%s\" has \"Road\" cause but no "
3744  "corresponding [road_*] section",
3745  filename, extra_rule_name(pextra));
3746  ok = false;
3747  break;
3748  }
3749  section = road_sections[road_number(proad)];
3750 
3751  reqs = lookup_req_list(file, compat, section, "first_reqs",
3752  extra_rule_name(pextra));
3753  if (reqs == nullptr) {
3754  ok = false;
3755  break;
3756  }
3757  requirement_vector_copy(&proad->first_reqs, reqs);
3758 
3759  if (!secfile_lookup_int(file, &proad->move_cost, "%s.move_cost",
3760  section)) {
3761  qCCritical(ruleset_category, "Error: %s", secfile_error());
3762  ok = false;
3763  break;
3764  }
3765 
3766  modestr = secfile_lookup_str_default(file, "FastAlways",
3767  "%s.move_mode", section);
3768  proad->move_mode = road_move_mode_by_name(modestr, fc_strcasecmp);
3769  if (!road_move_mode_is_valid(proad->move_mode)) {
3770  qCCritical(ruleset_category,
3771  "Illegal move_mode \"%s\" for road \"%s\"", modestr,
3772  extra_rule_name(pextra));
3773  ok = false;
3774  break;
3775  }
3776 
3778  {
3780  file, 0, "%s.%s_incr_const", section, get_output_identifier(o));
3782  file, 0, "%s.%s_incr", section, get_output_identifier(o));
3784  file, 0, "%s.%s_bonus", section, get_output_identifier(o));
3785  }
3787 
3788  special = secfile_lookup_str_default(file, "None", "%s.compat_special",
3789  section);
3790  if (!fc_strcasecmp(special, "Road")) {
3791  if (compat_road) {
3792  qCCritical(ruleset_category,
3793  "Multiple roads marked as compatibility \"Road\"");
3794  ok = false;
3795  }
3796  compat_road = true;
3797  proad->compat = ROCO_ROAD;
3798  } else if (!fc_strcasecmp(special, "Railroad")) {
3799  if (compat_rail) {
3800  qCCritical(ruleset_category,
3801  "Multiple roads marked as compatibility \"Railroad\"");
3802  ok = false;
3803  }
3804  compat_rail = true;
3805  proad->compat = ROCO_RAILROAD;
3806  } else if (!fc_strcasecmp(special, "River")) {
3807  if (compat_river) {
3808  qCCritical(ruleset_category,
3809  "Multiple roads marked as compatibility \"River\"");
3810  ok = false;
3811  }
3812  compat_river = true;
3813  proad->compat = ROCO_RIVER;
3814  } else if (!fc_strcasecmp(special, "None")) {
3815  proad->compat = ROCO_NONE;
3816  } else {
3817  qCCritical(ruleset_category,
3818  "Illegal compatibility special \"%s\" for road %s",
3819  special, extra_rule_name(pextra));
3820  ok = false;
3821  }
3822 
3823  if (!ok) {
3824  break;
3825  }
3826 
3827  slist = secfile_lookup_str_vec(file, &nval, "%s.integrates", section);
3828  BV_CLR_ALL(proad->integrates);
3829  for (j = 0; j < nval; j++) {
3830  const char *sval = slist[j];
3831  struct extra_type *textra = extra_type_by_rule_name(sval);
3832  struct road_type *top = nullptr;
3833 
3834  if (textra != nullptr) {
3835  top = extra_road_get(textra);
3836  }
3837 
3838  if (top == nullptr) {
3839  qCCritical(
3840  ruleset_category,
3841  "\"%s\" road \"%s\" integrates with unknown road \"%s\".",
3842  filename, extra_rule_name(pextra), sval);
3843  ok = false;
3844  break;
3845  } else {
3846  BV_SET(proad->integrates, road_number(top));
3847  }
3848  }
3849  delete[] slist;
3850  slist = nullptr;
3851 
3852  if (!ok) {
3853  break;
3854  }
3855 
3856  slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
3857  BV_CLR_ALL(proad->flags);
3858  for (j = 0; j < nval; j++) {
3859  const char *sval = slist[j];
3860 
3861  if (compat->compat_mode
3862  && !fc_strcasecmp("PreventsOtherRoads", sval)) {
3863  // Nothing to do here
3864  } else if (compat->compat_mode
3865  && !fc_strcasecmp("RequiresBridge", sval)) {
3866  extra_type_iterate(pbridged)
3867  {
3868  if (BV_ISSET(compat_bridged, pbridged->id)) {
3869  BV_SET(pextra->bridged_over, pbridged->id);
3870  }
3871  }
3873  } else {
3874  enum road_flag_id flag = road_flag_id_by_name(sval, fc_strcasecmp);
3875 
3876  if (!road_flag_id_is_valid(flag)) {
3877  qCCritical(ruleset_category,
3878  "\"%s\" road \"%s\": unknown flag \"%s\".", filename,
3879  extra_rule_name(pextra), sval);
3880  ok = false;
3881  break;
3882  } else {
3883  BV_SET(proad->flags, flag);
3884  }
3885  }
3886  }
3887  delete[] slist;
3888  slist = nullptr;
3889 
3890  if (!ok) {
3891  break;
3892  }
3893  }
3895 
3896  for (j = 0; ok && j < game.control.num_road_types; j++) {
3897  const char *section = road_sections[j];
3898  const char *extra_name = secfile_lookup_str(file, "%s.extra", section);
3899  struct extra_type *pextra = extra_type_by_rule_name(extra_name);
3900 
3901  if (!is_extra_caused_by(pextra, EC_ROAD)) {
3902  qCCritical(ruleset_category,
3903  "\"%s\" road section [%s]: extra \"%s\" does not have "
3904  "\"Road\" in its causes",
3905  filename, section, extra_name);
3906  ok = false;
3907  }
3908  }
3909  }
3910 
3911  if (ok) {
3912  extra_type_iterate(pextra)
3913  {
3914  pextra->bridged = extra_type_list_new();
3915  extra_type_iterate(pbridged)
3916  {
3917  if (BV_ISSET(pextra->bridged_over, pbridged->id)) {
3918  extra_type_list_append(pextra->bridged, pbridged);
3919  }
3920  }
3922  }
3924  }
3925 
3926  if (ok) {
3927  secfile_check_unused(file);
3928  }
3929 
3930  return ok;
3931 }
3932 
3937 static bool load_government_names(struct section_file *file,
3938  struct rscompat_info *compat)
3939 {
3940  int nval = 0;
3941  struct section_list *sec;
3942  const char *filename = secfile_name(file);
3943  bool ok = true;
3944 
3945  compat->ver_governments =
3946  rscompat_check_capabilities(file, filename, compat);
3947  if (compat->ver_governments <= 0) {
3948  return false;
3949  }
3950 
3951  (void) secfile_entry_by_path(file, "datafile.description"); // unused
3952  (void) secfile_entry_by_path(file, "datafile.ruledit"); // unused
3953 
3955  if (nullptr == sec || 0 == (nval = section_list_size(sec))) {
3956  qCCritical(ruleset_category, "\"%s\": No governments?!?", filename);
3957  ok = false;
3958  } else if (nval > G_LAST) {
3959  qCCritical(ruleset_category, "\"%s\": Too many governments (%d, max %d)",
3960  filename, nval, G_LAST);
3961  ok = false;
3962  }
3963 
3964  if (ok) {
3965  governments_alloc(nval);
3966 
3967  /* Government names are needed early so that get_government_by_name will
3968  * work. */
3969  for (auto &gov : governments) {
3970  const char *sec_name =
3971  section_name(section_list_get(sec, government_index(&gov)));
3972 
3973  if (!ruleset_load_names(&gov.name, nullptr, file, sec_name)) {
3974  ok = false;
3975  break;
3976  }
3977  };
3978  }
3979 
3980  section_list_destroy(sec);
3981 
3982  if (ok) {
3984  nval = (nullptr != sec ? section_list_size(sec) : 0);
3985 
3986  if (nval > MAX_NUM_MULTIPLIERS) {
3987  qCCritical(ruleset_category,
3988  "\"%s\": Too many multipliers (%d, max %d)", filename, nval,
3990 
3991  ok = false;
3992  } else {
3993  game.control.num_multipliers = nval;
3994  }
3995 
3996  if (ok) {
3997  multipliers_iterate(pmul)
3998  {
3999  const char *sec_name =
4000  section_name(section_list_get(sec, multiplier_index(pmul)));
4001 
4002  if (!ruleset_load_names(&pmul->name, nullptr, file, sec_name)) {
4003  qCCritical(ruleset_category,
4004  "\"%s\": Cannot load multiplier names", filename);
4005  ok = false;
4006  break;
4007  }
4008  }
4010  }
4011  section_list_destroy(sec);
4012  }
4013 
4014  return ok;
4015 }
4016 
4020 static bool load_ruleset_governments(struct section_file *file,
4021  struct rscompat_info *compat)
4022 {
4023  struct section_list *sec;
4024  const char *filename = secfile_name(file);
4025  bool ok = true;
4026 
4028 
4030  file, "governments.during_revolution", filename, nullptr);
4031  if (game.government_during_revolution == nullptr) {
4032  ok = false;
4033  }
4034 
4035  if (ok) {
4036  game.info.government_during_revolution_id =
4038 
4039  // easy ones:
4040  for (auto &g : governments) {
4041  const int i = government_index(&g);
4042  const char *sec_name = section_name(section_list_get(sec, i));
4043  struct requirement_vector *reqs = lookup_req_list(
4044  file, compat, sec_name, "reqs", government_rule_name(&g));
4045 
4046  if (reqs == nullptr) {
4047  ok = false;
4048  break;
4049  }
4050 
4051  if (nullptr != secfile_entry_lookup(file, "%s.ai_better", sec_name)) {
4052  char entry[100];
4053 
4054  fc_snprintf(entry, sizeof(entry), "%s.ai_better", sec_name);
4055  g.ai.better = lookup_government(file, entry, filename, nullptr);
4056  if (g.ai.better == nullptr) {
4057  ok = false;
4058  break;
4059  }
4060  } else {
4061  g.ai.better = nullptr;
4062  }
4063  requirement_vector_copy(&g.reqs, reqs);
4064 
4065  sz_strlcpy(g.graphic_str,
4066  secfile_lookup_str(file, "%s.graphic", sec_name));
4067  sz_strlcpy(g.graphic_alt,
4068  secfile_lookup_str(file, "%s.graphic_alt", sec_name));
4069 
4070  g.helptext = lookup_strvec(file, sec_name, "helptext");
4071  } // iterate governments - g
4072  }
4073 
4074  if (ok) {
4075  // titles
4076  for (auto &g : governments) {
4077  const char *sec_name =
4078  section_name(section_list_get(sec, government_index(&g)));
4079  const char *male, *female;
4080 
4081  if (!(male = secfile_lookup_str(file, "%s.ruler_male_title", sec_name))
4082  || !(female = secfile_lookup_str(file, "%s.ruler_female_title",
4083  sec_name))) {
4084  qCCritical(ruleset_category,
4085  "Lack of default ruler titles for "
4086  "government \"%s\" (nb %d): %s",
4088  secfile_error());
4089  ok = false;
4090  break;
4091  } else if (nullptr
4092  == government_ruler_title_new(&g, nullptr, male, female)) {
4093  qCCritical(ruleset_category,
4094  "Lack of default ruler titles for "
4095  "government \"%s\" (nb %d).",
4097  ok = false;
4098  break;
4099  }
4100  } // iterate governments - g
4101  }
4102 
4103  section_list_destroy(sec);
4104 
4105  if (ok) {
4107  multipliers_iterate(pmul)
4108  {
4109  int id = multiplier_index(pmul);
4110  const char *sec_name = section_name(section_list_get(sec, id));
4111  struct requirement_vector *reqs;
4112 
4113  if (!secfile_lookup_int(file, &pmul->start, "%s.start", sec_name)) {
4114  qCCritical(ruleset_category, "Error: %s", secfile_error());
4115  ok = false;
4116  break;
4117  }
4118  if (!secfile_lookup_int(file, &pmul->stop, "%s.stop", sec_name)) {
4119  qCCritical(ruleset_category, "Error: %s", secfile_error());
4120  ok = false;
4121  break;
4122  }
4123  if (pmul->stop <= pmul->start) {
4124  qCCritical(ruleset_category,
4125  "Multiplier \"%s\" stop (%d) must be greater "
4126  "than start (%d)",
4127  multiplier_rule_name(pmul), pmul->stop, pmul->start);
4128  ok = false;
4129  break;
4130  }
4131  if (!secfile_lookup_int(file, &pmul->step, "%s.step", sec_name)) {
4132  qCCritical(ruleset_category, "Error: %s", secfile_error());
4133  ok = false;
4134  break;
4135  }
4136  if (((pmul->stop - pmul->start) % pmul->step) != 0) {
4137  qCCritical(ruleset_category,
4138  "Multiplier \"%s\" step (%d) does not fit "
4139  "exactly into interval start-stop (%d to %d)",
4140  multiplier_rule_name(pmul), pmul->step, pmul->start,
4141  pmul->stop);
4142  ok = false;
4143  break;
4144  }
4145  if (!secfile_lookup_int(file, &pmul->def, "%s.default", sec_name)) {
4146  qCCritical(ruleset_category, "Error: %s", secfile_error());
4147  ok = false;
4148  break;
4149  }
4150  if (pmul->def < pmul->start || pmul->def > pmul->stop) {
4151  qCCritical(ruleset_category,
4152  "Multiplier \"%s\" default (%d) not within "
4153  "legal range (%d to %d)",
4154  multiplier_rule_name(pmul), pmul->def, pmul->start,
4155  pmul->stop);
4156  ok = false;
4157  break;
4158  }
4159  if (((pmul->def - pmul->start) % pmul->step) != 0) {
4160  qCCritical(ruleset_category,
4161  "Multiplier \"%s\" default (%d) not legal "
4162  "with respect to step size %d",
4163  multiplier_rule_name(pmul), pmul->def, pmul->step);
4164  ok = false;
4165  break;
4166  }
4167  pmul->offset =
4168  secfile_lookup_int_default(file, 0, "%s.offset", sec_name);
4169  pmul->factor =
4170  secfile_lookup_int_default(file, 100, "%s.factor", sec_name);
4171  if (pmul->factor == 0) {
4172  qCCritical(ruleset_category,
4173  "Multiplier \"%s\" scaling factor must "
4174  "not be zero",
4175  multiplier_rule_name(pmul));
4176  ok = false;
4177  break;
4178  }
4179 
4180  reqs = lookup_req_list(file, compat, sec_name, "reqs",
4181  multiplier_rule_name(pmul));
4182  if (reqs == nullptr) {
4183  ok = false;
4184  break;
4185  }
4186  requirement_vector_copy(&pmul->reqs, reqs);
4187 
4188  pmul->helptext = lookup_strvec(file, sec_name, "helptext");
4189  }
4191  section_list_destroy(sec);
4192  }
4193 
4194  if (ok) {
4195  secfile_check_unused(file);
4196  }
4197 
4198  return ok;
4199 }
4200 
4212 static void send_ruleset_control(struct conn_list *dest)
4213 {
4214  int desc_left = game.control.desc_length;
4215  int idx = 0;
4216 
4217  lsend_packet_ruleset_control(dest, &(game.control));
4218 
4219  if (game.ruleset_summary != nullptr) {
4220  struct packet_ruleset_summary summary;
4221 
4222  sz_strlcpy(summary.text, game.ruleset_summary);
4223 
4224  lsend_packet_ruleset_summary(dest, &summary);
4225  }
4226 
4227  while (desc_left > 0) {
4228  struct packet_ruleset_description_part part;
4229  int this_len = desc_left;
4230 
4231  if (this_len > MAX_LEN_CONTENT - 21) {
4232  this_len = MAX_LEN_CONTENT - 1;
4233  }
4234 
4235  part.text[this_len] = '\0';
4236 
4237  qstrncpy(part.text, &game.ruleset_description[idx], this_len);
4238  idx += this_len;
4239  desc_left -= this_len;
4240 
4241  lsend_packet_ruleset_description_part(dest, &part);
4242  }
4243 }
4244 
4250 static const char *check_leader_names(struct nation_type *pnation)
4251 {
4252  nation_leader_list_iterate(nation_leaders(pnation), pleader)
4253  {
4254  const char *name = nation_leader_name(pleader);
4255 
4256  nation_leader_list_iterate(nation_leaders(pnation), prev_leader)
4257  {
4258  if (prev_leader == pleader) {
4259  break;
4260  } else if (0 == fc_strcasecmp(name, nation_leader_name(prev_leader))) {
4261  return name;
4262  }
4263  }
4265  }
4267  return nullptr;
4268 }
4269 
4274 static bool load_nation_names(struct section_file *file,
4275  struct rscompat_info *compat)
4276 {
4277  struct section_list *sec;
4278  int j;
4279  bool ok = true;
4280  const char *filename = secfile_name(file);
4281 
4282  compat->ver_nations = rscompat_check_capabilities(file, filename, compat);
4283  if (compat->ver_nations <= 0) {
4284  return false;
4285  }
4286 
4287  (void) secfile_entry_by_path(file, "datafile.description"); // unused
4288  (void) secfile_entry_by_path(file, "datafile.ruledit"); // unused
4289 
4291  if (nullptr == sec) {
4292  qCCritical(ruleset_category, "No available nations in this ruleset!");
4293  ok = false;
4294  } else if (section_list_size(sec) > MAX_NUM_NATIONS) {
4295  qCCritical(ruleset_category, "Too many nations (max %d, we have %d)!",
4296  MAX_NUM_NATIONS, section_list_size(sec));
4297  ok = false;
4298  } else {
4299  game.control.nation_count = section_list_size(sec);
4300  nations_alloc(game.control.nation_count);
4301 
4302  for (auto &pl : nations) {
4303  const int i = nation_index(&pl);
4304  const char *sec_name = section_name(section_list_get(sec, i));
4305  const char *domain = secfile_lookup_str_default(
4306  file, nullptr, "%s.translation_domain", sec_name);
4307  const char *noun_plural =
4308  secfile_lookup_str(file, "%s.plural", sec_name);
4309 
4310  if (domain == nullptr) {
4311  domain = "freeciv-nations";
4312  }
4313 
4314  if (!strcmp("freeciv", domain)) {
4315  pl.translation_domain = nullptr;
4316  } else if (!strcmp("freeciv-nations", domain)) {
4317  pl.translation_domain = new char[strlen(domain) + 1];
4318  qstrcpy(pl.translation_domain, domain);
4319  } else {
4320  qCCritical(ruleset_category,
4321  "Unsupported translation domain \"%s\" for %s", domain,
4322  sec_name);
4323  ok = false;
4324  break;
4325  }
4326 
4327  if (!ruleset_load_names(&pl.adjective, domain, file, sec_name)) {
4328  ok = false;
4329  break;
4330  }
4331  name_set(&pl.noun_plural, domain, noun_plural);
4332 
4333  // Check if nation name is already defined.
4334  for (j = 0; j < i && ok; j++) {
4335  struct nation_type *n2 = nation_by_number(j);
4336 
4337  /* Compare strings after stripping off qualifiers -- we don't want
4338  * two nations to end up with identical adjectives displayed to
4339  * users. (This check only catches English, not localisations, of
4340  * course.) */
4341  if (0
4342  == strcmp(Qn_(untranslated_name(&n2->adjective)),
4343  Qn_(untranslated_name(&pl.adjective)))) {
4344  qCCritical(ruleset_category,
4345  "Two nations defined with the same adjective \"%s\": "
4346  "in section \'%s\' and section \'%s\'",
4347  Qn_(untranslated_name(&pl.adjective)),
4348  section_name(section_list_get(sec, j)), sec_name);
4349  ok = false;
4350  } else if (!strcmp(rule_name_get(&n2->adjective),
4351  rule_name_get(&pl.adjective))) {
4352  /* We cannot have the same rule name, as the game needs them to
4353  * be distinct. */
4354  qCCritical(ruleset_category,
4355  "Two nations defined with the same rule_name \"%s\": "
4356  "in section \'%s\' and section \'%s\'",
4357  rule_name_get(&pl.adjective),
4358  section_name(section_list_get(sec, j)), sec_name);
4359  ok = false;
4360  } else if (0
4361  == strcmp(Qn_(untranslated_name(&n2->noun_plural)),
4362  Qn_(untranslated_name(&pl.noun_plural)))) {
4363  // We don't want identical English plural names either.
4364  qCCritical(ruleset_category,
4365  "Two nations defined with the same plural name \"%s\": "
4366  "in section \'%s\' and section \'%s\'",
4367  Qn_(untranslated_name(&pl.noun_plural)),
4368  section_name(section_list_get(sec, j)), sec_name);
4369  ok = false;
4370  }
4371  }
4372  if (!ok) {
4373  break;
4374  }
4375  }
4376  }
4377 
4378  section_list_destroy(sec);
4379 
4380  if (ok) {
4382  if (sec) {
4383  section_list_iterate(sec, psection)
4384  {
4385  struct nation_group *pgroup;
4386  const char *name;
4387 
4388  name = secfile_lookup_str(file, "%s.name", section_name(psection));
4389  if (nullptr == name) {
4390  qCCritical(ruleset_category, "Error: %s", secfile_error());
4391  ok = false;
4392  break;
4393  }
4394  pgroup = nation_group_new(name);
4395  if (pgroup == nullptr) {
4396  ok = false;
4397  break;
4398  }
4399  }
4401  section_list_destroy(sec);
4402  sec = nullptr;
4403  }
4404  }
4405 
4406  return ok;
4407 }
4408 
4412 static bool is_on_allowed_list(const char *name, const char **list,
4413  size_t len)
4414 {
4415  int i;
4416 
4417  for (i = 0; i < len; i++) {
4418  if (!fc_strcasecmp(name, list[i])) {
4419  return true;
4420  }
4421  }
4422  return false;
4423 }
4424 
4429 static bool
4430 load_city_name_list(struct section_file *file, struct nation_type *pnation,
4431  const char *secfile_str1, const char *secfile_str2,
4432  const char **allowed_terrains, size_t atcount)
4433 {
4434  size_t dim, j;
4435  bool ok = true;
4436  const char **cities = secfile_lookup_str_vec(file, &dim, "%s.%s",
4437  secfile_str1, secfile_str2);
4438 
4439  /* Each string will be of the form "<cityname> (<label>, <label>, ...)".
4440  * The cityname is just the name for this city, while each "label" matches
4441  * a terrain type for the city (or "river"), with a preceeding ! to negate
4442  * it. The parentheses are optional (but necessary to have the settings,
4443  * of course). Our job is now to parse it. */
4444  for (j = 0; j < dim; j++) {
4445  size_t len = qstrlen(cities[j]);
4446  char city_name[len + 1], *p, *next, *end;
4447  struct nation_city *pncity;
4448 
4449  sz_strlcpy(city_name, cities[j]);
4450 
4451  /* Now we wish to determine values for all of the city labels. A value
4452  * of NCP_NONE means no preference (which is necessary so that the use
4453  * of this is optional); NCP_DISLIKE means the label is negated and
4454  * NCP_LIKE means it's labelled. Mostly the parsing just involves
4455  * a lot of ugly string handling... */
4456  if ((p = strchr(city_name, '('))) {
4457  *p++ = '\0';
4458 
4459  if (!(end = strchr(p, ')'))) {
4460  qCCritical(ruleset_category,
4461  "\"%s\" [%s] %s: city name \"%s\" "
4462  "unmatched parenthesis.",
4463  secfile_name(file), secfile_str1, secfile_str2,
4464  cities[j]);
4465  ok = false;
4466  } else {
4467  for (*end++ = '\0'; '\0' != *end; end++) {
4468  if (!QChar::isSpace(*end)) {
4469  qCCritical(ruleset_category,
4470  "\"%s\" [%s] %s: city name \"%s\" "
4471  "contains characters after last parenthesis.",
4472  secfile_name(file), secfile_str1, secfile_str2,
4473  cities[j]);
4474  ok = false;
4475  break;
4476  }
4477  }
4478  }
4479  }
4480 
4481  // Build the nation_city.
4482  remove_leading_trailing_spaces(city_name);
4483  if (check_cityname(city_name)) {
4484  /* The ruleset contains a name that is too long. This shouldn't
4485  * happen - if it does, the author should get immediate feedback. */
4486  qCCritical(ruleset_category,
4487  "\"%s\" [%s] %s: city name \"%s\" "
4488  "is too long.",
4489  secfile_name(file), secfile_str1, secfile_str2, city_name);
4490  ok = false;
4491  city_name[MAX_LEN_CITYNAME - 1] = '\0';
4492  }
4493  pncity = nation_city_new(pnation, city_name);
4494 
4495  if (nullptr != p) {
4496  // Handle the labels one at a time.
4497  do {
4498  enum nation_city_preference prefer;
4499 
4500  if ((next = strchr(p, ','))) {
4501  *next = '\0';
4502  }
4504 
4505  /* The ! is used to mark a negative, which is recorded with
4506  * NCP_DISLIKE. Otherwise we use a NCP_LIKE.
4507  */
4508  if (*p == '!') {
4509  p++;
4510  prefer = NCP_DISLIKE;
4511  } else {
4512  prefer = NCP_LIKE;
4513  }
4514 
4515  if (0 == fc_strcasecmp(p, "river")) {
4516  if (game.server.ruledit.allowed_terrains != nullptr
4517  && !is_on_allowed_list(p, game.server.ruledit.allowed_terrains,
4518  atcount)) {
4519  qCCritical(ruleset_category,
4520  "\"%s\" [%s] %s: city \"%s\" "
4521  "has terrain hint \"%s\" not in allowed_terrains.",
4522  secfile_name(file), secfile_str1, secfile_str2,
4523  city_name, p);
4524  ok = false;
4525  } else {
4526  nation_city_set_river_preference(pncity, prefer);
4527  }
4528  } else {
4529  const struct terrain *pterrain = terrain_by_rule_name(p);
4530 
4531  if (nullptr == pterrain) {
4532  // Try with removing frequent trailing 's'.
4533  size_t l = qstrlen(p);
4534 
4535  if (0 < l && 's' == QChar::toLower(p[l - 1])) {
4536  char saved = p[l - 1];
4537 
4538  p[l - 1] = '\0';
4539  pterrain = terrain_by_rule_name(p);
4540  if (pterrain == nullptr) {
4541  // Didn't help, restore for later allowed_terrains check
4542  p[l - 1] = saved;
4543  }
4544  }
4545  }
4546 
4547  /* Nationset may have been devised with a specific set of terrains
4548  * in mind which don't quite match this ruleset, in which case we
4549  * (a) quietly ignore any hints mentioned that don't happen to be
4550  * in the current ruleset, (b) enforce that terrains mentioned by
4551  * nations must be on the list */
4552  if (pterrain != nullptr
4553  && game.server.ruledit.allowed_terrains != nullptr) {
4554  if (!is_on_allowed_list(p, game.server.ruledit.allowed_terrains,
4555  atcount)) {
4556  // Terrain exists, but not intended for these nations
4557  qCCritical(ruleset_category,
4558  "\"%s\" [%s] %s: city \"%s\" "
4559  "has terrain hint \"%s\" not in allowed_terrains.",
4560  secfile_name(file), secfile_str1, secfile_str2,
4561  city_name, p);
4562  ok = false;
4563  break;
4564  }
4565  } else if (!pterrain) {
4566  /* Terrain doesn't exist; only complain if it's not on any list
4567  */
4568  if (game.server.ruledit.allowed_terrains == nullptr
4569  || !is_on_allowed_list(
4570  p, game.server.ruledit.allowed_terrains, atcount)) {
4571  qCCritical(ruleset_category,
4572  "\"%s\" [%s] %s: city \"%s\" "
4573  "has unknown terrain hint \"%s\".",
4574  secfile_name(file), secfile_str1, secfile_str2,
4575  city_name, p);
4576  ok = false;
4577  break;
4578  }
4579  }
4580  if (nullptr != pterrain) {
4581  nation_city_set_terrain_preference(pncity, pterrain, prefer);
4582  }
4583  }
4584 
4585  p = next ? next + 1 : nullptr;
4586  } while (nullptr != p && '\0' != *p);
4587  }
4588  }
4589  delete[] cities;
4590  cities = nullptr;
4591  return ok;
4592 }
4593 
4597 static bool load_ruleset_nations(struct section_file *file,
4598  struct rscompat_info *compat)
4599 {
4600  struct government *gov;
4601  int j;
4602  size_t dim;
4603  char temp_name[MAX_LEN_NAME];
4604  const char **vec;
4605  const char *name, *bad_leader;
4606  const char *sval;
4607  int default_set;
4608  const char *filename = secfile_name(file);
4609  struct section_list *sec = nullptr;
4610  enum trait tr;
4611  bool ok = true;
4612 
4613  name = secfile_lookup_str_default(file, nullptr, "ruledit.nationlist");
4614  if (name != nullptr) {
4615  game.server.ruledit.nationlist = fc_strdup(name);
4616  }
4617  vec = secfile_lookup_str_vec(file,
4618  &game.server.ruledit.embedded_nations_count,
4619  "ruledit.embedded_nations");
4620 
4621  if (vec != nullptr) {
4622  // Copy to persistent vector
4623  game.server.ruledit.embedded_nations =
4624  new char *[game.server.ruledit.embedded_nations_count];
4625 
4626  for (j = 0; j < game.server.ruledit.embedded_nations_count; j++) {
4627  game.server.ruledit.embedded_nations[j] = fc_strdup(vec[j]);
4628  }
4629 
4630  delete[] vec;
4631  vec = nullptr;
4632  }
4633 
4634  game.default_government = nullptr;
4635 
4636  ruleset_load_traits(game.server.default_traits, file, "default_traits",
4637  "");
4638  for (tr = trait_begin(); tr != trait_end(); tr = trait_next(tr)) {
4639  if (game.server.default_traits[tr].min < 0) {
4640  game.server.default_traits[tr].min = TRAIT_DEFAULT_VALUE;
4641  }
4642  if (game.server.default_traits[tr].max < 0) {
4643  game.server.default_traits[tr].max = TRAIT_DEFAULT_VALUE;
4644  }
4645  if (game.server.default_traits[tr].fixed < 0) {
4646  int diff = game.server.default_traits[tr].max
4647  - game.server.default_traits[tr].min;
4648 
4649  /* TODO: Should sometimes round the a / 2 = x.5 results up */
4650  game.server.default_traits[tr].fixed =
4651  diff / 2 + game.server.default_traits[tr].min;
4652  }
4653  if (game.server.default_traits[tr].max
4654  < game.server.default_traits[tr].min) {
4655  qCCritical(ruleset_category, "Default values for trait %s not sane.",
4656  trait_name(tr));
4657  ok = false;
4658  break;
4659  }
4660  }
4661 
4662  if (ok) {
4663  vec = secfile_lookup_str_vec(file, &game.server.ruledit.ag_count,
4664  "compatibility.allowed_govs");
4665  if (vec != nullptr) {
4666  // Copy to persistent vector
4667  game.server.ruledit.nc_agovs =
4668  new char *[game.server.ruledit.ag_count];
4669  game.server.ruledit.allowed_govs =
4670  (const char **) game.server.ruledit.nc_agovs;
4671 
4672  for (j = 0; j < game.server.ruledit.ag_count; j++) {
4673  game.server.ruledit.allowed_govs[j] = fc_strdup(vec[j]);
4674  }
4675 
4676  delete[] vec;
4677  vec = nullptr;
4678  }
4679 
4680  vec = secfile_lookup_str_vec(file, &game.server.ruledit.at_count,
4681  "compatibility.allowed_terrains");
4682  if (vec != nullptr) {
4683  // Copy to persistent vector
4684  game.server.ruledit.nc_aterrs =
4685  new char *[game.server.ruledit.at_count];
4686  game.server.ruledit.allowed_terrains =
4687  (const char **) game.server.ruledit.nc_aterrs;
4688 
4689  for (j = 0; j < game.server.ruledit.at_count; j++) {
4690  game.server.ruledit.allowed_terrains[j] = fc_strdup(vec[j]);
4691  }
4692 
4693  delete[] vec;
4694  vec = nullptr;
4695  }
4696 
4697  vec = secfile_lookup_str_vec(file, &game.server.ruledit.as_count,
4698  "compatibility.allowed_styles");
4699  if (vec != nullptr) {
4700  // Copy to persistent vector
4701  game.server.ruledit.nc_astyles =
4702  new char *[game.server.ruledit.as_count];
4703  game.server.ruledit.allowed_styles =
4704  (const char **) game.server.ruledit.nc_astyles;
4705 
4706  for (j = 0; j < game.server.ruledit.as_count; j++) {
4707  game.server.ruledit.allowed_styles[j] = fc_strdup(vec[j]);
4708  }
4709 
4710  delete[] vec;
4711  vec = nullptr;
4712  }
4713 
4714  sval = secfile_lookup_str_default(file, nullptr,
4715  "compatibility.default_government");
4716  /* We deliberately don't check this against allowed_govs. It's only
4717  * specified once so not vulnerable to typos, and may usefully be set in
4718  * a specific ruleset to a gov not explicitly known by the nation set. */
4719  if (sval != nullptr) {
4721  if (game.default_government == nullptr) {
4722  qCCritical(ruleset_category,
4723  "Tried to set unknown government type \"%s\" as "
4724  "default_government!",
4725  sval);
4726  ok = false;
4727  } else {
4728  game.info.default_government_id =
4730  }
4731  }
4732  }
4733 
4734  if (ok) {
4736  if (sec) {
4737  section_list_iterate(sec, psection)
4738  {
4739  const char *set_name, *set_rule_name, *set_description;
4740 
4741  set_name =
4742  secfile_lookup_str(file, "%s.name", section_name(psection));
4743  set_rule_name =
4744  secfile_lookup_str(file, "%s.rule_name", section_name(psection));
4745  set_description = secfile_lookup_str_default(
4746  file, "", "%s.description", section_name(psection));
4747  if (nullptr == set_name || nullptr == set_rule_name) {
4748  qCCritical(ruleset_category, "Error: %s", secfile_error());
4749  ok = false;
4750  break;
4751  }
4752  if (nation_set_new(set_name, set_rule_name, set_description)
4753  == nullptr) {
4754  ok = false;
4755  break;
4756  }
4757  }
4759  section_list_destroy(sec);
4760  sec = nullptr;
4761  } else {
4762  qCCritical(ruleset_category,
4763  "At least one nation set [" NATION_SET_SECTION_PREFIX "_*] "
4764  "must be defined.");
4765  ok = false;
4766  }
4767  }
4768 
4769  if (ok) {
4770  // Default set that every nation is a member of.
4771  sval = secfile_lookup_str_default(file, nullptr,
4772  "compatibility.default_nationset");
4773  if (sval != nullptr) {
4774  const struct nation_set *pset = nation_set_by_rule_name(sval);
4775  if (pset != nullptr) {
4776  default_set = nation_set_number(pset);
4777  } else {
4778  qCCritical(ruleset_category, "Unknown default_nationset \"%s\".",
4779  sval);
4780  ok = false;
4781  }
4782  } else if (nation_set_count() == 1) {
4783  /* If there's only one set defined, every nation is implicitly a
4784  * member of that set. */
4785  default_set = 0;
4786  } else {
4787  /* No default nation set; every nation must explicitly specify at
4788  * least one set to be a member of. */
4789  default_set = -1;
4790  }
4791  }
4792 
4793  if (ok) {
4795  if (sec) {
4796  section_list_iterate(sec, psection)
4797  {
4798  struct nation_group *pgroup;
4799  bool hidden;
4800 
4801  name = secfile_lookup_str(file, "%s.name", section_name(psection));
4802  pgroup = nation_group_by_rule_name(name);
4803  if (pgroup == nullptr) {
4804  ok = false;
4805  break;
4806  }
4807 
4808  hidden = secfile_lookup_bool_default(file, false, "%s.hidden",
4809  section_name(psection));
4811 
4812  if (!secfile_lookup_int(file, &j, "%s.match",
4813  section_name(psection))) {
4814  qCCritical(ruleset_category, "Error: %s", secfile_error());
4815  ok = false;
4816  break;
4817  }
4818  nation_group_set_match(pgroup, j);
4819  }
4821  section_list_destroy(sec);
4822  sec = nullptr;
4823  }
4824  }
4825 
4826  if (ok) {
4828  for (auto &pnation : nations) {
4829  struct nation_type *pconflict;
4830  const int i = nation_index(&pnation);
4831  char tmp[200] = "\0";
4832  const char *barb_type;
4833  const char *sec_name = section_name(section_list_get(sec, i));
4834  const char *legend;
4835 
4836  // Nation sets and groups.
4837  if (default_set >= 0) {
4838  nation_set_list_append(pnation.sets,
4839  nation_set_by_number(default_set));
4840  }
4841  vec = secfile_lookup_str_vec(file, &dim, "%s.groups", sec_name);
4842  for (j = 0; j < dim; j++) {
4843  struct nation_set *pset = nation_set_by_rule_name(vec[j]);
4844  struct nation_group *pgroup = nation_group_by_rule_name(vec[j]);
4845 
4846  fc_assert(pset == nullptr || pgroup == nullptr);
4847 
4848  if (nullptr != pset) {
4849  nation_set_list_append(pnation.sets, pset);
4850  } else if (nullptr != pgroup) {
4851  nation_group_list_append(pnation.groups, pgroup);
4852  } else {
4853  /* For nation authors, this would probably be considered an
4854  * error. But it can happen normally. The civ1 compatibility
4855  * ruleset only uses the nations that were in civ1, so not all of
4856  * the links will exist. */
4857  qCDebug(ruleset_category, "Nation %s: Unknown set/group \"%s\".",
4858  nation_rule_name(&pnation), vec[j]);
4859  }
4860  }
4861  delete[] vec;
4862  vec = nullptr;
4863  if (nation_set_list_size(pnation.sets) < 1) {
4864  qCCritical(ruleset_category,
4865  "Nation %s is not a member of any nation set",
4866  nation_rule_name(&pnation));
4867  ok = false;
4868  break;
4869  }
4870 
4871  // Nation conflicts.
4872  vec =
4873  secfile_lookup_str_vec(file, &dim, "%s.conflicts_with", sec_name);
4874  for (j = 0; j < dim; j++) {
4875  pconflict = nation_by_rule_name(vec[j]);
4876 
4877  if (&pnation == pconflict) {
4878  qCCritical(ruleset_category, "Nation %s conflicts with itself",
4879  nation_rule_name(&pnation));
4880  ok = false;
4881  break;
4882  } else if (nullptr != pconflict) {
4883  nation_list_append(pnation.server.conflicts_with, pconflict);
4884  } else {
4885  /* For nation authors, this would probably be considered an
4886  * error. But it can happen normally. The civ1 compatibility
4887  * ruleset only uses the nations that were in civ1, so not all of
4888  * the links will exist. */
4889  qCDebug(ruleset_category,
4890  "Nation %s: conflicts_with nation \"%s\" is unknown.",
4891  nation_rule_name(&pnation), vec[j]);
4892  }
4893  }
4894  delete[] vec;
4895  vec = nullptr;
4896  if (!ok) {
4897  break;
4898  }
4899 
4900  // Nation leaders.
4901  for (j = 0; j < MAX_NUM_LEADERS; j++) {
4902  const char *sex;
4903  bool is_male = false;
4904 
4905  name = secfile_lookup_str(file, "%s.leaders%d.name", sec_name, j);
4906  if (nullptr == name) {
4907  // No more to read.
4908  break;
4909  }
4910 
4911  if (check_name(name)) {
4912  /* The ruleset contains a name that is too long. This shouldn't
4913  * happen - if it does, the author should get immediate feedback
4914  */
4915  sz_strlcpy(temp_name, name);
4916  qCCritical(ruleset_category,
4917  "Nation %s: leader name \"%s\" "
4918  "is too long.",
4919  nation_rule_name(&pnation), name);
4920  ok = false;
4921  break;
4922  }
4923 
4924  sex = secfile_lookup_str(file, "%s.leaders%d.sex", sec_name, j);
4925  if (nullptr == sex) {
4926  qCCritical(ruleset_category, "Nation %s: leader \"%s\": %s.",
4927  nation_rule_name(&pnation), name, secfile_error());
4928  ok = false;
4929  break;
4930  } else if (0 == fc_strcasecmp("Male", sex)) {
4931  is_male = true;
4932  } else if (0 != fc_strcasecmp("Female", sex)) {
4933  qCCritical(ruleset_category,
4934  "Nation %s: leader \"%s\" has unsupported "
4935  "sex variant \"%s\".",
4936  nation_rule_name(&pnation), name, sex);
4937  ok = false;
4938  break;
4939  }
4940  (void) nation_leader_new(&pnation, name, is_male);
4941  }
4942  if (!ok) {
4943  break;
4944  }
4945 
4946  // Check the number of leaders.
4947  if (MAX_NUM_LEADERS == j) {
4948  // Too much leaders, get the real number defined in the ruleset.
4949  while (nullptr
4950  != secfile_entry_lookup(file, "%s.leaders%d.name", sec_name,
4951  j)) {
4952  j++;
4953  }
4954  qCCritical(ruleset_category,
4955  "Nation %s: Too many leaders; max is %d",
4956  nation_rule_name(&pnation), MAX_NUM_LEADERS);
4957  ok = false;
4958  break;
4959  } else if (0 == j) {
4960  qCCritical(ruleset_category,
4961  "Nation %s: no leaders; at least one is required.",
4962  nation_rule_name(&pnation));
4963  ok = false;
4964  break;
4965  }
4966 
4967  // Check if leader name is not already defined in this nation.
4968  if ((bad_leader = check_leader_names(&pnation))) {
4969  qCCritical(ruleset_category,
4970  "Nation %s: leader \"%s\" defined more than once.",
4971  nation_rule_name(&pnation), bad_leader);
4972  ok = false;
4973  break;
4974  }
4975 
4976  // Nation player color preference, if any
4977  fc_assert_ret_val(pnation.server.rgb == nullptr, false);
4978  (void) rgbcolor_load(file, &pnation.server.rgb, "%s.color", sec_name);
4979 
4980  // Load nation traits
4981  ruleset_load_traits(pnation.server.traits, file, sec_name, "trait_");
4982  for (tr = trait_begin(); tr != trait_end(); tr = trait_next(tr)) {
4983  bool server_traits_used = true;
4984 
4985  if (pnation.server.traits[tr].min < 0) {
4986  pnation.server.traits[tr].min = game.server.default_traits[tr].min;
4987  } else {
4988  server_traits_used = false;
4989  }
4990  if (pnation.server.traits[tr].max < 0) {
4991  pnation.server.traits[tr].max = game.server.default_traits[tr].max;
4992  } else {
4993  server_traits_used = false;
4994  }
4995  if (pnation.server.traits[tr].fixed < 0) {
4996  if (server_traits_used) {
4997  pnation.server.traits[tr].fixed =
4998  game.server.default_traits[tr].fixed;
4999  } else {
5000  int diff = pnation.server.traits[tr].max
5001  - pnation.server.traits[tr].min;
5002 
5003  /* TODO: Should sometimes round the a / 2 = x.5 results up */
5004  pnation.server.traits[tr].fixed =
5005  diff / 2 + pnation.server.traits[tr].min;
5006  }
5007  }
5008  if (pnation.server.traits[tr].max < pnation.server.traits[tr].min) {
5009  qCCritical(ruleset_category, "%s values for trait %s not sane.",
5010  nation_rule_name(&pnation), trait_name(tr));
5011  ok = false;
5012  break;
5013  }
5014  }
5015 
5016  if (!ok) {
5017  break;
5018  }
5019 
5020  pnation.is_playable = secfile_lookup_bool_default(
5021  file, true, "%s.is_playable", sec_name);
5022 
5023  // Check barbarian type. Default is "None" meaning not a barbarian
5024  barb_type = secfile_lookup_str_default(file, "None",
5025  "%s.barbarian_type", sec_name);
5026  pnation.barb_type = barbarian_type_by_name(barb_type, fc_strcasecmp);
5027  if (!barbarian_type_is_valid(pnation.barb_type)) {
5028  qCCritical(ruleset_category,
5029  "Nation %s, barbarian_type is invalid (\"%s\")",
5030  nation_rule_name(&pnation), barb_type);
5031  ok = false;
5032  break;
5033  }
5034 
5035  if (pnation.barb_type != NOT_A_BARBARIAN && pnation.is_playable) {
5036  /* We can't allow players to use barbarian nations, barbarians
5037  * may run out of nations */
5038  qCCritical(ruleset_category,
5039  "Nation %s marked both barbarian and playable.",
5040  nation_rule_name(&pnation));
5041  ok = false;
5042  break;
5043  }
5044 
5045  // Flags
5046  sz_strlcpy(pnation.flag_graphic_str,
5047  secfile_lookup_str_default(file, "-", "%s.flag", sec_name));
5048  sz_strlcpy(
5049  pnation.flag_graphic_alt,
5050  secfile_lookup_str_default(file, "-", "%s.flag_alt", sec_name));
5051 
5052  // Ruler titles
5053  for (j = 0;; j++) {
5054  const char *male, *female;
5055 
5057  file, nullptr, "%s.ruler_titles%d.government", sec_name, j);
5058  if (nullptr == name) {
5059  // End of the list of ruler titles.
5060  break;
5061  }
5062 
5063  /* NB: even if the government doesn't exist, we load the entries
5064  * for the ruler titles to avoid warnings about unused entries. */
5065  male = secfile_lookup_str(file, "%s.ruler_titles%d.male_title",
5066  sec_name, j);
5067  female = secfile_lookup_str(file, "%s.ruler_titles%d.female_title",
5068  sec_name, j);
5070 
5071  /* Nationset may have been devised with a specific set of govs in
5072  * mind which don't quite match this ruleset, in which case we
5073  * (a) quietly ignore any govs mentioned that don't happen to be in
5074  * the current ruleset, (b) enforce that govs mentioned by nations
5075  * must be on the list */
5076  if (gov != nullptr && game.server.ruledit.allowed_govs != nullptr) {
5077  if (!is_on_allowed_list(name, game.server.ruledit.allowed_govs,
5078  game.server.ruledit.ag_count)) {
5079  // Gov exists, but not intended for these nations
5080  gov = nullptr;
5081  qCCritical(ruleset_category,
5082  "Nation %s: government \"%s\" not in allowed_govs.",
5083  nation_rule_name(&pnation), name);
5084  ok = false;
5085  break;
5086  }
5087  } else if (!gov) {
5088  // Gov doesn't exist; only complain if it's not on any list
5089  if (game.server.ruledit.allowed_govs == nullptr
5090  || !is_on_allowed_list(name, game.server.ruledit.allowed_govs,
5091  game.server.ruledit.ag_count)) {
5092  qCCritical(ruleset_category,
5093  "Nation %s: government \"%s\" not found.",
5094  nation_rule_name(&pnation), name);
5095  ok = false;
5096  break;
5097  }
5098  }
5099  if (nullptr != male && nullptr != female) {
5100  if (gov) {
5101  (void) government_ruler_title_new(gov, &pnation, male, female);
5102  }
5103  } else {
5104  qCCritical(ruleset_category, "%s", secfile_error());
5105  ok = false;
5106  break;
5107  }
5108  }
5109  if (!ok) {
5110  break;
5111  }
5112 
5113  // City styles
5114  name = secfile_lookup_str(file, "%s.style", sec_name);
5115  if (!name) {
5116  qCCritical(ruleset_category, "%s", secfile_error());
5117  ok = false;
5118  break;
5119  }
5120  pnation.style = style_by_rule_name(name);
5121  if (pnation.style == nullptr) {
5122  if (game.server.ruledit.allowed_styles == nullptr
5123  || !is_on_allowed_list(name, game.server.ruledit.allowed_styles,
5124  game.server.ruledit.as_count)) {
5125  qCCritical(ruleset_category, "Nation %s: Illegal style \"%s\"",
5126  nation_rule_name(&pnation), name);
5127  ok = false;
5128  break;
5129  } else {
5130  qCDebug(ruleset_category,
5131  "Nation %s: style \"%s\" not supported in this "
5132  "ruleset; using default.",
5133  nation_rule_name(&pnation), name);
5134  pnation.style = style_by_number(0);
5135  }
5136  }
5137 
5138  // Civilwar nations
5139  vec = secfile_lookup_str_vec(file, &dim, "%s.civilwar_nations",
5140  sec_name);
5141  for (j = 0; j < dim; j++) {
5142  pconflict = nation_by_rule_name(vec[j]);
5143 
5144  /* No test for duplicate nations is performed. If there is a
5145  * duplicate entry it will just cause that nation to have an
5146  * increased probability of being chosen. */
5147  if (pconflict == &pnation) {
5148  qCCritical(ruleset_category,
5149  "Nation %s is its own civil war nation",
5150  nation_rule_name(&pnation));
5151  ok = false;
5152  break;
5153  } else if (nullptr != pconflict) {
5154  nation_list_append(pnation.server.civilwar_nations, pconflict);
5155  nation_list_append(pconflict->server.parent_nations, &pnation);
5156  } else {
5157  /* For nation authors, this would probably be considered an
5158  * error. But it can happen normally. The civ1 compatability
5159  * ruleset only uses the nations that were in civ1, so not all of
5160  * the links will exist. */
5161  qCDebug(ruleset_category,
5162  "Nation %s: civil war nation \"%s\" is unknown.",
5163  nation_rule_name(&pnation), vec[j]);
5164  }
5165  }
5166  delete[] vec;
5167  vec = nullptr;
5168  if (!ok) {
5169  break;
5170  }
5171 
5172  // Load nation specific initial items
5173  if (!lookup_tech_list(file, sec_name, "init_techs", pnation.init_techs,
5174  filename)) {
5175  ok = false;
5176  break;
5177  }
5178  if (!lookup_building_list(file, sec_name, "init_buildings",
5179  pnation.init_buildings, filename)) {
5180  ok = false;
5181  break;
5182  }
5183  if (!lookup_unit_list(file, sec_name, "init_units", pnation.init_units,
5184  filename)) {
5185  ok = false;
5186  break;
5187  }
5188  fc_strlcat(tmp, sec_name, 200);
5189  fc_strlcat(tmp, ".init_government", 200);
5190  if (secfile_entry_by_path(file, tmp)) {
5191  pnation.init_government =
5192  lookup_government(file, tmp, filename, nullptr);
5193  /* If specified, init_government has to be in this specific
5194  * ruleset, not just allowed_govs */
5195  if (pnation.init_government == nullptr) {
5196  ok = false;
5197  break;
5198  }
5199  /* ...but if a list of govs has been specified, enforce that this
5200  * nation's init_government is on the list. */
5201  if (game.server.ruledit.allowed_govs != nullptr
5202  && !is_on_allowed_list(
5203  government_rule_name(pnation.init_government),
5204  game.server.ruledit.allowed_govs,
5205  game.server.ruledit.ag_count)) {
5206  qCCritical(ruleset_category,
5207  "Nation %s: init_government \"%s\" not allowed.",
5208  nation_rule_name(&pnation),
5209  government_rule_name(pnation.init_government));
5210  ok = false;
5211  break;
5212  }
5213  }
5214 
5215  // Read default city names.
5216  if (!load_city_name_list(file, &pnation, sec_name, "cities",
5217  game.server.ruledit.allowed_terrains,
5218  game.server.ruledit.at_count)) {
5219  ok = false;
5220  break;
5221  }
5222 
5223  legend = secfile_lookup_str_default(file, "", "%s.legend", sec_name);
5224  pnation.legend = fc_strdup(legend);
5225  if (check_strlen(pnation.legend, MAX_LEN_MSG, nullptr)) {
5226  qCCritical(ruleset_category, "Nation %s: legend \"%s\" is too long.",
5227  nation_rule_name(&pnation), pnation.legend);
5228  ok = false;
5229  break;
5230  }
5231 
5232  pnation.player = nullptr;
5233  }
5234  section_list_destroy(sec);
5235  sec = nullptr;
5236  }
5237 
5238  // Clean up on aborted load
5239  if (sec) {
5240  fc_assert(!ok);
5241  section_list_destroy(sec);
5242  }
5243 
5244  if (ok) {
5245  secfile_check_unused(file);
5246  }
5247 
5248  if (ok) {
5249  // Update cached number of playable nations in the current set
5251 
5252  // Sanity checks on all sets
5253  nation_sets_iterate(pset)
5254  {
5255  int num_playable = 0, barb_land_count = 0, barb_sea_count = 0,
5256  barb_both_count = 0;
5257 
5258  for (auto &pnation : nations) {
5259  if (nation_is_in_set(&pnation, pset)) {
5260  switch (nation_barbarian_type(&pnation)) {
5261  case NOT_A_BARBARIAN:
5262  if (is_nation_playable(&pnation)) {
5263  num_playable++;
5264  }
5265  break;
5266  case LAND_BARBARIAN:
5267  barb_land_count++;
5268  break;
5269  case SEA_BARBARIAN:
5270  barb_sea_count++;
5271  break;
5272  case ANIMAL_BARBARIAN:
5273  // Animals are optional
5274  break;
5275  case LAND_AND_SEA_BARBARIAN:
5276  barb_both_count++;
5277  break;
5278  default:
5279  fc_assert_ret_val(false, false);
5280  }
5281  }
5282  }
5283  if (num_playable < 1) {
5284  qCCritical(ruleset_category,
5285  "Nation set \"%s\" has no playable nations. "
5286  "At least one required!",
5287  nation_set_rule_name(pset));
5288  ok = false;
5289  break;
5290  }
5291  if (barb_land_count == 0 && barb_both_count == 0) {
5292  qCCritical(ruleset_category,
5293  "No land barbarian nation defined in set \"%s\". "
5294  "At least one required!",
5295  nation_set_rule_name(pset));
5296  ok = false;
5297  break;
5298  }
5299  if (barb_sea_count == 0 && barb_both_count == 0) {
5300  qCCritical(ruleset_category,
5301  "No sea barbarian nation defined in set \"%s\". "
5302  "At least one required!",
5303  nation_set_rule_name(pset));
5304  ok = false;
5305  break;
5306  }
5307  }
5309  }
5310 
5311  return ok;
5312 }
5313 
5318 static bool load_style_names(struct section_file *file,
5319  struct rscompat_info *compat)
5320 {
5321  bool ok = true;
5322  struct section_list *sec;
5323  const char *filename = secfile_name(file);
5324 
5325  compat->ver_styles = rscompat_check_capabilities(file, filename, compat);
5326  if (compat->ver_styles <= 0) {
5327  return false;
5328  }
5329 
5330  (void) secfile_entry_by_path(file, "datafile.description"); // unused
5331  (void) secfile_entry_by_path(file, "datafile.ruledit"); // unused
5332 
5334  if (nullptr == sec) {
5335  qCCritical(ruleset_category,
5336  "No available nation styles in this ruleset!");
5337  ok = false;
5338  } else {
5339  game.control.num_styles = section_list_size(sec);
5340 
5341  styles_alloc(game.control.num_styles);
5342 
5343  styles_iterate(ps)
5344  {
5345  const int i = style_index(ps);
5346  const char *sec_name = section_name(section_list_get(sec, i));
5347 
5348  fc_assert(ruleset_load_names(&ps->name, nullptr, file, sec_name));
5349  }
5351  }
5352 
5353  section_list_destroy(sec);
5354 
5355  if (ok) {
5356  // The citystyle sections:
5357  int i = 0;
5358 
5360  if (nullptr != sec) {
5361  city_styles_alloc(section_list_size(sec));
5362  section_list_iterate(sec, style)
5363  {
5364  if (!ruleset_load_names(&city_styles[i].name, nullptr, file,
5365  section_name(style))) {
5366  ok = false;
5367  break;
5368  }
5369  i++;
5370  }
5372 
5373  section_list_destroy(sec);
5374  } else {
5375  city_styles_alloc(0);
5376  }
5377  }
5378 
5379  return ok;
5380 }
5381 
5385 static bool load_ruleset_styles(struct section_file *file,
5386  struct rscompat_info *compat)
5387 {
5388  struct section_list *sec;
5389  int i;
5390  bool ok = true;
5391 
5392  // City Styles ...
5393 
5395 
5396  // Get rest:
5397  for (i = 0; i < game.control.styles_count; i++) {
5398  struct requirement_vector *reqs;
5399  const char *sec_name = section_name(section_list_get(sec, i));
5400 
5401  sz_strlcpy(city_styles[i].graphic,
5402  secfile_lookup_str(file, "%s.graphic", sec_name));
5403  sz_strlcpy(city_styles[i].graphic_alt,
5404  secfile_lookup_str(file, "%s.graphic_alt", sec_name));
5405  sz_strlcpy(city_styles[i].citizens_graphic,
5406  secfile_lookup_str_default(file, "-", "%s.citizens_graphic",
5407  sec_name));
5408  sz_strlcpy(city_styles[i].citizens_graphic_alt,
5410  file, "generic", "%s.citizens_graphic_alt", sec_name));
5411 
5412  reqs = lookup_req_list(file, compat, sec_name, "reqs",
5414  if (reqs == nullptr) {
5415  ok = false;
5416  break;
5417  }
5418  requirement_vector_copy(&city_styles[i].reqs, reqs);
5419  }
5420 
5421  section_list_destroy(sec);
5422 
5423  if (ok) {
5425 
5426  if (sec != nullptr) {
5427  int musi;
5428 
5429  game.control.num_music_styles = section_list_size(sec);
5430  music_styles_alloc(game.control.num_music_styles);
5431  musi = 0;
5432 
5433  section_list_iterate(sec, psection)
5434  {
5435  struct requirement_vector *reqs;
5436  struct music_style *pmus = music_style_by_number(musi);
5437  const char *sec_name = section_name(psection);
5438 
5439  const char *s = secfile_lookup_str_default(
5440  file, "-", "%s.music_peaceful", sec_name);
5441  if (s) {
5442  pmus->music_peaceful = s;
5443  }
5444 
5445  s = secfile_lookup_str_default(file, "-", "%s.music_combat",
5446  sec_name);
5447  if (s) {
5448  pmus->music_combat = s;
5449  }
5450  reqs =
5451  lookup_req_list(file, compat, sec_name, "reqs", "Music Style");
5452  if (reqs == nullptr) {
5453  ok = false;
5454  break;
5455  }
5456  requirement_vector_copy(&pmus->reqs, reqs);
5457 
5458  musi++;
5459  }
5461  }
5462 
5463  section_list_destroy(sec);
5464  }
5465 
5466  return ok;
5467 }
5468 
5475  struct action_auto_perf *auto_perf,
5476  const char *uflags_path,
5477  const char *filename)
5478 {
5479  /* Add each listed protected unit type flag as a !present
5480  * requirement. */
5481  if (secfile_entry_lookup(file, "%s", uflags_path)) {
5482  enum unit_type_flag_id *protecor_flag;
5483  size_t psize;
5484  int i;
5485 
5486  protecor_flag = secfile_lookup_enum_vec(file, &psize, unit_type_flag_id,
5487  "%s", uflags_path);
5488 
5489  if (!protecor_flag) {
5490  // Entity exists but couldn't read it.
5491  qCCritical(ruleset_category, "\"%s\": %s: bad unit type flag list.",
5492  filename, uflags_path);
5493 
5494  return false;
5495  }
5496 
5497  for (i = 0; i < psize; i++) {
5498  requirement_vector_append(&auto_perf->reqs,
5499  req_from_values(VUT_UTFLAG, REQ_RANGE_LOCAL,
5500  false, false, true,
5501  protecor_flag[i]));
5502  }
5503 
5504  delete[] protecor_flag;
5505  protecor_flag = nullptr;
5506  }
5507 
5508  return true;
5509 }
5510 
5515 static bool load_action_auto_actions(struct section_file *file,
5516  struct action_auto_perf *auto_perf,
5517  const char *actions_path,
5518  const char *filename)
5519 {
5520  // Read the alternative actions.
5521  if (secfile_entry_lookup(file, "%s", actions_path)) {
5522  enum gen_action *unit_acts;
5523  size_t asize;
5524  int i;
5525 
5526  unit_acts = secfile_lookup_enum_vec(file, &asize, gen_action, "%s",
5527  actions_path);
5528 
5529  if (!unit_acts) {
5530  // Entity exists but couldn't read it.
5531  qCCritical(ruleset_category, "\"%s\": %s: bad action list", filename,
5532  actions_path);
5533 
5534  return false;
5535  }
5536 
5537  for (i = 0; i < asize; i++) {
5538  auto_perf->alternatives[i] = unit_acts[i];
5539  }
5540 
5541  delete[] unit_acts;
5542  unit_acts = nullptr;
5543  }
5544 
5545  return true;
5546 }
5547 
5551 static bool load_muuk_as_action_auto(struct section_file *file,
5552  struct action_auto_perf *auto_perf,
5553  const char *item, const char *filename)
5554 {
5555  char uflags_path[100];
5556  char action_path[100];
5557 
5558  fc_snprintf(uflags_path, sizeof(uflags_path),
5559  "missing_unit_upkeep.%s_protected", item);
5560  fc_snprintf(action_path, sizeof(action_path),
5561  "missing_unit_upkeep.%s_unit_act", item);
5562 
5563  return (
5564  load_action_auto_uflag_block(file, auto_perf, uflags_path, filename)
5565  && load_action_auto_actions(file, auto_perf, action_path, filename));
5566 }
5567 
5571 static bool load_ruleset_cities(struct section_file *file,
5572  struct rscompat_info *compat)
5573 {
5574  const char *filename = secfile_name(file);
5575  const char *item;
5576  struct section_list *sec;
5577  bool ok = true;
5578 
5579  compat->ver_cities = rscompat_check_capabilities(file, filename, compat);
5580  if (compat->ver_cities <= 0) {
5581  return false;
5582  }
5583 
5584  (void) secfile_entry_by_path(file, "datafile.description"); // unused
5585  (void) secfile_entry_by_path(file, "datafile.ruledit"); // unused
5586 
5587  // Specialist options
5589  if (section_list_size(sec) >= SP_MAX) {
5590  qCCritical(ruleset_category,
5591  "\"%s\": Too many specialists (%d, max %d).", filename,
5592  section_list_size(sec), SP_MAX);
5593  ok = false;
5594  }
5595 
5596  if (ok) {
5597  int i = 0;
5598  const char *tag;
5599 
5600  game.control.num_specialist_types = section_list_size(sec);
5601 
5602  section_list_iterate(sec, psection)
5603  {
5604  struct specialist *s = specialist_by_number(i);
5605  struct requirement_vector *reqs;
5606  const char *sec_name = section_name(psection);
5607 
5608  if (!ruleset_load_names(&s->name, nullptr, file, sec_name)) {
5609  ok = false;
5610  break;
5611  }
5612 
5614  "%s.short_name", sec_name);
5615  name_set(&s->abbreviation, nullptr, item);
5616 
5617  tag = secfile_lookup_str(file, "%s.graphic", sec_name);
5618  if (tag == nullptr) {
5619  qCCritical(ruleset_category,
5620  "\"%s\": No graphic tag for specialist at %s.", filename,
5621  sec_name);
5622  ok = false;
5623  break;
5624  }
5625  sz_strlcpy(s->graphic_str, tag);
5627  file, "-", "%s.graphic_alt", sec_name));
5628 
5629  reqs = lookup_req_list(file, compat, sec_name, "reqs",
5631  if (reqs == nullptr) {
5632  ok = false;
5633  break;
5634  }
5635  requirement_vector_copy(&s->reqs, reqs);
5636 
5637  s->helptext = lookup_strvec(file, sec_name, "helptext");
5638 
5639  if (requirement_vector_size(&s->reqs) == 0
5640  && DEFAULT_SPECIALIST == -1) {
5641  DEFAULT_SPECIALIST = i;
5642  }
5643  i++;
5644  }
5646  }
5647 
5648  if (ok && DEFAULT_SPECIALIST == -1) {
5649  qCCritical(ruleset_category,
5650  "\"%s\": must give a min_size of 0 for at least one "
5651  "specialist type.",
5652  filename);
5653  ok = false;
5654  }
5655  section_list_destroy(sec);
5656  sec = nullptr;
5657 
5658  if (ok) {
5659  // City Parameters
5660 
5661  game.info.celebratesize = secfile_lookup_int_default(
5662  file, GAME_DEFAULT_CELEBRATESIZE, "parameters.celebrate_size_limit");
5663  game.info.add_to_size_limit = secfile_lookup_int_default(
5664  file, GAME_DEFAULT_ADDTOSIZE, "parameters.add_to_size_limit");
5665  game.info.angrycitizen = secfile_lookup_bool_default(
5666  file, GAME_DEFAULT_ANGRYCITIZEN, "parameters.angry_citizens");
5667 
5668  if (!secfile_lookup_bool(file, &game.info.changeable_budget,
5669  "parameters.changeable_budget")) {
5670  if (secfile_entry_by_path(file, "parameters.changable_tax")) {
5671  qCWarning(ruleset_category,
5672  "parameters.changable_tax is deprecated; use "
5673  "parameters.changeable_budget instead.");
5674  }
5675  game.info.changeable_budget = secfile_lookup_bool_default(
5676  file, GAME_DEFAULT_CHANGEABLE_BUDGET, "parameters.changable_tax");
5677  }
5678  game.info.forced_science =
5679  secfile_lookup_int_default(file, 0, "parameters.forced_science");
5680  game.info.forced_luxury =
5681  secfile_lookup_int_default(file, 100, "parameters.forced_luxury");
5682  game.info.forced_gold =
5683  secfile_lookup_int_default(file, 0, "parameters.forced_gold");
5684  if (game.info.forced_science + game.info.forced_luxury
5685  + game.info.forced_gold
5686  != 100) {
5687  qCCritical(ruleset_category,
5688  "\"%s\": Forced taxes do not add up in ruleset!", filename);
5689  ok = false;
5690  }
5691  }
5692 
5693  if (ok) {
5694  // civ1 & 2 didn't reveal tiles
5695  game.server.vision_reveal_tiles =
5697  "parameters.vision_reveal_tiles");
5698 
5699  game.info.pop_report_zeroes =
5700  secfile_lookup_int_default(file, 1, "parameters.pop_report_zeroes");
5701 
5702  // Citizens configuration.
5703  game.info.citizen_nationality = secfile_lookup_bool_default(
5704  file, GAME_DEFAULT_NATIONALITY, "citizen.nationality");
5705  game.info.citizen_convert_speed = secfile_lookup_int_default(
5706  file, GAME_DEFAULT_CONVERT_SPEED, "citizen.convert_speed");
5707  game.info.citizen_partisans_pct =
5708  secfile_lookup_int_default(file, 0, "citizen.partisans_pct");
5709  game.info.conquest_convert_pct =
5710  secfile_lookup_int_default(file, 0, "citizen.conquest_convert_pct");
5711  }
5712 
5713  if (ok) {
5714  // Missing unit upkeep.
5715  struct action_auto_perf *auto_perf;
5716 
5717  // Can't pay food upkeep!
5719  auto_perf->cause = AAPC_UNIT_UPKEEP;
5720 
5721  // This is about food upkeep.
5722  requirement_vector_append(
5723  &auto_perf->reqs,
5724  req_from_str("OutputType", "Local", false, true, true, "Food"));
5725 
5726  // Internally represented as an action auto performer rule.
5727  if (!load_muuk_as_action_auto(file, auto_perf, "food", filename)) {
5728  ok = false;
5729  }
5730 
5731  game.info.muuk_food_wipe = secfile_lookup_bool_default(
5732  file, RS_DEFAULT_MUUK_FOOD_WIPE, "missing_unit_upkeep.food_wipe");
5733 
5734  // Can't pay gold upkeep!
5736  auto_perf->cause = AAPC_UNIT_UPKEEP;
5737 
5738  // This is about gold upkeep.
5739  requirement_vector_append(
5740  &auto_perf->reqs,
5741  req_from_str("OutputType", "Local", false, true, true, "Gold"));
5742 
5743  // Internally represented as an action auto performer rule.
5744  if (!load_muuk_as_action_auto(file, auto_perf, "gold", filename)) {
5745  ok = false;
5746  }
5747 
5748  game.info.muuk_gold_wipe = secfile_lookup_bool_default(
5749  file, RS_DEFAULT_MUUK_GOLD_WIPE, "missing_unit_upkeep.gold_wipe");
5750 
5751  // Can't pay shield upkeep!
5753  auto_perf->cause = AAPC_UNIT_UPKEEP;
5754 
5755  // This is about shield upkeep.
5756  requirement_vector_append(
5757  &auto_perf->reqs,
5758  req_from_str("OutputType", "Local", false, true, true, "Shield"));
5759 
5760  // Internally represented as an action auto performer rule.
5761  if (!load_muuk_as_action_auto(file, auto_perf, "shield", filename)) {
5762  ok = false;
5763  }
5764 
5765  game.info.muuk_shield_wipe =
5767  "missing_unit_upkeep.shield_wipe");
5768  }
5769 
5770  if (ok) {
5771  secfile_check_unused(file);
5772  }
5773 
5774  return ok;
5775 }
5776 
5780 static bool load_ruleset_effects(struct section_file *file,
5781  struct rscompat_info *compat)
5782 {
5783  struct section_list *sec;
5784  const char *type;
5785  const char *filename;
5786  bool ok = true;
5787 
5788  filename = secfile_name(file);
5789 
5790  compat->ver_effects = rscompat_check_capabilities(file, filename, compat);
5791  if (compat->ver_effects <= 0) {
5792  return false;
5793  }
5794 
5795  compat->cap_effects = secfile_lookup_str(file, "datafile.options");
5796 
5797  (void) secfile_entry_by_path(file, "datafile.description"); // unused
5798  (void) secfile_entry_by_path(file, "datafile.ruledit"); // unused
5799 
5800  // Parse effects and add them to the effects ruleset cache.
5802  section_list_iterate(sec, psection)
5803  {
5804  enum effect_type eff;
5805  int value;
5806  struct multiplier *pmul;
5807  struct effect *peffect;
5808  const char *sec_name = section_name(psection);
5809  struct requirement_vector *reqs;
5810 
5811  type = secfile_lookup_str(file, "%s.type", sec_name);
5812 
5813  if (type == nullptr) {
5814  qCCritical(ruleset_category, "\"%s\" [%s] missing effect type.",
5815  filename, sec_name);
5816  ok = false;
5817  break;
5818  }
5819 
5820  if (compat->compat_mode
5821  && rscompat_old_effect_3_1(type, file, sec_name, compat)) {
5822  continue;
5823  }
5824 
5825  eff = effect_type_by_name(type, fc_strcasecmp);
5826  if (!effect_type_is_valid(eff)) {
5827  qCCritical(ruleset_category,
5828  "\"%s\" [%s] lists unknown effect type \"%s\".", filename,
5829  sec_name, type);
5830  ok = false;
5831  break;
5832  }
5833 
5834  value = secfile_lookup_int_default(file, 1, "%s.value", sec_name);
5835 
5836  {
5837  const char *multiplier_name =
5838  secfile_lookup_str(file, "%s.multiplier", sec_name);
5839 
5840  if (multiplier_name) {
5841  pmul = multiplier_by_rule_name(multiplier_name);
5842  if (!pmul) {
5843  qCCritical(ruleset_category,
5844  "\"%s\" [%s] has unknown multiplier \"%s\".", filename,
5845  sec_name, multiplier_name);
5846  ok = false;
5847  break;
5848  }
5849  } else {
5850  pmul = nullptr;
5851  }
5852  }
5853 
5854  peffect = effect_new(eff, value, pmul);
5855 
5856  reqs = lookup_req_list(file, compat, sec_name, "reqs", type);
5857  if (reqs == nullptr) {
5858  ok = false;
5859  break;
5860  }
5861 
5863  {
5864  effect_req_append(peffect, *preq);
5865  }
5867 
5868  if (compat->compat_mode) {
5869  reqs = lookup_req_list(file, compat, sec_name, "nreqs", type);
5870  if (reqs == nullptr) {
5871  ok = false;
5872  break;
5873  }
5875  {
5876  preq->present = !preq->present;
5877  effect_req_append(peffect, *preq);
5878  }
5880  }
5881  }
5883 
5884  if (sec != nullptr) {
5885  section_list_destroy(sec);
5886  }
5887 
5888  if (ok) {
5889  secfile_check_unused(file);
5890  }
5891 
5892  return ok;
5893 }
5894 
5899  int def, int min, int max,
5900  const char *path, ...)
5901 {
5902  char fullpath[256];
5903  int ival;
5904  va_list args;
5905 
5906  va_start(args, path);
5907  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
5908  va_end(args);
5909 
5910  if (!secfile_lookup_int(file, &ival, "%s", fullpath)) {
5911  ival = def;
5912  }
5913 
5914  if (ival < min) {
5915  qCCritical(ruleset_category,
5916  "\"%s\" should be in the interval [%d, %d] "
5917  "but is %d; using the minimal value.",
5918  fullpath, min, max, ival);
5919  ival = min;
5920  }
5921 
5922  if (ival > max) {
5923  qCCritical(ruleset_category,
5924  "\"%s\" should be in the interval [%d, %d] "
5925  "but is %d; using the maximal value.",
5926  fullpath, min, max, ival);
5927  ival = max;
5928  }
5929 
5930  return ival;
5931 }
5932 
5936 static bool load_action_ui_name(struct section_file *file, int act,
5937  const char *entry_name)
5938 {
5939  const char *text;
5940 
5942  "actions.%s", entry_name);
5943  sz_strlcpy(action_by_number(act)->ui_name, text);
5944 
5945  return true;
5946 }
5947 
5951 static bool load_action_range_max(struct section_file *file, action_id act)
5952 {
5953  struct entry *pentry;
5954  int max_range;
5955 
5956  pentry = secfile_entry_lookup(file, "actions.%s",
5958 
5959  if (!pentry) {
5960  max_range = action_max_range_default(act);
5961  } else {
5962  const char *custom;
5963 
5964  if (entry_type_get(pentry) == ENTRY_INT
5965  && entry_int_get(pentry, &max_range)) {
5966  // max_range already assigned
5967  } else if (entry_type_get(pentry) == ENTRY_STR
5968  && entry_str_get(pentry, &custom)
5970  max_range = ACTION_DISTANCE_UNLIMITED;
5971  } else {
5972  qCCritical(ruleset_category, "Bad actions.%s",
5975  return false;
5976  }
5977  }
5978 
5979  action_by_number(act)->max_distance = max_range;
5980  return true;
5981 }
5982 
5986 static bool load_action_range(struct section_file *file, action_id act)
5987 {
5988  if (action_max_range_ruleset_var_name(act) != nullptr) {
5989  // Max range can be loaded from the ruleset.
5990  if (!load_action_range_max(file, act)) {
5991  return false;
5992  }
5993  }
5994 
5995  if (action_min_range_ruleset_var_name(act) != nullptr) {
5996  // Min range can be loaded from the ruleset.
5998  file, action_min_range_default(act), "actions.%s",
6000  }
6001 
6002  return true;
6003 }
6004 
6008 static bool load_action_kind(struct section_file *file, action_id act)
6009 {
6010  if (action_target_kind_ruleset_var_name(act) != nullptr) {
6011  // Target kind can be loaded from the ruleset.
6013  action_target_kind(secfile_lookup_enum_default(
6014  file, RS_DEFAULT_USER_ACTION_TARGET_KIND, action_target_kind,
6015  "actions.%s", action_target_kind_ruleset_var_name(act)));
6016  }
6017 
6018  return true;
6019 }
6020 
6025  action_id act)
6026 {
6027  if (action_actor_consuming_always_ruleset_var_name(act) != nullptr) {
6028  // Actor consumption can be loaded from the ruleset.
6031  file, RS_DEFAULT_ACTION_ACTOR_CONSUMING_ALWAYS, "actions.%s",
6033  }
6034 
6035  return true;
6036 }
6037 
6041 static bool load_ruleset_game(struct section_file *file, bool act,
6042  struct rscompat_info *compat)
6043 {
6044  const char *sval, **svec;
6045  const char *filename;
6046  int *food_ini;
6047  int i;
6048  size_t teams;
6049  const char *pref_text;
6050  size_t gni_tmp;
6051  struct section_list *sec = nullptr;
6052  size_t nval;
6053  const char *name;
6054  bool ok = true;
6055 
6056  if (file == nullptr) {
6057  return false;
6058  }
6059  filename = secfile_name(file);
6060 
6061  name =
6062  secfile_lookup_str_default(file, nullptr, "ruledit.description_file");
6063  if (name != nullptr) {
6064  game.server.ruledit.description_file = fc_strdup(name);
6065  }
6066 
6067  // section: tileset
6068  pref_text = secfile_lookup_str_default(file, "", "tileset.prefered");
6069  if (pref_text[0] != '\0') {
6070  qCWarning(deprecations_category,
6071  "Entry tileset.prefered in game.ruleset."
6072  " Use correct spelling tileset.preferred instead");
6073  }
6074  pref_text =
6075  secfile_lookup_str_default(file, pref_text, "tileset.preferred");
6076  if (pref_text[0] != '\0') {
6077  // There was tileset suggestion
6078  sz_strlcpy(game.control.preferred_tileset, pref_text);
6079  } else {
6080  // No tileset suggestions
6081  game.control.preferred_tileset[0] = '\0';
6082  }
6083 
6084  // section: soundset
6085  pref_text = secfile_lookup_str_default(file, "", "soundset.prefered");
6086  if (pref_text[0] != '\0') {
6087  qCWarning(deprecations_category,
6088  "Entry soundset.prefered in game.ruleset."
6089  " Use correct spelling soundset.preferred instead");
6090  }
6091  pref_text =
6092  secfile_lookup_str_default(file, pref_text, "soundset.preferred");
6093  if (pref_text[0] != '\0') {
6094  // There was soundset suggestion
6095  sz_strlcpy(game.control.preferred_soundset, pref_text);
6096  } else {
6097  // No soundset suggestions
6098  game.control.preferred_soundset[0] = '\0';
6099  }
6100 
6101  // section: musicset
6102  pref_text = secfile_lookup_str_default(file, "", "musicset.prefered");
6103  if (pref_text[0] != '\0') {
6104  qCWarning(deprecations_category,
6105  "Entry musicset.prefered in game.ruleset."
6106  " Use correct spelling musicset.preferred instead");
6107  }
6108  pref_text =
6109  secfile_lookup_str_default(file, pref_text, "musicset.preferred");
6110  if (pref_text[0] != '\0') {
6111  // There was musicset suggestion
6112  sz_strlcpy(game.control.preferred_musicset, pref_text);
6113  } else {
6114  // No musicset suggestions
6115  game.control.preferred_musicset[0] = '\0';
6116  }
6117 
6118  // section: about
6119  pref_text = secfile_lookup_str(file, "about.name");
6120  /* Ruleset/modpack name found */
6121  sz_strlcpy(game.control.name, pref_text);
6122 
6123  pref_text = secfile_lookup_str_default(file, "", "about.version");
6124  if (pref_text[0] != '\0') {
6125  /* Ruleset/modpack version found */
6126  sz_strlcpy(game.control.version, pref_text);
6127  } else {
6128  // No version information
6129  game.control.version[0] = '\0';
6130  }
6131 
6132  pref_text = secfile_lookup_str_default(file, "", "about.alt_dir");
6133  if (pref_text[0] != '\0') {
6134  // Alt directory definition found.
6135  sz_strlcpy(game.control.alt_dir, pref_text);
6136  } else {
6137  // No alt directory information
6138  game.control.alt_dir[0] = '\0';
6139  }
6140 
6141  pref_text = secfile_lookup_str_default(file, "", "about.summary");
6142  if (pref_text[0] != '\0') {
6143  int len;
6144 
6145  /* Ruleset/modpack summary found */
6146  len = qstrlen(pref_text);
6147  game.ruleset_summary = new char[len + 1];
6148  fc_strlcpy(game.ruleset_summary, pref_text, len + 1);
6149  } else {
6150  // No summary
6151  if (game.ruleset_summary != nullptr) {
6152  delete[] game.ruleset_summary;
6153  game.ruleset_summary = nullptr;
6154  }
6155  }
6156 
6157  pref_text = secfile_lookup_str_default(file, "", "about.description");
6158  if (pref_text[0] != '\0') {
6159  int len;
6160 
6161  /* Ruleset/modpack description found */
6162  len = qstrlen(pref_text);
6163  game.ruleset_description = new char[len + 1];
6164  fc_strlcpy(game.ruleset_description, pref_text, len + 1);
6165  game.control.desc_length = len;
6166  } else {
6167  // No description
6168  if (game.ruleset_description != nullptr) {
6169  delete[] game.ruleset_description;
6170  game.ruleset_description = nullptr;
6171  }
6172  game.control.desc_length = 0;
6173  }
6174 
6175  pref_text = secfile_lookup_str_default(file, "", "about.capabilities");
6176  if (pref_text[0] != '\0') {
6177  int len = qstrlen(pref_text);
6178 
6179  game.ruleset_capabilities = new char[len + 1];
6180  fc_strlcpy(game.ruleset_capabilities, pref_text, len + 1);
6181  } else {
6182  game.ruleset_capabilities = new char[1];
6183  game.ruleset_capabilities[0] = '\0';
6184  }
6185 
6186  // section: options
6187  if (!lookup_tech_list(file, "options", "global_init_techs",
6188  game.rgame.global_init_techs, filename)) {
6189  ok = false;
6190  }
6191 
6192  if (ok) {
6193  if (!lookup_building_list(file, "options", "global_init_buildings",
6194  game.rgame.global_init_buildings, filename)) {
6195  ok = false;
6196  }
6197  }
6198 
6199  if (ok) {
6200  const char **slist;
6201  int j;
6202 
6203  game.control.popup_tech_help =
6204  secfile_lookup_bool_default(file, false, "options.popup_tech_help");
6205 
6206  // section: civstyle
6207  game.info.base_pollution = secfile_lookup_int_default(
6208  file, RS_DEFAULT_BASE_POLLUTION, "civstyle.base_pollution");
6209 
6210  game.info.gameloss_style = GAMELOSS_STYLE_CLASSICAL;
6211 
6212  slist = secfile_lookup_str_vec(file, &nval, "civstyle.gameloss_style");
6213  for (j = 0; j < nval; j++) {
6214  enum gameloss_style style;
6215 
6216  sval = slist[j];
6217  if (strcmp(sval, "") == 0) {
6218  continue;
6219  }
6220  style = gameloss_style_by_name(sval, fc_strcasecmp);
6221  if (!gameloss_style_is_valid(style)) {
6222  qCCritical(ruleset_category,
6223  "\"%s\": bad value \"%s\" for gameloss_style.", filename,
6224  sval);
6225  ok = false;
6226  break;
6227  } else {
6228  game.info.gameloss_style =
6229  gameloss_style(game.info.gameloss_style | style);
6230  }
6231  }
6232  delete[] slist;
6233  slist = nullptr;
6234  }
6235 
6236  if (ok) {
6237  auto str =
6239  "civstyle.initial_diplomatic_state");
6240  game.server.initial_diplomatic_state =
6241  diplstate_type_by_name(str, fc_strcasecmp);
6242  if (!diplstate_type_is_valid(game.server.initial_diplomatic_state)) {
6243  qCritical() << "Invalid value for initial_diplomatic_state:"
6244  << QString(str);
6245  ok = false;
6246  }
6247  }
6248 
6249  if (ok) {
6252  "civstyle.happy_cost");
6255  "civstyle.food_cost");
6256  game.info.civil_war_enabled = secfile_lookup_bool_default(
6257  file, true, "civstyle.civil_war_enabled");
6258 
6259  game.info.civil_war_bonus_celebrating =
6261  "civstyle.civil_war_bonus_celebrating");
6262 
6263  game.info.civil_war_bonus_unhappy =
6265  "civstyle.civil_war_bonus_unhappy");
6266 
6267  game.info.paradrop_to_transport = secfile_lookup_bool_default(
6268  file, false, "civstyle.paradrop_to_transport");
6269 
6270  // TODO: move to global_unit_options
6271  game.info.base_bribe_cost = secfile_lookup_int_default_min_max(
6273  RS_MAX_BASE_BRIBE_COST, "civstyle.base_bribe_cost");
6274  // TODO: move to global_unit_options
6277  "civstyle.ransom_gold");
6278  // TODO: move to global_unit_options
6279  game.info.pillage_select = secfile_lookup_bool_default(
6280  file, RS_DEFAULT_PILLAGE_SELECT, "civstyle.pillage_select");
6281 
6282  game.info.tech_steal_allow_holes =
6284  "civstyle.tech_steal_allow_holes");
6285  game.info.tech_trade_allow_holes =
6287  "civstyle.tech_trade_allow_holes");
6288  game.info.tech_trade_loss_allow_holes =
6290  "civstyle.tech_trade_loss_allow_holes");
6291  game.info.tech_parasite_allow_holes =
6293  "civstyle.tech_parasite_allow_holes");
6294  game.info.tech_loss_allow_holes = secfile_lookup_bool_default(
6295  file, RS_DEFAULT_TECH_LOSS_HOLES, "civstyle.tech_loss_allow_holes");
6296 
6297  // TODO: move to global_unit_options
6298  game.server.upgrade_veteran_loss = secfile_lookup_int_default_min_max(
6300  RS_MAX_UPGRADE_VETERAN_LOSS, "civstyle.upgrade_veteran_loss");
6301  // TODO: move to global_unit_options
6302  game.server.autoupgrade_veteran_loss =
6306  "civstyle.autoupgrade_veteran_loss");
6307 
6308  game.info.base_tech_cost = secfile_lookup_int_default_min_max(
6310  RS_MAX_BASE_TECH_COST, "research.base_tech_cost");
6311 
6312  food_ini =
6313  secfile_lookup_int_vec(file, &gni_tmp, "civstyle.granary_food_ini");
6314  game.info.granary_num_inis = static_cast<int>(gni_tmp);
6315 
6316  if (game.info.granary_num_inis > MAX_GRANARY_INIS) {
6317  qCCritical(ruleset_category,
6318  "Too many granary_food_ini entries (%d, max %d)",
6319  game.info.granary_num_inis, MAX_GRANARY_INIS);
6320  ok = false;
6321  } else if (game.info.granary_num_inis == 0) {
6322  qCritical("No values for granary_food_ini. Using default "
6323  "value %d.",
6325  game.info.granary_num_inis = 1;
6326  game.info.granary_food_ini[0] = RS_DEFAULT_GRANARY_FOOD_INI;
6327  } else {
6328  int gi;
6329 
6330  // check for <= 0 entries
6331  for (gi = 0; gi < game.info.granary_num_inis; gi++) {
6332  if (food_ini && food_ini[gi] <= 0) {
6333  if (gi == 0) {
6334  food_ini[gi] = RS_DEFAULT_GRANARY_FOOD_INI;
6335  } else {
6336  food_ini[gi] = food_ini[gi - 1];
6337  }
6338  qCritical("Bad value for granary_food_ini[%i]. Using %i.", gi,
6339  food_ini[gi]);
6340  }
6341  game.info.granary_food_ini[gi] = food_ini[gi];
6342  }
6343  }
6344  delete[] food_ini;
6345  food_ini = nullptr;
6346  }
6347 
6348  if (ok) {
6349  game.info.granary_food_inc = secfile_lookup_int_default_min_max(
6351  RS_MAX_GRANARY_FOOD_INC, "civstyle.granary_food_inc");
6352 
6354  {
6355  game.info.min_city_center_output[o] =
6358  RS_MAX_CITY_CENTER_OUTPUT, "civstyle.min_city_center_%s",
6360  }
6362  }
6363 
6364  if (ok) {
6365  const char *tus_text;
6366 
6367  game.server.init_vis_radius_sq = secfile_lookup_int_default_min_max(
6369  RS_MAX_VIS_RADIUS_SQ, "civstyle.init_vis_radius_sq");
6370 
6371  game.info.init_city_radius_sq = secfile_lookup_int_default_min_max(
6373  RS_MAX_CITY_RADIUS_SQ, "civstyle.init_city_radius_sq");
6374 
6376  "civstyle.gold_upkeep_style");
6377  game.info.gold_upkeep_style =
6378  gold_upkeep_style_by_name(tus_text, fc_strcasecmp);
6379  if (!gold_upkeep_style_is_valid(game.info.gold_upkeep_style)) {
6380  qCCritical(ruleset_category, "Unknown gold upkeep style \"%s\"",
6381  tus_text);
6382  ok = false;
6383  }
6384 
6385  game.info.granularity =
6386  secfile_lookup_int_default(file, 1, "civstyle.output_granularity");
6387 
6388  // section: illness
6389  game.info.illness_on = secfile_lookup_bool_default(
6390  file, RS_DEFAULT_ILLNESS_ON, "illness.illness_on");
6391  game.info.illness_base_factor = secfile_lookup_int_default_min_max(
6393  RS_MAX_ILLNESS_BASE_FACTOR, "illness.illness_base_factor");
6394  game.info.illness_min_size = secfile_lookup_int_default_min_max(
6396  RS_MAX_ILLNESS_MIN_SIZE, "illness.illness_min_size");
6397  game.info.illness_trade_infection = secfile_lookup_int_default_min_max(
6401  "illness.illness_trade_infection");
6402  game.info.illness_pollution_factor = secfile_lookup_int_default_min_max(
6404  RS_MAX_ILLNESS_POLLUTION_PCT, "illness.illness_pollution_factor");
6405 
6406  // section: incite_cost
6407  game.server.base_incite_cost = secfile_lookup_int_default_min_max(
6409  RS_MAX_INCITE_BASE_COST, "incite_cost.base_incite_cost");
6410  game.server.incite_improvement_factor =
6414  "incite_cost.improvement_factor");
6415  game.server.incite_unit_factor = secfile_lookup_int_default_min_max(
6417  RS_MAX_INCITE_UNIT_FCT, "incite_cost.unit_factor");
6418  game.server.incite_total_factor = secfile_lookup_int_default_min_max(
6420  RS_MAX_INCITE_TOTAL_FCT, "incite_cost.total_factor");
6421 
6422  if (ok) {
6423  // Auto attack.
6424  struct action_auto_perf *auto_perf;
6425 
6426  /* Action auto performers aren't ready to be exposed in the ruleset
6427  * yet. The behavior when two action auto performers for the same
6428  * cause can fire isn't set in stone yet. How is one of them chosen?
6429  * What if all the actions of the chosen action auto performer turned
6430  * out to be illegal but one of the other action auto performers that
6431  * fired has legal actions? These issues can decide what other action
6432  * rules action auto performers can represent in the future. Deciding
6433  * should therefore wait until a rule needs action auto performers to
6434  * work a certain way. */
6435  /* Only one action auto performer, ACTION_AUTO_MOVED_ADJ, is caused
6436  * by AAPC_UNIT_MOVED_ADJ. It is therefore safe to expose the full
6437  * requirement vector to the ruleset. */
6438  struct requirement_vector *reqs;
6439 
6440  /* A unit moved next to this unit and the autoattack server setting
6441  * is enabled. */
6443  auto_perf->cause = AAPC_UNIT_MOVED_ADJ;
6444 
6445  reqs = lookup_req_list(file, compat, "auto_attack", "if_attacker",
6446  "auto_attack");
6447  if (reqs == nullptr) {
6448  ok = false;
6449  }
6450 
6451  requirement_vector_copy(&auto_perf->reqs, reqs);
6452 
6454  file, auto_perf, "auto_attack.attack_actions", filename)) {
6455  // Failed to load auto attack actions
6456  qCCritical(ruleset_category, "\"%s\": %s: failed load %s.", filename,
6457  "auto_attack", "attack_actions");
6458  ok = false;
6459  }
6460 
6461  if (compat->compat_mode) {
6462  enum unit_type_flag_id *protecor_flag;
6463  size_t psize;
6464 
6465  if (secfile_entry_lookup(file, "%s", "auto_attack.will_never")) {
6466  protecor_flag =
6467  secfile_lookup_enum_vec(file, &psize, unit_type_flag_id, "%s",
6468  "auto_attack.will_never");
6469 
6470  if (!protecor_flag) {
6471  // Entity exists but couldn't read it.
6472  qCCritical(ruleset_category,
6473  "\"%s\": %s: bad unit type flag list.", filename,
6474  "auto_attack.will_never");
6475 
6476  ok = false;
6477  }
6478  } else {
6479  psize = 0;
6480  protecor_flag = nullptr;
6481  }
6482 
6483  if (!rscompat_auto_attack_3_1(compat, auto_perf, psize,
6484  protecor_flag)) {
6485  // Upgrade failed
6486  qCCritical(ruleset_category, "\"%s\": %s: failed to upgrade.",
6487  filename, "auto_attack");
6488  ok = false;
6489  }
6490 
6491  if (psize) {
6492  delete[] protecor_flag;
6493  protecor_flag = nullptr;
6494  }
6495  }
6496  }
6497 
6498  // section: actions
6499  if (ok) {
6500  int force_capture_units, force_bombard, force_explode_nuclear;
6501 
6503  "actions.force_trade_route")) {
6504  /* Forbid entering the marketplace when a trade route can be
6505  * established. */
6506  BV_SET(action_by_number(ACTION_MARKETPLACE)->blocked_by,
6507  ACTION_TRADE_ROUTE);
6508  }
6509 
6510  /* Forbid bombarding, exploading nuclear or attacking when it is
6511  * legal to capture units. */
6512  force_capture_units =
6514  "actions.force_capture_units");
6515 
6516  if (force_capture_units) {
6517  BV_SET(action_by_number(ACTION_BOMBARD)->blocked_by,
6518  ACTION_CAPTURE_UNITS);
6519  BV_SET(action_by_number(ACTION_BOMBARD2)->blocked_by,
6520  ACTION_CAPTURE_UNITS);
6521  BV_SET(action_by_number(ACTION_BOMBARD3)->blocked_by,
6522  ACTION_CAPTURE_UNITS);
6523  BV_SET(action_by_number(ACTION_NUKE)->blocked_by,
6524  ACTION_CAPTURE_UNITS);
6525  BV_SET(action_by_number(ACTION_NUKE_CITY)->blocked_by,
6526  ACTION_CAPTURE_UNITS);
6527  BV_SET(action_by_number(ACTION_NUKE_UNITS)->blocked_by,
6528  ACTION_CAPTURE_UNITS);
6529  BV_SET(action_by_number(ACTION_SUICIDE_ATTACK)->blocked_by,
6530  ACTION_CAPTURE_UNITS);
6531  BV_SET(action_by_number(ACTION_ATTACK)->blocked_by,
6532  ACTION_CAPTURE_UNITS);
6533  BV_SET(action_by_number(ACTION_CONQUER_CITY)->blocked_by,
6534  ACTION_CAPTURE_UNITS);
6535  BV_SET(action_by_number(ACTION_CONQUER_CITY2)->blocked_by,
6536  ACTION_CAPTURE_UNITS);
6537  }
6538 
6539  /* Forbid exploding nuclear or attacking when it is legal to
6540  * bombard. */
6541  force_bombard = secfile_lookup_bool_default(
6542  file, RS_DEFAULT_FORCE_BOMBARD, "actions.force_bombard");
6543 
6544  if (force_bombard) {
6545  BV_SET(action_by_number(ACTION_NUKE)->blocked_by, ACTION_BOMBARD);
6546  BV_SET(action_by_number(ACTION_NUKE_CITY)->blocked_by,
6547  ACTION_BOMBARD);
6548  BV_SET(action_by_number(ACTION_NUKE_UNITS)->blocked_by,
6549  ACTION_BOMBARD);
6550  BV_SET(action_by_number(ACTION_SUICIDE_ATTACK)->blocked_by,
6551  ACTION_BOMBARD);
6552  BV_SET(action_by_number(ACTION_ATTACK)->blocked_by, ACTION_BOMBARD);
6553  BV_SET(action_by_number(ACTION_CONQUER_CITY)->blocked_by,
6554  ACTION_BOMBARD);
6555  BV_SET(action_by_number(ACTION_CONQUER_CITY2)->blocked_by,
6556  ACTION_BOMBARD);
6557  BV_SET(action_by_number(ACTION_NUKE)->blocked_by, ACTION_BOMBARD2);
6558  BV_SET(action_by_number(ACTION_NUKE_CITY)->blocked_by,
6559  ACTION_BOMBARD2);
6560  BV_SET(action_by_number(ACTION_NUKE_UNITS)->blocked_by,
6561  ACTION_BOMBARD2);
6562  BV_SET(action_by_number(ACTION_SUICIDE_ATTACK)->blocked_by,
6563  ACTION_BOMBARD2);
6564  BV_SET(action_by_number(ACTION_ATTACK)->blocked_by, ACTION_BOMBARD2);
6565  BV_SET(action_by_number(ACTION_CONQUER_CITY)->blocked_by,
6566  ACTION_BOMBARD2);
6567  BV_SET(action_by_number(ACTION_CONQUER_CITY2)->blocked_by,
6568  ACTION_BOMBARD2);
6569  BV_SET(action_by_number(ACTION_NUKE)->blocked_by, ACTION_BOMBARD3);
6570  BV_SET(action_by_number(ACTION_NUKE_CITY)->blocked_by,
6571  ACTION_BOMBARD3);
6572  BV_SET(action_by_number(ACTION_NUKE_UNITS)->blocked_by,
6573  ACTION_BOMBARD3);
6574  BV_SET(action_by_number(ACTION_SUICIDE_ATTACK)->blocked_by,
6575  ACTION_BOMBARD3);
6576  BV_SET(action_by_number(ACTION_ATTACK)->blocked_by, ACTION_BOMBARD3);
6577  BV_SET(action_by_number(ACTION_CONQUER_CITY)->blocked_by,
6578  ACTION_BOMBARD3);
6579  BV_SET(action_by_number(ACTION_CONQUER_CITY2)->blocked_by,
6580  ACTION_BOMBARD3);
6581  }
6582 
6583  // Forbid attacking when it is legal to do explode nuclear.
6584  force_explode_nuclear =
6586  "actions.force_explode_nuclear");
6587 
6588  if (force_explode_nuclear) {
6589  BV_SET(action_by_number(ACTION_SUICIDE_ATTACK)->blocked_by,
6590  ACTION_NUKE);
6591  BV_SET(action_by_number(ACTION_ATTACK)->blocked_by, ACTION_NUKE);
6592  BV_SET(action_by_number(ACTION_CONQUER_CITY)->blocked_by,
6593  ACTION_NUKE);
6594  BV_SET(action_by_number(ACTION_CONQUER_CITY2)->blocked_by,
6595  ACTION_NUKE);
6596  BV_SET(action_by_number(ACTION_SUICIDE_ATTACK)->blocked_by,
6597  ACTION_NUKE_CITY);
6598  BV_SET(action_by_number(ACTION_ATTACK)->blocked_by,
6599  ACTION_NUKE_CITY);
6600  BV_SET(action_by_number(ACTION_CONQUER_CITY)->blocked_by,
6601  ACTION_NUKE_CITY);
6602  BV_SET(action_by_number(ACTION_CONQUER_CITY2)->blocked_by,
6603  ACTION_NUKE_CITY);
6604  BV_SET(action_by_number(ACTION_SUICIDE_ATTACK)->blocked_by,
6605  ACTION_NUKE_UNITS);
6606  BV_SET(action_by_number(ACTION_ATTACK)->blocked_by,
6607  ACTION_NUKE_UNITS);
6608  BV_SET(action_by_number(ACTION_CONQUER_CITY)->blocked_by,
6609  ACTION_NUKE_UNITS);
6610  BV_SET(action_by_number(ACTION_CONQUER_CITY2)->blocked_by,
6611  ACTION_NUKE_UNITS);
6612  }
6613 
6614  /* If the "Poison City" action or the "Poison City Escape" action
6615  * should empty the granary. */
6616  /* TODO: empty granary and reduce population should become separate
6617  * action effect flags when actions are generalized. */
6618  game.info.poison_empties_food_stock = secfile_lookup_bool_default(
6620  "actions.poison_empties_food_stock");
6621 
6622  /* If the "Steal Maps" action or the "Steal Maps Escape" action always
6623  * will reveal all cities when successful. */
6624  game.info.steal_maps_reveals_all_cities = secfile_lookup_bool_default(
6626  "actions.steal_maps_reveals_all_cities");
6627 
6628  /* Allow setting required distance for some actions before generalized
6629  * actions. */
6630  action_iterate(act_id)
6631  {
6632  if (!load_action_range(file, act_id)) {
6633  ok = false;
6634  }
6635  if (!load_action_kind(file, act_id)) {
6636  ok = false;
6637  }
6638  if (!load_action_actor_consuming_always(file, act_id)) {
6639  ok = false;
6640  }
6641  load_action_ui_name(file, act_id,
6643  }
6645 
6646  /* The quiet (don't auto generate help for) property of all actions
6647  * live in a single enum vector. This avoids generic action
6648  * expectations. */
6649  if (secfile_entry_by_path(file, "actions.quiet_actions")) {
6650  enum gen_action *quiet_actions;
6651  size_t asize;
6652  int j;
6653 
6654  quiet_actions = secfile_lookup_enum_vec(file, &asize, gen_action,
6655  "actions.quiet_actions");
6656 
6657  if (!quiet_actions) {
6658  // Entity exists but couldn't read it.
6659  qCCritical(ruleset_category,
6660  "\"%s\": actions.quiet_actions: bad action list",
6661  filename);
6662 
6663  ok = false;
6664  }
6665 
6666  for (j = 0; j < asize; j++) {
6667  // Don't auto generate help text for this action.
6668  action_by_number(quiet_actions[j])->quiet = true;
6669  }
6670 
6671  delete[] quiet_actions;
6672  quiet_actions = nullptr;
6673  }
6674  }
6675 
6676  if (ok) {
6679 
6680  if (sec) {
6681  section_list_iterate(sec, psection)
6682  {
6683  struct action_enabler *enabler;
6684  const char *sec_name = section_name(psection);
6685  struct action *paction;
6686  struct requirement_vector *actor_reqs;
6687  struct requirement_vector *target_reqs;
6688  const char *action_text;
6689 
6690  enabler = action_enabler_new();
6691 
6692  action_text = secfile_lookup_str(file, "%s.action", sec_name);
6693 
6694  if (action_text == nullptr) {
6695  qCCritical(ruleset_category,
6696  "\"%s\" [%s] missing action to enable.", filename,
6697  sec_name);
6698  ok = false;
6699  break;
6700  }
6701 
6702  paction = action_by_rule_name(action_text);
6703  if (!paction) {
6704  qCCritical(ruleset_category,
6705  "\"%s\" [%s] lists unknown action type \"%s\".",
6706  filename, sec_name, action_text);
6707  ok = false;
6708  break;
6709  }
6710 
6711  enabler->action = paction->id;
6712 
6713  actor_reqs = lookup_req_list(file, compat, sec_name, "actor_reqs",
6714  action_text);
6715  if (actor_reqs == nullptr) {
6716  ok = false;
6717  break;
6718  }
6719 
6720  requirement_vector_copy(&enabler->actor_reqs, actor_reqs);
6721 
6722  target_reqs = lookup_req_list(file, compat, sec_name,
6723  "target_reqs", action_text);
6724  if (target_reqs == nullptr) {
6725  ok = false;
6726  break;
6727  }
6728 
6729  requirement_vector_copy(&enabler->target_reqs, target_reqs);
6730 
6731  action_enabler_add(enabler);
6732  }
6734  section_list_destroy(sec);
6735  }
6736  }
6737  }
6738 
6739  if (compat->compat_mode) {
6740  bool slow_invasions = secfile_lookup_bool_default(
6741  file, true, "global_unit_options.slow_invasions");
6742 
6743  if (!rscompat_old_slow_invasions_3_1(compat, slow_invasions)) {
6744  ok = false;
6745  }
6746  }
6747 
6748  if (ok) {
6749  const char *tus_text;
6750 
6751  // section: combat_rules
6752  game.info.tired_attack = secfile_lookup_bool_default(
6753  file, RS_DEFAULT_TIRED_ATTACK, "combat_rules.tired_attack");
6754 
6755  game.info.only_killing_makes_veteran = secfile_lookup_bool_default(
6757  "combat_rules.only_killing_makes_veteran");
6758 
6759  game.info.nuke_pop_loss_pct = secfile_lookup_int_default_min_max(
6761  RS_MAX_NUKE_POP_LOSS_PCT, "combat_rules.nuke_pop_loss_pct");
6762 
6763  game.info.nuke_defender_survival_chance_pct =
6768  "combat_rules.nuke_defender_survival_chance_pct");
6769 
6770  // section: borders
6771  game.info.border_city_radius_sq = secfile_lookup_int_default_min_max(
6773  RS_MAX_BORDER_RADIUS_SQ_CITY, "borders.radius_sq_city");
6774  game.info.border_size_effect = secfile_lookup_int_default_min_max(
6776  RS_MAX_BORDER_SIZE_EFFECT, "borders.size_effect");
6777 
6778  game.info.border_city_permanent_radius_sq =
6783  "borders.radius_sq_city_permanent");
6784 
6785  // section: research
6787  "research.tech_cost_style");
6788  game.info.tech_cost_style =
6789  tech_cost_style_by_name(tus_text, fc_strcasecmp);
6790  if (!tech_cost_style_is_valid(game.info.tech_cost_style)) {
6791  qCCritical(ruleset_category, "Unknown tech cost style \"%s\"",
6792  tus_text);
6793  ok = false;
6794  }
6795 
6797  "research.tech_leakage");
6798  game.info.tech_leakage =
6799  tech_leakage_style_by_name(tus_text, fc_strcasecmp);
6800  if (!tech_leakage_style_is_valid(game.info.tech_leakage)) {
6801  qCCritical(ruleset_category, "Unknown tech leakage \"%s\"", tus_text);
6802  ok = false;
6803  }
6804  if (game.info.tech_cost_style == TECH_COST_CIV1CIV2
6805  && game.info.tech_leakage != TECH_LEAKAGE_NONE) {
6806  qCritical("Only tech_leakage \"%s\" supported with "
6807  "tech_cost_style \"%s\". ",
6808  tech_leakage_style_name(TECH_LEAKAGE_NONE),
6809  tech_cost_style_name(TECH_COST_CIV1CIV2));
6810  qCritical("Switching to tech_leakage \"%s\".",
6811  tech_leakage_style_name(TECH_LEAKAGE_NONE));
6812  game.info.tech_leakage = TECH_LEAKAGE_NONE;
6813  }
6814  game.info.base_tech_cost = secfile_lookup_int_default_min_max(
6816  RS_MAX_BASE_TECH_COST, "research.base_tech_cost");
6817 
6819  "research.tech_upkeep_style");
6820 
6821  game.info.tech_upkeep_style =
6822  tech_upkeep_style_by_name(tus_text, fc_strcasecmp);
6823 
6824  if (!tech_upkeep_style_is_valid(game.info.tech_upkeep_style)) {
6825  qCCritical(ruleset_category, "Unknown tech upkeep style \"%s\"",
6826  tus_text);
6827  ok = false;
6828  }
6829  }
6830 
6831  if (ok) {
6832  game.info.tech_upkeep_divider = secfile_lookup_int_default_min_max(
6834  RS_MAX_TECH_UPKEEP_DIVIDER, "research.tech_upkeep_divider");
6835 
6836  sval = secfile_lookup_str_default(file, nullptr,
6837  "research.free_tech_method");
6838  if (sval == nullptr) {
6839  qCCritical(ruleset_category, "No free_tech_method given");
6840  ok = false;
6841  } else {
6842  game.info.free_tech_method =
6843  free_tech_method_by_name(sval, fc_strcasecmp);
6844  if (!free_tech_method_is_valid(game.info.free_tech_method)) {
6845  qCCritical(ruleset_category, "Bad value %s for free_tech_method.",
6846  sval);
6847  ok = false;
6848  }
6849  }
6850  }
6851 
6852  if (ok) {
6853  int cf;
6854 
6855  // section: culture
6856  game.info.culture_vic_points = secfile_lookup_int_default(
6857  file, RS_DEFAULT_CULTURE_VIC_POINTS, "culture.victory_min_points");
6858  game.info.culture_vic_lead = secfile_lookup_int_default(
6859  file, RS_DEFAULT_CULTURE_VIC_LEAD, "culture.victory_lead_pct");
6860  game.info.culture_migration_pml = secfile_lookup_int_default(
6861  file, RS_DEFAULT_CULTURE_MIGRATION_PML, "culture.migration_pml");
6862  game.info.history_interest_pml =
6864  "culture.history_interest_pml");
6865 
6866  // section: calendar
6867  game.calendar.calendar_skip_0 = secfile_lookup_bool_default(
6868  file, RS_DEFAULT_CALENDAR_SKIP_0, "calendar.skip_year_0");
6869  game.server.start_year = secfile_lookup_int_default(
6870  file, GAME_START_YEAR, "calendar.start_year");
6871  game.calendar.calendar_fragments =
6872  secfile_lookup_int_default(file, 0, "calendar.fragments");
6873 
6874  if (game.calendar.calendar_fragments > MAX_CALENDAR_FRAGMENTS) {
6875  qCCritical(ruleset_category, "Too many calendar fragments. Max is %d",
6877  ok = false;
6878  game.calendar.calendar_fragments = 0;
6879  }
6880  sz_strlcpy(game.calendar.positive_year_label,
6882  "calendar.positive_label"));
6883  sz_strlcpy(game.calendar.negative_year_label,
6885  "calendar.negative_label"));
6886 
6887  for (cf = 0; cf < game.calendar.calendar_fragments; cf++) {
6888  const char *fname;
6889 
6890  fname = secfile_lookup_str_default(file, nullptr,
6891  "calendar.fragment_name%d", cf);
6892  if (fname != nullptr) {
6893  qstrncpy(game.calendar.calendar_fragment_name[cf], fname,
6894  sizeof(game.calendar.calendar_fragment_name[cf]));
6895  }
6896  }
6897  }
6898 
6899  if (ok) {
6900  // section playercolors
6901  struct rgbcolor *prgbcolor = nullptr;
6902  bool color_read = true;
6903 
6904  // Check if the player list is defined and empty.
6905  if (playercolor_count() != 0) {
6906  ok = false;
6907  } else {
6908  i = 0;
6909 
6910  while (color_read) {
6911  prgbcolor = nullptr;
6912 
6913  color_read =
6914  rgbcolor_load(file, &prgbcolor, "playercolors.colorlist%d", i);
6915  if (color_read) {
6916  playercolor_add(prgbcolor);
6917  }
6918 
6919  i++;
6920  }
6921 
6922  if (playercolor_count() == 0) {
6923  qCCritical(ruleset_category, "No player colors defined!");
6924  ok = false;
6925  }
6926 
6927  if (ok) {
6928  fc_assert(game.plr_bg_color == nullptr);
6929  if (!rgbcolor_load(file, &game.plr_bg_color,
6930  "playercolors.background")) {
6931  qCCritical(ruleset_category,
6932  "No background player color defined! (%s)",
6933  secfile_error());
6934  ok = false;
6935  }
6936  }
6937  }
6938  }
6939 
6940  if (ok) {
6941  // section: teams
6942  svec = secfile_lookup_str_vec(file, &teams, "teams.names");
6943  if (team_slot_count() < teams) {
6944  teams = team_slot_count();
6945  }
6946  game.server.ruledit.named_teams = teams;
6947  for (i = 0; i < teams; i++) {
6949  }
6950  delete[] svec;
6951  svec = nullptr;
6952 
6954  nval = (nullptr != sec ? section_list_size(sec) : 0);
6955  if (nval > MAX_DISASTER_TYPES) {
6956  int num = nval; // No "size_t" to printf
6957 
6958  qCCritical(ruleset_category,
6959  "\"%s\": Too many disaster types (%d, max %d)", filename,
6960  num, MAX_DISASTER_TYPES);
6961  section_list_destroy(sec);
6962  ok = false;
6963  } else {
6964  game.control.num_disaster_types = nval;
6965  }
6966  }
6967 
6968  if (ok) {
6969  disaster_type_iterate(pdis)
6970  {
6971  int id = disaster_index(pdis);
6972  int j;
6973  size_t eff_count;
6974  struct requirement_vector *reqs;
6975  const char *sec_name = section_name(section_list_get(sec, id));
6976 
6977  if (!ruleset_load_names(&pdis->name, nullptr, file, sec_name)) {
6978  qCCritical(ruleset_category, "\"%s\": Cannot load disaster names",
6979  filename);
6980  ok = false;
6981  break;
6982  }
6983 
6984  reqs = lookup_req_list(file, compat, sec_name, "reqs",
6985  disaster_rule_name(pdis));
6986  if (reqs == nullptr) {
6987  ok = false;
6988  break;
6989  }
6990  requirement_vector_copy(&pdis->reqs, reqs);
6991 
6992  pdis->frequency = secfile_lookup_int_default(
6993  file, GAME_DEFAULT_DISASTER_FREQ, "%s.frequency", sec_name);
6994 
6995  svec =
6996  secfile_lookup_str_vec(file, &eff_count, "%s.effects", sec_name);
6997 
6998  BV_CLR_ALL(pdis->effects);
6999  for (j = 0; j < eff_count; j++) {
7000  const char *dsval = svec[j];
7001  enum disaster_effect_id effect;
7002 
7003  effect = disaster_effect_id_by_name(dsval, fc_strcasecmp);
7004 
7005  if (!disaster_effect_id_is_valid(effect)) {
7006  qCCritical(ruleset_category,
7007  "\"%s\" disaster \"%s\": unknown effect \"%s\".",
7008  filename, disaster_rule_name(pdis), dsval);
7009  ok = false;
7010  break;
7011  } else {
7012  BV_SET(pdis->effects, effect);
7013  }
7014  }
7015 
7016  delete[] svec;
7017  svec = nullptr;
7018 
7019  if (!ok) {
7020  break;
7021  }
7022  }
7024  section_list_destroy(sec);
7025  }
7026 
7027  if (ok) {
7029 
7030  achievements_iterate(pach)
7031  {
7032  int id = achievement_index(pach);
7033  const char *sec_name = section_name(section_list_get(sec, id));
7034  const char *type_name;
7035  const char *msg;
7036 
7037  type_name =
7038  secfile_lookup_str_default(file, nullptr, "%s.type", sec_name);
7039 
7040  pach->type = achievement_type_by_name(type_name, fc_strcasecmp);
7041  if (!achievement_type_is_valid(pach->type)) {
7042  qCCritical(ruleset_category, "Achievement has unknown type \"%s\".",
7043  type_name != nullptr ? type_name : "(nullptr)");
7044  ok = false;
7045  }
7046 
7047  if (ok) {
7048  pach->unique = secfile_lookup_bool_default(
7049  file, GAME_DEFAULT_ACH_UNIQUE, "%s.unique", sec_name);
7050 
7051  pach->value = secfile_lookup_int_default(
7052  file, GAME_DEFAULT_ACH_VALUE, "%s.value", sec_name);
7053  pach->culture =
7054  secfile_lookup_int_default(file, 0, "%s.culture", sec_name);
7055 
7056  msg = secfile_lookup_str_default(file, nullptr, "%s.first_msg",
7057  sec_name);
7058  if (msg == nullptr) {
7059  qCCritical(ruleset_category, "Achievement %s has no first msg!",
7060  sec_name);
7061  ok = false;
7062  } else {
7063  pach->first_msg = fc_strdup(msg);
7064  }
7065  }
7066 
7067  if (ok) {
7068  msg = secfile_lookup_str_default(file, nullptr, "%s.cons_msg",
7069  sec_name);
7070  if (msg == nullptr) {
7071  if (!pach->unique) {
7072  qCCritical(ruleset_category,
7073  "Achievement %s has no msg for consecutive gainers!",
7074  sec_name);
7075  ok = false;
7076  }
7077  } else {
7078  pach->cons_msg = fc_strdup(msg);
7079  }
7080  }
7081 
7082  if (!ok) {
7083  break;
7084  }
7085  }
7087  section_list_destroy(sec);
7088  }
7089 
7090  if (ok) {
7091  for (i = 0; (name = secfile_lookup_str_default(
7092  file, nullptr, "trade.settings%d.type", i));
7093  i++) {
7095 
7096  if (type == TRT_LAST) {
7097  qCCritical(ruleset_category,
7098  "\"%s\" unknown trade route type \"%s\".", filename,
7099  name);
7100  ok = false;
7101  } else {
7102  struct trade_route_settings *set =
7104  const char *cancelling;
7105  const char *bonus;
7106 
7107  set->trade_pct =
7108  secfile_lookup_int_default(file, 100, "trade.settings%d.pct", i);
7110  file, "Active", "trade.settings%d.cancelling", i);
7112  if (set->cancelling == TRI_LAST) {
7113  qCCritical(ruleset_category,
7114  "\"%s\" unknown traderoute cancelling type \"%s\".",
7115  filename, cancelling);
7116  ok = false;
7117  }
7118 
7119  bonus = secfile_lookup_str_default(file, "None",
7120  "trade.settings%d.bonus", i);
7121 
7122  set->bonus_type =
7123  traderoute_bonus_type_by_name(bonus, fc_strcasecmp);
7124 
7125  if (!traderoute_bonus_type_is_valid(set->bonus_type)) {
7126  qCCritical(ruleset_category,
7127  "\"%s\" unknown traderoute bonus type \"%s\".",
7128  filename, bonus);
7129  ok = false;
7130  }
7131  }
7132  }
7133  }
7134 
7135  if (ok) {
7136  const char *str =
7137  secfile_lookup_str_default(file, "Leaving", "trade.goods_selection");
7138 
7139  game.info.goods_selection =
7140  goods_selection_method_by_name(str, fc_strcasecmp);
7141 
7142  if (!goods_selection_method_is_valid(game.info.goods_selection)) {
7143  qCCritical(ruleset_category,
7144  "\"%s\" goods selection method \"%s\" unknown.", filename,
7145  str);
7146  ok = false;
7147  }
7148  }
7149 
7150  if (ok) {
7152 
7153  goods_type_iterate(pgood)
7154  {
7155  int id = goods_index(pgood);
7156  const char *sec_name = section_name(section_list_get(sec, id));
7157  struct requirement_vector *reqs;
7158  const char **slist;
7159  int j;
7160 
7161  reqs = lookup_req_list(file, compat, sec_name, "reqs",
7162  goods_rule_name(pgood));
7163  if (reqs == nullptr) {
7164  ok = false;
7165  break;
7166  }
7167  requirement_vector_copy(&pgood->reqs, reqs);
7168 
7169  pgood->from_pct =
7170  secfile_lookup_int_default(file, 100, "%s.from_pct", sec_name);
7171  pgood->to_pct =
7172  secfile_lookup_int_default(file, 100, "%s.to_pct", sec_name);
7173  pgood->onetime_pct =
7174  secfile_lookup_int_default(file, 100, "%s.onetime_pct", sec_name);
7175 
7176  slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name);
7177  BV_CLR_ALL(pgood->flags);
7178  for (j = 0; j < nval; j++) {
7179  enum goods_flag_id flag;
7180 
7181  sval = slist[j];
7182  flag = goods_flag_id_by_name(sval, fc_strcasecmp);
7183  if (!goods_flag_id_is_valid(flag)) {
7184  qCCritical(ruleset_category,
7185  "\"%s\" good \"%s\": unknown flag \"%s\".", filename,
7186  goods_rule_name(pgood), sval);
7187  ok = false;
7188  break;
7189  } else {
7190  BV_SET(pgood->flags, flag);
7191  }
7192  }
7193  delete[] slist;
7194  slist = nullptr;
7195 
7196  pgood->helptext = lookup_strvec(file, sec_name, "helptext");
7197  }
7199  section_list_destroy(sec);
7200  }
7201 
7202  if (ok) {
7204 
7205  if (sec != nullptr) {
7206  int num = section_list_size(sec);
7207 
7208  for (i = 0; i < num; i++) {
7209  const char *sec_name = section_name(section_list_get(sec, i));
7210  const char *clause_name =
7211  secfile_lookup_str_default(file, nullptr, "%s.type", sec_name);
7212  enum clause_type type =
7213  clause_type_by_name(clause_name, fc_strcasecmp);
7214  struct clause_info *info;
7215  struct requirement_vector *reqs;
7216 
7217  if (!clause_type_is_valid(type)) {
7218  qCCritical(ruleset_category, "\"%s\" unknown clause type \"%s\".",
7219  filename, clause_name);
7220  ok = false;
7221  break;
7222  }
7223 
7224  info = clause_info_get(type);
7225 
7226  if (info->enabled) {
7227  qCCritical(ruleset_category,
7228  "\"%s\" dublicate clause type \"%s\" definition.",
7229  filename, clause_name);
7230  ok = false;
7231  break;
7232  }
7233 
7234  reqs = lookup_req_list(file, compat, sec_name, "giver_reqs",
7235  clause_name);
7236  if (reqs == nullptr) {
7237  ok = false;
7238  break;
7239  }
7240  requirement_vector_copy(&info->giver_reqs, reqs);
7241 
7242  reqs = lookup_req_list(file, compat, sec_name, "receiver_reqs",
7243  clause_name);
7244  if (reqs == nullptr) {
7245  ok = false;
7246  break;
7247  }
7248  requirement_vector_copy(&info->receiver_reqs, reqs);
7249 
7250  info->enabled = true;
7251  }
7252  }
7253  section_list_destroy(sec);
7254  }
7255 
7256  /* secfile_check_unused() is not here, but only after also settings section
7257  * has been loaded. */
7258 
7259  return ok;
7260 }
7261 
7266 static void send_ruleset_unit_classes(struct conn_list *dest)
7267 {
7268  struct packet_ruleset_unit_class packet;
7269  struct packet_ruleset_unit_class_flag fpacket;
7270  int i;
7271 
7272  for (i = 0; i < MAX_NUM_USER_UCLASS_FLAGS; i++) {
7273  const char *flagname;
7274  const char *helptxt;
7275 
7276  fpacket.id = i + UCF_USER_FLAG_1;
7277 
7278  flagname =
7279  unit_class_flag_id_name(unit_class_flag_id(i + UCF_USER_FLAG_1));
7280  if (flagname == nullptr) {
7281  fpacket.name[0] = '\0';
7282  } else {
7283  sz_strlcpy(fpacket.name, flagname);
7284  }
7285 
7286  helptxt =
7287  unit_class_flag_helptxt(unit_class_flag_id(i + UCF_USER_FLAG_1));
7288  if (helptxt == nullptr) {
7289  fpacket.helptxt[0] = '\0';
7290  } else {
7291  sz_strlcpy(fpacket.helptxt, helptxt);
7292  }
7293 
7294  lsend_packet_ruleset_unit_class_flag(dest, &fpacket);
7295  }
7296 
7298  {
7299  packet.id = uclass_number(c);
7300  sz_strlcpy(packet.name, untranslated_name(&c->name));
7301  sz_strlcpy(packet.rule_name, rule_name_get(&c->name));
7302  packet.min_speed = c->min_speed;
7303  packet.hp_loss_pct = c->hp_loss_pct;
7304  packet.hut_behavior = c->hut_behavior;
7305  packet.non_native_def_pct = c->non_native_def_pct;
7306  packet.flags = c->flags;
7307 
7308  packet_strvec_compute(packet.helptext, c->helptext);
7309 
7310  lsend_packet_ruleset_unit_class(dest, &packet);
7311  }
7313 }
7314 
7319 static void send_ruleset_units(struct conn_list *dest)
7320 {
7321  struct packet_ruleset_unit packet;
7322  struct packet_ruleset_unit_flag fpacket;
7323  int i;
7324 
7325  for (i = 0; i < MAX_NUM_USER_UNIT_FLAGS; i++) {
7326  const char *flagname;
7327  const char *helptxt;
7328 
7329  fpacket.id = i + UTYF_USER_FLAG_1;
7330 
7331  flagname =
7332  unit_type_flag_id_name(unit_type_flag_id(i + UTYF_USER_FLAG_1));
7333  if (flagname == nullptr) {
7334  fpacket.name[0] = '\0';
7335  } else {
7336  sz_strlcpy(fpacket.name, flagname);
7337  }
7338 
7339  helptxt =
7340  unit_type_flag_helptxt(unit_type_flag_id(i + UTYF_USER_FLAG_1));
7341  if (helptxt == nullptr) {
7342  fpacket.helptxt[0] = '\0';
7343  } else {
7344  sz_strlcpy(fpacket.helptxt, helptxt);
7345  }
7346 
7347  lsend_packet_ruleset_unit_flag(dest, &fpacket);
7348  }
7349 
7351  {
7352  packet.id = utype_number(u);
7353  sz_strlcpy(packet.name, untranslated_name(&u->name));
7354  sz_strlcpy(packet.rule_name, rule_name_get(&u->name));
7355  sz_strlcpy(packet.sound_move, u->sound_move);
7356  sz_strlcpy(packet.sound_move_alt, u->sound_move_alt);
7357  sz_strlcpy(packet.sound_fight, u->sound_fight);
7358  sz_strlcpy(packet.sound_fight_alt, u->sound_fight_alt);
7359  sz_strlcpy(packet.graphic_str, u->graphic_str);
7360  sz_strlcpy(packet.graphic_alt, u->graphic_alt);
7361  packet.unit_class_id = uclass_number(utype_class(u));
7362  packet.build_cost = u->build_cost;
7363  packet.pop_cost = u->pop_cost;
7364  packet.attack_strength = u->attack_strength;
7365  packet.defense_strength = u->defense_strength;
7366  packet.move_rate = u->move_rate;
7367  packet.tech_requirement = u->require_advance
7368  ? advance_number(u->require_advance)
7369  : advance_count();
7370 
7371  i = 0;
7372  requirement_vector_iterate(&u->build_reqs, req)
7373  {
7374  packet.build_reqs[i++] = *req;
7375  }
7377  packet.build_reqs_count = i;
7378 
7379  packet.vision_radius_sq = u->vision_radius_sq;
7380  packet.transport_capacity = u->transport_capacity;
7381  packet.hp = u->hp;
7382  packet.firepower = u->firepower;
7383  packet.obsoleted_by =
7384  u->obsoleted_by ? utype_number(u->obsoleted_by) : utype_count();
7385  packet.converted_to =
7386  u->converted_to ? utype_number(u->converted_to) : utype_count();
7387  packet.convert_time = u->convert_time;
7388  packet.fuel = u->fuel;
7389  packet.flags = u->flags;
7390  packet.roles = u->roles;
7391  packet.happy_cost = u->happy_cost;
7392  output_type_iterate(o) { packet.upkeep[o] = u->upkeep[o]; }
7394  packet.paratroopers_range = u->paratroopers_range;
7395  packet.bombard_rate = u->bombard_rate;
7396  packet.city_size = u->city_size;
7397  packet.city_slots = u->city_slots;
7398  packet.cargo = u->cargo;
7399  packet.targets = u->targets;
7400  packet.embarks = u->embarks;
7401  packet.disembarks = u->disembarks;
7402  packet.vlayer = u->vlayer;
7403 
7404  if (u->veteran == nullptr) {
7405  // Use the default veteran system.
7406  packet.veteran_levels = 0;
7407  } else {
7408  // Per unit veteran system definition.
7409  packet.veteran_levels = utype_veteran_levels(u);
7410 
7411  for (i = 0; i < packet.veteran_levels; i++) {
7412  const struct veteran_level *vlevel = utype_veteran_level(u, i);
7413 
7414  sz_strlcpy(packet.veteran_name[i], untranslated_name(&vlevel->name));
7415  packet.power_fact[i] = vlevel->power_fact;
7416  packet.move_bonus[i] = vlevel->move_bonus;
7417  packet.base_raise_chance[i] = vlevel->base_raise_chance;
7418  packet.work_raise_chance[i] = vlevel->work_raise_chance;
7419  }
7420  }
7421  packet_strvec_compute(packet.helptext, u->helptext);
7422 
7423  packet.worker = u->adv.worker;
7424 
7425  lsend_packet_ruleset_unit(dest, &packet);
7426 
7427  combat_bonus_list_iterate(u->bonuses, pbonus)
7428  {
7429  struct packet_ruleset_unit_bonus bonuspacket;
7430 
7431  bonuspacket.unit = packet.id;
7432  bonuspacket.flag = pbonus->flag;
7433  bonuspacket.type = pbonus->type;
7434  bonuspacket.value = pbonus->value;
7435  bonuspacket.quiet = pbonus->quiet;
7436 
7437  lsend_packet_ruleset_unit_bonus(dest, &bonuspacket);
7438  }
7440  }
7442 }
7443 
7448 static void send_ruleset_specialists(struct conn_list *dest)
7449 {
7450  struct packet_ruleset_specialist packet;
7451 
7452  specialist_type_iterate(spec_id)
7453  {
7454  struct specialist *s = specialist_by_number(spec_id);
7455  int j;
7456 
7457  packet.id = spec_id;
7458  sz_strlcpy(packet.plural_name, untranslated_name(&s->name));
7459  sz_strlcpy(packet.rule_name, rule_name_get(&s->name));
7460  sz_strlcpy(packet.short_name, untranslated_name(&s->abbreviation));
7461  sz_strlcpy(packet.graphic_str, s->graphic_str);
7462  sz_strlcpy(packet.graphic_alt, s->graphic_alt);
7463  j = 0;
7464  requirement_vector_iterate(&s->reqs, preq) { packet.reqs[j++] = *preq; }
7466  packet.reqs_count = j;
7467 
7468  packet_strvec_compute(packet.helptext, s->helptext);
7469 
7470  lsend_packet_ruleset_specialist(dest, &packet);
7471  }
7473 }
7477 static void send_ruleset_tech_classes(struct conn_list *dest)
7478 {
7479  struct packet_ruleset_tech_class packet;
7480 
7481  tech_class_iterate(ptclass)
7482  {
7483  packet.id = ptclass->idx;
7484  sz_strlcpy(packet.name, untranslated_name(&ptclass->name));
7485  sz_strlcpy(packet.rule_name, rule_name_get(&ptclass->name));
7486  packet.cost_pct = ptclass->cost_pct;
7487 
7488  lsend_packet_ruleset_tech_class(dest, &packet);
7489  }
7491 }
7492 
7497 static void send_ruleset_techs(struct conn_list *dest)
7498 {
7499  struct packet_ruleset_tech packet;
7500  struct packet_ruleset_tech_flag fpacket;
7501  int i;
7502 
7503  for (i = 0; i < MAX_NUM_USER_TECH_FLAGS; i++) {
7504  const char *flagname;
7505  const char *helptxt;
7506 
7507  fpacket.id = i + TECH_USER_1;
7508 
7509  flagname = tech_flag_id_name_cb(tech_flag_id(i + TECH_USER_1));
7510  if (flagname == nullptr) {
7511  fpacket.name[0] = '\0';
7512  } else {
7513  sz_strlcpy(fpacket.name, flagname);
7514  }
7515 
7516  helptxt = tech_flag_helptxt(tech_flag_id(i + TECH_USER_1));
7517  if (helptxt == nullptr) {
7518  fpacket.helptxt[0] = '\0';
7519  } else {
7520  sz_strlcpy(fpacket.helptxt, helptxt);
7521  }
7522 
7523  lsend_packet_ruleset_tech_flag(dest, &fpacket);
7524  }
7525 
7527  {
7528  packet.id = advance_number(a);
7529  packet.removed = !valid_advance(a);
7530  if (a->tclass == nullptr) {
7531  packet.tclass = 0;
7532  } else {
7533  packet.tclass = a->tclass->idx;
7534  }
7535  sz_strlcpy(packet.name, untranslated_name(&a->name));
7536  sz_strlcpy(packet.rule_name, rule_name_get(&a->name));
7537  sz_strlcpy(packet.graphic_str, a->graphic_str);
7538  sz_strlcpy(packet.graphic_alt, a->graphic_alt);
7539 
7540  // Current size of the packet's research_reqs requirement vector.
7541  i = 0;
7542 
7543  /* The requirements req1 and req2 are needed to research a tech. Send
7544  * them in the research_reqs requirement vector. Range is set to player
7545  * since pooled research is configurable. */
7546 
7547  if ((a->require[AR_ONE] != A_NEVER)
7548  && advance_number(a->require[AR_ONE]) > A_NONE) {
7549  packet.research_reqs[i++] =
7550  req_from_values(VUT_ADVANCE, REQ_RANGE_PLAYER, false, true, false,
7551  advance_number(a->require[AR_ONE]));
7552  }
7553 
7554  if ((a->require[AR_TWO] != A_NEVER)
7555  && advance_number(a->require[AR_TWO]) > A_NONE) {
7556  packet.research_reqs[i++] =
7557  req_from_values(VUT_ADVANCE, REQ_RANGE_PLAYER, false, true, false,
7558  advance_number(a->require[AR_TWO]));
7559  ;
7560  }
7561 
7562  /* The requirements of the tech's research_reqs also goes in the
7563  * packet's research_reqs requirement vector. */
7564  requirement_vector_iterate(&a->research_reqs, req)
7565  {
7566  packet.research_reqs[i++] = *req;
7567  }
7569 
7570  /* The packet's research_reqs should contain req1, req2 and the
7571  * requirements of the tech's research_reqs. */
7572  packet.research_reqs_count = i;
7573 
7574  packet.root_req = a->require[AR_ROOT]
7575  ? advance_number(a->require[AR_ROOT])
7576  : advance_count();
7577 
7578  packet.flags = a->flags;
7579  packet.cost = a->cost;
7580  packet.num_reqs = a->num_reqs;
7581  packet_strvec_compute(packet.helptext, a->helptext);
7582 
7583  lsend_packet_ruleset_tech(dest, &packet);
7584  }
7586 }
7587 
7592 static void send_ruleset_buildings(struct conn_list *dest)
7593 {
7595  {
7596  struct packet_ruleset_building packet;
7597  int j;
7598 
7599  packet.id = improvement_number(b);
7600  packet.genus = b->genus;
7601  sz_strlcpy(packet.name, untranslated_name(&b->name));
7602  sz_strlcpy(packet.rule_name, rule_name_get(&b->name));
7603  sz_strlcpy(packet.graphic_str, b->graphic_str);
7604  sz_strlcpy(packet.graphic_alt, b->graphic_alt);
7605  j = 0;
7606  requirement_vector_iterate(&b->reqs, preq) { packet.reqs[j++] = *preq; }
7608  packet.reqs_count = j;
7609  j = 0;
7610  requirement_vector_iterate(&b->obsolete_by, pobs)
7611  {
7612  packet.obs_reqs[j++] = *pobs;
7613  }
7615  packet.obs_count = j;
7616  packet.build_cost = b->build_cost;
7617  packet.upkeep = b->upkeep;
7618  packet.sabotage = b->sabotage;
7619  packet.flags = b->flags;
7620  sz_strlcpy(packet.soundtag, b->soundtag);
7621  sz_strlcpy(packet.soundtag_alt, b->soundtag_alt);
7622  packet_strvec_compute(packet.helptext, b->helptext);
7623 
7624  lsend_packet_ruleset_building(dest, &packet);
7625  }
7627 }
7628 
7633 static void send_ruleset_terrain(struct conn_list *dest)
7634 {
7635  struct packet_ruleset_terrain packet;
7636  struct packet_ruleset_terrain_flag fpacket;
7637  int i;
7638 
7639  lsend_packet_ruleset_terrain_control(dest, &terrain_control);
7640 
7641  for (i = 0; i < MAX_NUM_USER_TER_FLAGS; i++) {
7642  const char *flagname;
7643  const char *helptxt;
7644 
7645  fpacket.id = i + TER_USER_1;
7646 
7647  flagname = terrain_flag_id_name_cb(terrain_flag_id(i + TER_USER_1));
7648  if (flagname == nullptr) {
7649  fpacket.name[0] = '\0';
7650  } else {
7651  sz_strlcpy(fpacket.name, flagname);
7652  }
7653 
7654  helptxt = terrain_flag_helptxt(terrain_flag_id(i + TER_USER_1));
7655  if (helptxt == nullptr) {
7656  fpacket.helptxt[0] = '\0';
7657  } else {
7658  sz_strlcpy(fpacket.helptxt, helptxt);
7659  }
7660 
7661  lsend_packet_ruleset_terrain_flag(dest, &fpacket);
7662  }
7663 
7664  terrain_type_iterate(pterrain)
7665  {
7666  struct extra_type **r;
7667 
7668  packet.id = terrain_number(pterrain);
7669  packet.tclass = pterrain->tclass;
7670  packet.native_to = pterrain->native_to;
7671 
7672  sz_strlcpy(packet.name, untranslated_name(&pterrain->name));
7673  sz_strlcpy(packet.rule_name, rule_name_get(&pterrain->name));
7674  sz_strlcpy(packet.graphic_str, pterrain->graphic_str);
7675  sz_strlcpy(packet.graphic_alt, pterrain->graphic_alt);
7676 
7677  packet.movement_cost = pterrain->movement_cost;
7678  packet.defense_bonus = pterrain->defense_bonus;
7679 
7680  output_type_iterate(o) { packet.output[o] = pterrain->output[o]; }
7682 
7683  packet.num_resources = 0;
7684  for (r = pterrain->resources; *r; r++) {
7685  packet.resources[packet.num_resources++] = extra_number(*r);
7686  }
7687 
7689  {
7690  packet.road_output_incr_pct[o] = pterrain->road_output_incr_pct[o];
7691  }
7693 
7694  packet.base_time = pterrain->base_time;
7695  packet.road_time = pterrain->road_time;
7696 
7697  packet.cultivate_time = pterrain->cultivate_time;
7698 
7699  packet.plant_time = pterrain->plant_time;
7700 
7701  packet.irrigation_result =
7702  (pterrain->irrigation_result
7703  ? terrain_number(pterrain->irrigation_result)
7704  : terrain_count());
7705  packet.irrigation_food_incr = pterrain->irrigation_food_incr;
7706  packet.irrigation_time = pterrain->irrigation_time;
7707 
7708  packet.mining_result =
7709  (pterrain->mining_result ? terrain_number(pterrain->mining_result)
7710  : terrain_count());
7711  packet.mining_shield_incr = pterrain->mining_shield_incr;
7712  packet.mining_time = pterrain->mining_time;
7713 
7714  packet.animal =
7715  (pterrain->animal == nullptr ? -1 : utype_number(pterrain->animal));
7716  packet.transform_result =
7717  (pterrain->transform_result
7718  ? terrain_number(pterrain->transform_result)
7719  : terrain_count());
7720  packet.placing_time = pterrain->placing_time;
7721  packet.pillage_time = pterrain->pillage_time;
7722  packet.transform_time = pterrain->transform_time;
7723  packet.clean_pollution_time = pterrain->clean_pollution_time;
7724  packet.clean_fallout_time = pterrain->clean_fallout_time;
7725 
7726  packet.flags = pterrain->flags;
7727 
7728  packet.color_red = pterrain->rgb->r;
7729  packet.color_green = pterrain->rgb->g;
7730  packet.color_blue = pterrain->rgb->b;
7731 
7732  packet_strvec_compute(packet.helptext, pterrain->helptext);
7733 
7734  lsend_packet_ruleset_terrain(dest, &packet);
7735  }
7737 }
7738 
7742 static void send_ruleset_resources(struct conn_list *dest)
7743 {
7744  struct packet_ruleset_resource packet;
7745 
7746  extra_type_by_cause_iterate(EC_RESOURCE, presource)
7747  {
7748  packet.id = extra_index(presource);
7749 
7751  {
7752  packet.output[o] = presource->data.resource->output[o];
7753  }
7755 
7756  lsend_packet_ruleset_resource(dest, &packet);
7757  }
7759 }
7760 
7765 static void send_ruleset_extras(struct conn_list *dest)
7766 {
7767  struct packet_ruleset_extra packet;
7768  struct packet_ruleset_extra_flag fpacket;
7769  int i;
7770 
7771  for (i = 0; i < MAX_NUM_USER_EXTRA_FLAGS; i++) {
7772  const char *flagname;
7773  const char *helptxt;
7774 
7775  fpacket.id = i + EF_USER_FLAG_1;
7776 
7777  flagname = extra_flag_id_name(extra_flag_id(i + EF_USER_FLAG_1));
7778  if (flagname == nullptr) {
7779  fpacket.name[0] = '\0';
7780  } else {
7781  sz_strlcpy(fpacket.name, flagname);
7782  }
7783 
7784  helptxt = extra_flag_helptxt(extra_flag_id(i + EF_USER_FLAG_1));
7785  if (helptxt == nullptr) {
7786  fpacket.helptxt[0] = '\0';
7787  } else {
7788  sz_strlcpy(fpacket.helptxt, helptxt);
7789  }
7790 
7791  lsend_packet_ruleset_extra_flag(dest, &fpacket);
7792  }
7793 
7795  {
7796  int j;
7797 
7798  packet.id = extra_number(e);
7799  sz_strlcpy(packet.name, untranslated_name(&e->name));
7800  sz_strlcpy(packet.rule_name, rule_name_get(&e->name));
7801 
7802  packet.category = e->category;
7803 
7804  BV_CLR_ALL(packet.causes);
7805  for (j = 0; j < EC_COUNT; j++) {
7806  if (is_extra_caused_by(e, j)) {
7807  BV_SET(packet.causes, j);
7808  }
7809  }
7810 
7811  BV_CLR_ALL(packet.rmcauses);
7812  for (j = 0; j < ERM_COUNT; j++) {
7813  if (is_extra_removed_by(e, extra_rmcause(j))) {
7814  BV_SET(packet.rmcauses, j);
7815  }
7816  }
7817 
7818  sz_strlcpy(packet.activity_gfx, e->activity_gfx);
7819  sz_strlcpy(packet.act_gfx_alt, e->act_gfx_alt);
7820  sz_strlcpy(packet.act_gfx_alt2, e->act_gfx_alt2);
7821  sz_strlcpy(packet.rmact_gfx, e->rmact_gfx);
7822  sz_strlcpy(packet.rmact_gfx_alt, e->rmact_gfx_alt);
7823  sz_strlcpy(packet.graphic_str, e->graphic_str);
7824  sz_strlcpy(packet.graphic_alt, e->graphic_alt);
7825 
7826  j = 0;
7827  requirement_vector_iterate(&e->reqs, preq) { packet.reqs[j++] = *preq; }
7829  packet.reqs_count = j;
7830 
7831  j = 0;
7832  requirement_vector_iterate(&e->rmreqs, preq)
7833  {
7834  packet.rmreqs[j++] = *preq;
7835  }
7837  packet.rmreqs_count = j;
7838 
7839  packet.appearance_chance = e->appearance_chance;
7840  j = 0;
7841  requirement_vector_iterate(&e->appearance_reqs, preq)
7842  {
7843  packet.appearance_reqs[j++] = *preq;
7844  }
7846  packet.appearance_reqs_count = j;
7847 
7848  packet.disappearance_chance = e->disappearance_chance;
7849  j = 0;
7850  requirement_vector_iterate(&e->disappearance_reqs, preq)
7851  {
7852  packet.disappearance_reqs[j++] = *preq;
7853  }
7855  packet.disappearance_reqs_count = j;
7856 
7857  packet.visibility_req = e->visibility_req;
7858  packet.buildable = e->buildable;
7859  packet.generated = e->generated;
7860  packet.build_time = e->build_time;
7861  packet.build_time_factor = e->build_time_factor;
7862  packet.removal_time = e->removal_time;
7863  packet.removal_time_factor = e->removal_time_factor;
7864  packet._unused = 0;
7865  packet.defense_bonus = e->defense_bonus;
7866  packet.eus = e->eus;
7867 
7868  packet.native_to = e->native_to;
7869 
7870  packet.flags = e->flags;
7871  packet.hidden_by = e->hidden_by;
7872  packet.bridged_over = e->bridged_over;
7873  packet.conflicts = e->conflicts;
7874 
7875  packet_strvec_compute(packet.helptext, e->helptext);
7876 
7877  lsend_packet_ruleset_extra(dest, &packet);
7878  }
7880 }
7881 
7886 static void send_ruleset_bases(struct conn_list *dest)
7887 {
7888  extra_type_by_cause_iterate(EC_BASE, pextra)
7889  {
7890  struct base_type *b = extra_base_get(pextra);
7891  struct packet_ruleset_base packet;
7892 
7893  packet.id = base_number(b);
7894 
7895  packet.gui_type = b->gui_type;
7896  packet.border_sq = b->border_sq;
7897  packet.vision_main_sq = b->vision_main_sq;
7898  packet.vision_invis_sq = b->vision_invis_sq;
7899  packet.vision_subs_sq = b->vision_subs_sq;
7900 
7901  packet.flags = b->flags;
7902 
7903  lsend_packet_ruleset_base(dest, &packet);
7904  }
7906 }
7907 
7912 static void send_ruleset_roads(struct conn_list *dest)
7913 {
7914  struct packet_ruleset_road packet;
7915 
7916  extra_type_by_cause_iterate(EC_ROAD, pextra)
7917  {
7918  struct road_type *r = extra_road_get(pextra);
7919  int j;
7920 
7921  packet.id = road_number(r);
7922 
7923  j = 0;
7925  {
7926  packet.first_reqs[j++] = *preq;
7927  }
7929  packet.first_reqs_count = j;
7930 
7931  packet.move_cost = r->move_cost;
7932  packet.move_mode = r->move_mode;
7933 
7935  {
7936  packet.tile_incr_const[o] = r->tile_incr_const[o];
7937  packet.tile_incr[o] = r->tile_incr[o];
7938  packet.tile_bonus[o] = r->tile_bonus[o];
7939  }
7941 
7942  packet.compat = r->compat;
7943 
7944  packet.integrates = r->integrates;
7945  packet.flags = r->flags;
7946 
7947  lsend_packet_ruleset_road(dest, &packet);
7948  }
7950 }
7951 
7956 static void send_ruleset_goods(struct conn_list *dest)
7957 {
7958  struct packet_ruleset_goods packet;
7959 
7961  {
7962  int j;
7963 
7964  packet.id = goods_number(g);
7965  sz_strlcpy(packet.name, untranslated_name(&g->name));
7966  sz_strlcpy(packet.rule_name, rule_name_get(&g->name));
7967 
7968  j = 0;
7969  requirement_vector_iterate(&g->reqs, preq) { packet.reqs[j++] = *preq; }
7971  packet.reqs_count = j;
7972 
7973  packet.from_pct = g->from_pct;
7974  packet.to_pct = g->to_pct;
7975  packet.onetime_pct = g->onetime_pct;
7976  packet.flags = g->flags;
7977 
7978  packet_strvec_compute(packet.helptext, g->helptext);
7979 
7980  lsend_packet_ruleset_goods(dest, &packet);
7981  }
7983 }
7984 
7989 static void send_ruleset_disasters(struct conn_list *dest)
7990 {
7991  struct packet_ruleset_disaster packet;
7992 
7994  {
7995  int j;
7996 
7997  packet.id = disaster_number(d);
7998 
7999  sz_strlcpy(packet.name, untranslated_name(&d->name));
8000  sz_strlcpy(packet.rule_name, rule_name_get(&d->name));
8001 
8002  j = 0;
8003  requirement_vector_iterate(&d->reqs, preq) { packet.reqs[j++] = *preq; }
8005  packet.reqs_count = j;
8006 
8007  packet.frequency = d->frequency;
8008 
8009  packet.effects = d->effects;
8010 
8011  lsend_packet_ruleset_disaster(dest, &packet);
8012  }
8014 }
8015 
8020 static void send_ruleset_achievements(struct conn_list *dest)
8021 {
8022  struct packet_ruleset_achievement packet;
8023 
8025  {
8026  packet.id = achievement_number(a);
8027 
8028  sz_strlcpy(packet.name, untranslated_name(&a->name));
8029  sz_strlcpy(packet.rule_name, rule_name_get(&a->name));
8030 
8031  packet.type = a->type;
8032  packet.unique = a->unique;
8033  packet.value = a->value;
8034 
8035  lsend_packet_ruleset_achievement(dest, &packet);
8036  }
8038 }
8039 
8043 static void send_ruleset_actions(struct conn_list *dest)
8044 {
8045  struct packet_ruleset_action packet;
8046 
8047  action_iterate(act)
8048  {
8049  struct action *paction = action_by_number(act);
8050 
8051  packet.id = act;
8052  sz_strlcpy(packet.ui_name, action_by_number(act)->ui_name);
8053  packet.quiet = action_by_number(act)->quiet;
8054 
8055  packet.result = paction->result;
8056  packet.actor_consuming_always = paction->actor_consuming_always;
8057 
8058  packet.act_kind = action_by_number(act)->actor_kind;
8059  packet.tgt_kind = action_by_number(act)->target_kind;
8060  packet.sub_tgt_kind = action_id_get_sub_target_kind(act);
8061 
8062  packet.min_distance = action_by_number(act)->min_distance;
8063  packet.max_distance = action_by_number(act)->max_distance;
8064  packet.blocked_by = action_by_number(act)->blocked_by;
8065 
8066  lsend_packet_ruleset_action(dest, &packet);
8067  }
8069 }
8070 
8074 static void send_ruleset_action_enablers(struct conn_list *dest)
8075 {
8076  int counter;
8077  struct packet_ruleset_action_enabler packet;
8078 
8079  action_enablers_iterate(enabler)
8080  {
8081  packet.enabled_action = enabler->action;
8082 
8083  counter = 0;
8084  requirement_vector_iterate(&enabler->actor_reqs, req)
8085  {
8086  packet.actor_reqs[counter++] = *req;
8087  }
8089  packet.actor_reqs_count = counter;
8090 
8091  counter = 0;
8092  requirement_vector_iterate(&enabler->target_reqs, req)
8093  {
8094  packet.target_reqs[counter++] = *req;
8095  }
8097  packet.target_reqs_count = counter;
8098 
8099  lsend_packet_ruleset_action_enabler(dest, &packet);
8100  }
8102 }
8103 
8108 static void send_ruleset_action_auto_performers(struct conn_list *dest)
8109 {
8110  int counter;
8111  int id;
8112  struct packet_ruleset_action_auto packet;
8113 
8114  id = 0;
8116  {
8117  packet.id = id++;
8118 
8119  packet.cause = aperf->cause;
8120 
8121  counter = 0;
8122  requirement_vector_iterate(&aperf->reqs, req)
8123  {
8124  packet.reqs[counter++] = *req;
8125  }
8127  packet.reqs_count = counter;
8128 
8129  for (counter = 0;
8130  // Can't list more actions than all actions.
8131  counter < NUM_ACTIONS
8132  // ACTION_NONE terminates the list.
8133  && aperf->alternatives[counter] != ACTION_NONE;
8134  counter++) {
8135  packet.alternatives[counter] = aperf->alternatives[counter];
8136  }
8137  packet.alternatives_count = counter;
8138 
8139  lsend_packet_ruleset_action_auto(dest, &packet);
8140  }
8142 }
8143 
8148 static void send_ruleset_trade_routes(struct conn_list *dest)
8149 {
8150  struct packet_ruleset_trade packet;
8151  int itype;
8152 
8153  for (itype = TRT_NATIONAL; itype < TRT_LAST; itype++) {
8154  trade_route_type type = trade_route_type(itype);
8156 
8157  packet.id = type;
8158  packet.trade_pct = set->trade_pct;
8159  packet.cancelling = set->cancelling;
8160  packet.bonus_type = set->bonus_type;
8161 
8162  lsend_packet_ruleset_trade(dest, &packet);
8163  }
8164 }
8165 
8170 static void send_ruleset_governments(struct conn_list *dest)
8171 {
8172  struct packet_ruleset_government gov;
8173  struct packet_ruleset_government_ruler_title title;
8174  int j;
8175 
8176  for (auto &g : governments) {
8177  // send one packet_government
8178  gov.id = government_number(&g);
8179 
8180  j = 0;
8181  requirement_vector_iterate(&g.reqs, preq) { gov.reqs[j++] = *preq; }
8183  gov.reqs_count = j;
8184 
8185  sz_strlcpy(gov.name, untranslated_name(&g.name));
8186  sz_strlcpy(gov.rule_name, rule_name_get(&g.name));
8187  sz_strlcpy(gov.graphic_str, g.graphic_str);
8188  sz_strlcpy(gov.graphic_alt, g.graphic_alt);
8189  packet_strvec_compute(gov.helptext, g.helptext);
8190 
8191  lsend_packet_ruleset_government(dest, &gov);
8192 
8193  // Send one packet_government_ruler_title per ruler title.
8194 
8195  for (auto *pruler_title : qAsConst(*government_ruler_titles(&g))) {
8196  {
8197  const struct nation_type *pnation = ruler_title_nation(pruler_title);
8198 
8199  title.gov = government_number(&g);
8200  title.nation =
8201  pnation ? nation_index(pnation) : game.control.nation_count;
8202  sz_strlcpy(title.male_title,
8203  ruler_title_male_untranslated_name(pruler_title));
8204  sz_strlcpy(title.female_title,
8205  ruler_title_female_untranslated_name(pruler_title));
8206  lsend_packet_ruleset_government_ruler_title(dest, &title);
8207  }
8208  }
8209  } // iterate governments - g
8210 }
8211 
8216 static void send_ruleset_nations(struct conn_list *dest)
8217 {
8218  struct packet_ruleset_nation_sets sets_packet;
8219  struct packet_ruleset_nation_groups groups_packet;
8220  struct packet_ruleset_nation packet;
8221  int i;
8222 
8223  sets_packet.nsets = nation_set_count();
8224  i = 0;
8225  nation_sets_iterate(pset)
8226  {
8227  sz_strlcpy(sets_packet.names[i], nation_set_untranslated_name(pset));
8228  sz_strlcpy(sets_packet.rule_names[i], nation_set_rule_name(pset));
8229  sz_strlcpy(sets_packet.descriptions[i], nation_set_description(pset));
8230  i++;
8231  }
8233  lsend_packet_ruleset_nation_sets(dest, &sets_packet);
8234 
8235  groups_packet.ngroups = nation_group_count();
8236  i = 0;
8237  nation_groups_iterate(pgroup)
8238  {
8239  sz_strlcpy(groups_packet.groups[i],
8241  groups_packet.hidden[i] = pgroup->hidden;
8242  i++;
8243  }
8245  lsend_packet_ruleset_nation_groups(dest, &groups_packet);
8246 
8247  for (const auto &n : nations) {
8248  packet.id = nation_index(&n);
8249  if (n.translation_domain == nullptr) {
8250  packet.translation_domain[0] = '\0';
8251  } else {
8252  sz_strlcpy(packet.translation_domain, n.translation_domain);
8253  }
8254  sz_strlcpy(packet.adjective, untranslated_name(&n.adjective));
8255  sz_strlcpy(packet.rule_name, rule_name_get(&n.adjective));
8256  sz_strlcpy(packet.noun_plural, untranslated_name(&n.noun_plural));
8257  sz_strlcpy(packet.graphic_str, n.flag_graphic_str);
8258  sz_strlcpy(packet.graphic_alt, n.flag_graphic_alt);
8259 
8260  i = 0;
8262  {
8263  sz_strlcpy(packet.leader_name[i], nation_leader_name(pleader));
8264  packet.leader_is_male[i] = nation_leader_is_male(pleader);
8265  i++;
8266  }
8268  packet.leader_count = i;
8269 
8270  packet.style = style_number(n.style);
8271  packet.is_playable = n.is_playable;
8272  packet.barbarian_type = n.barb_type;
8273 
8274  sz_strlcpy(packet.legend, n.legend);
8275 
8276  i = 0;
8277  nation_set_list_iterate(n.sets, pset)
8278  {
8279  packet.sets[i++] = nation_set_number(pset);
8280  }
8282  packet.nsets = i;
8283 
8284  i = 0;
8285  nation_group_list_iterate(n.groups, pgroup)
8286  {
8287  packet.groups[i++] = nation_group_number(pgroup);
8288  }
8290  packet.ngroups = i;
8291 
8292  packet.init_government_id = n.init_government
8293  ? government_number(n.init_government)
8294  : government_count();
8295  fc_assert(ARRAY_SIZE(packet.init_techs) == ARRAY_SIZE(n.init_techs));
8296  for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
8297  if (n.init_techs[i] != A_LAST) {
8298  packet.init_techs[i] = n.init_techs[i];
8299  } else {
8300  break;
8301  }
8302  }
8303  packet.init_techs_count = i;
8304  fc_assert(ARRAY_SIZE(packet.init_units) == n.init_units.size());
8305  for (i = 0; i < MAX_NUM_UNIT_LIST; i++) {
8306  const struct unit_type *t = n.init_units[i];
8307  if (t) {
8308  packet.init_units[i] = utype_number(t);
8309  } else {
8310  break;
8311  }
8312  }
8313  packet.init_units_count = i;
8314  fc_assert(ARRAY_SIZE(packet.init_buildings)
8315  == ARRAY_SIZE(n.init_buildings));
8316  for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
8317  if (n.init_buildings[i] != B_LAST) {
8318  // Impr_type_id to int
8319  packet.init_buildings[i] = n.init_buildings[i];
8320  } else {
8321  break;
8322  }
8323  }
8324  packet.init_buildings_count = i;
8325 
8326  lsend_packet_ruleset_nation(dest, &packet);
8327  }
8328 
8329  // Send initial values of is_pickable
8330  send_nation_availability(dest, false);
8331 }
8332 
8337 static void send_ruleset_styles(struct conn_list *dest)
8338 {
8339  struct packet_ruleset_style packet;
8340 
8341  styles_iterate(s)
8342  {
8343  packet.id = style_index(s);
8344  sz_strlcpy(packet.name, untranslated_name(&s->name));
8345  sz_strlcpy(packet.rule_name, rule_name_get(&s->name));
8346 
8347  lsend_packet_ruleset_style(dest, &packet);
8348  }
8350 }
8351 
8355 static void send_ruleset_clauses(struct conn_list *dest)
8356 {
8357  struct packet_ruleset_clause packet;
8358  int i;
8359 
8360  for (i = 0; i < CLAUSE_COUNT; i++) {
8361  struct clause_info *info = clause_info_get(clause_type(i));
8362  int j;
8363 
8364  packet.type = clause_type(i);
8365  packet.enabled = info->enabled;
8366 
8367  j = 0;
8369  {
8370  packet.giver_reqs[j++] = *preq;
8371  }
8373  packet.giver_reqs_count = j;
8374 
8375  j = 0;
8377  {
8378  packet.receiver_reqs[j++] = *preq;
8379  }
8381  packet.receiver_reqs_count = j;
8382 
8383  lsend_packet_ruleset_clause(dest, &packet);
8384  }
8385 }
8386 
8391 static void send_ruleset_multipliers(struct conn_list *dest)
8392 {
8393  multipliers_iterate(pmul)
8394  {
8395  int j;
8396  struct packet_ruleset_multiplier packet;
8397 
8398  packet.id = multiplier_number(pmul);
8399  packet.start = pmul->start;
8400  packet.stop = pmul->stop;
8401  packet.step = pmul->step;
8402  packet.def = pmul->def;
8403  packet.offset = pmul->offset;
8404  packet.factor = pmul->factor;
8405 
8406  sz_strlcpy(packet.name, untranslated_name(&pmul->name));
8407  sz_strlcpy(packet.rule_name, rule_name_get(&pmul->name));
8408 
8409  j = 0;
8410  requirement_vector_iterate(&pmul->reqs, preq)
8411  {
8412  packet.reqs[j++] = *preq;
8413  }
8415  packet.reqs_count = j;
8416 
8417  packet_strvec_compute(packet.helptext, pmul->helptext);
8418 
8419  lsend_packet_ruleset_multiplier(dest, &packet);
8420  }
8422 }
8423 
8428 static void send_ruleset_cities(struct conn_list *dest)
8429 {
8430  struct packet_ruleset_city city_p;
8431  int k, j;
8432 
8433  for (k = 0; k < game.control.styles_count; k++) {
8434  city_p.style_id = k;
8435 
8436  j = 0;
8438  {
8439  city_p.reqs[j++] = *preq;
8440  }
8442  city_p.reqs_count = j;
8443 
8444  sz_strlcpy(city_p.name, untranslated_name(&city_styles[k].name));
8445  sz_strlcpy(city_p.rule_name, rule_name_get(&city_styles[k].name));
8446  sz_strlcpy(city_p.graphic, city_styles[k].graphic);
8447  sz_strlcpy(city_p.graphic_alt, city_styles[k].graphic_alt);
8448  sz_strlcpy(city_p.citizens_graphic, city_styles[k].citizens_graphic);
8449  sz_strlcpy(city_p.citizens_graphic_alt,
8451 
8452  lsend_packet_ruleset_city(dest, &city_p);
8453  }
8454 }
8455 
8460 static void send_ruleset_musics(struct conn_list *dest)
8461 {
8462  struct packet_ruleset_music packet;
8463 
8464  music_styles_iterate(pmus)
8465  {
8466  int j;
8467 
8468  packet.id = pmus->id;
8469 
8470  sz_strlcpy(packet.music_peaceful, qUtf8Printable(pmus->music_peaceful));
8471  sz_strlcpy(packet.music_combat, qUtf8Printable(pmus->music_combat));
8472 
8473  j = 0;
8474  requirement_vector_iterate(&(pmus->reqs), preq)
8475  {
8476  packet.reqs[j++] = *preq;
8477  }
8479  packet.reqs_count = j;
8480 
8481  lsend_packet_ruleset_music(dest, &packet);
8482  }
8484 }
8485 
8490 static void send_ruleset_game(struct conn_list *dest)
8491 {
8492  struct packet_ruleset_game misc_p;
8493  int i;
8494 
8495  fc_assert_ret(game.veteran != nullptr);
8496 
8497  // Per unit veteran system definition.
8498  misc_p.veteran_levels = game.veteran->levels;
8499 
8500  for (i = 0; i < misc_p.veteran_levels; i++) {
8501  const struct veteran_level *vlevel = game.veteran->definitions + i;
8502 
8503  sz_strlcpy(misc_p.veteran_name[i], untranslated_name(&vlevel->name));
8504  misc_p.power_fact[i] = vlevel->power_fact;
8505  misc_p.move_bonus[i] = vlevel->move_bonus;
8506  misc_p.base_raise_chance[i] = vlevel->base_raise_chance;
8507  misc_p.work_raise_chance[i] = vlevel->work_raise_chance;
8508  }
8509 
8510  fc_assert(sizeof(misc_p.global_init_techs)
8511  == sizeof(game.rgame.global_init_techs));
8512  fc_assert(ARRAY_SIZE(misc_p.global_init_techs)
8514  for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
8515  if (game.rgame.global_init_techs[i] != A_LAST) {
8516  misc_p.global_init_techs[i] = game.rgame.global_init_techs[i];
8517  } else {
8518  break;
8519  }
8520  }
8521  misc_p.global_init_techs_count = i;
8522 
8523  fc_assert(ARRAY_SIZE(misc_p.global_init_buildings)
8525  for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
8526  if (game.rgame.global_init_buildings[i] != B_LAST) {
8527  // Impr_type_id to int
8528  misc_p.global_init_buildings[i] = game.rgame.global_init_buildings[i];
8529  } else {
8530  break;
8531  }
8532  }
8533  misc_p.global_init_buildings_count = i;
8534 
8535  misc_p.default_specialist = DEFAULT_SPECIALIST;
8536 
8537  fc_assert_ret(game.plr_bg_color != nullptr);
8538 
8539  misc_p.background_red = game.plr_bg_color->r;
8540  misc_p.background_green = game.plr_bg_color->g;
8541  misc_p.background_blue = game.plr_bg_color->b;
8542 
8543  lsend_packet_ruleset_game(dest, &misc_p);
8544 }
8545 
8550 static void send_ruleset_team_names(struct conn_list *dest)
8551 {
8552  struct packet_team_name_info team_name_info_p;
8553 
8554  team_slots_iterate(tslot)
8555  {
8556  const char *name = team_slot_defined_name(tslot);
8557 
8558  if (nullptr == name) {
8559  // End of defined names.
8560  break;
8561  }
8562 
8563  team_name_info_p.team_id = team_slot_index(tslot);
8564  sz_strlcpy(team_name_info_p.team_name, name);
8565 
8566  lsend_packet_team_name_info(dest, &team_name_info_p);
8567  }
8569 }
8570 
8574 static void notify_ruleset_fallback(const char *msg)
8575 {
8576  notify_conn(nullptr, nullptr, E_LOG_FATAL, ftc_warning, "%s", msg);
8577 }
8578 
8582 bool load_rulesets(const char *restore, const char *alt, bool compat_mode,
8583  rs_conversion_logger logger, bool act, bool buffer_script,
8584  bool load_luadata)
8585 {
8586  if (load_rulesetdir(game.server.rulesetdir, compat_mode, logger, act,
8587  buffer_script, load_luadata)) {
8588  return true;
8589  }
8590 
8591  if (alt != nullptr) {
8592  if (load_rulesetdir(alt, compat_mode, logger, act, buffer_script,
8593  load_luadata)) {
8594  sz_strlcpy(game.server.rulesetdir, alt);
8595 
8596  return true;
8597  }
8598  }
8599 
8600  // Fallback to previous one.
8601  if (restore != nullptr) {
8602  if (load_rulesetdir(restore, compat_mode, logger, act, buffer_script,
8603  true)) {
8604  sz_strlcpy(game.server.rulesetdir, restore);
8605 
8607  _("Ruleset couldn't be loaded. Keeping previous one."));
8608 
8609  /* We're in sane state as restoring previous ruleset succeeded,
8610  * but return failure to indicate that this is not what caller
8611  * wanted. */
8612  return false;
8613  }
8614  }
8615 
8616  // Fallback to default one, but not if that's what we tried already
8617  if (strcmp(GAME_DEFAULT_RULESETDIR, game.server.rulesetdir)
8618  && (restore == nullptr || strcmp(GAME_DEFAULT_RULESETDIR, restore))) {
8619  if (load_rulesetdir(GAME_DEFAULT_RULESETDIR, false, nullptr, act,
8620  buffer_script, true)) {
8621  /* We're in sane state as fallback ruleset loading succeeded,
8622  * but return failure to indicate that this is not what caller
8623  * wanted. */
8625 
8627  _("Ruleset couldn't be loaded. Switching to default one."));
8628 
8629  return false;
8630  }
8631  }
8632 
8633  // Cannot load even default ruleset, we're in completely unusable state
8634  exit(EXIT_FAILURE);
8635 }
8636 
8640 static void nullcheck_secfile_destroy(struct section_file *file)
8641 {
8642  if (file != nullptr) {
8643  secfile_destroy(file);
8644  }
8645 }
8646 
8652 {
8654  requirement_vector_free(&reqs_list);
8655 }
8656 
8661 static bool load_rulesetdir(const char *rsdir, bool compat_mode,
8662  rs_conversion_logger logger, bool act,
8663  bool buffer_script, bool load_luadata)
8664 {
8665  struct section_file *techfile, *unitfile, *buildfile, *govfile, *terrfile;
8666  struct section_file *stylefile, *cityfile, *nationfile, *effectfile,
8667  *gamefile;
8668  bool ok = true;
8669  struct rscompat_info compat_info;
8670 
8671  qInfo(_("Loading rulesets."));
8672 
8673  compat_info.compat_mode = compat_mode;
8674  compat_info.log_cb = logger;
8675 
8677  // Reset the list of available player colors.
8678  playercolor_free();
8679  playercolor_init();
8681 
8682  delete[] script_buffer;
8683  delete[] parser_buffer;
8684  script_buffer = nullptr;
8685  parser_buffer = nullptr;
8686 
8687  server.playable_nations = 0;
8688 
8689  techfile = openload_ruleset_file("techs", rsdir);
8690  buildfile = openload_ruleset_file("buildings", rsdir);
8691  govfile = openload_ruleset_file("governments", rsdir);
8692  unitfile = openload_ruleset_file("units", rsdir);
8693  terrfile = openload_ruleset_file("terrain", rsdir);
8694  stylefile = openload_ruleset_file("styles", rsdir);
8695  cityfile = openload_ruleset_file("cities", rsdir);
8696  nationfile = openload_ruleset_file("nations", rsdir);
8697  effectfile = openload_ruleset_file("effects", rsdir);
8698  gamefile = openload_ruleset_file("game", rsdir);
8699  if (load_luadata) {
8700  game.server.luadata = openload_luadata_file(rsdir);
8701  } else {
8702  game.server.luadata = nullptr;
8703  }
8704 
8705  if (techfile == nullptr || buildfile == nullptr || govfile == nullptr
8706  || unitfile == nullptr || terrfile == nullptr || stylefile == nullptr
8707  || cityfile == nullptr || nationfile == nullptr
8708  || effectfile == nullptr || gamefile == nullptr) {
8709  ok = false;
8710  }
8711 
8712  if (ok) {
8713  ok = load_game_names(gamefile, &compat_info)
8714  && load_tech_names(techfile, &compat_info)
8715  && load_building_names(buildfile, &compat_info)
8716  && load_government_names(govfile, &compat_info)
8717  && load_unit_names(unitfile, &compat_info)
8718  && load_terrain_names(terrfile, &compat_info)
8719  && load_style_names(stylefile, &compat_info)
8720  && load_nation_names(nationfile, &compat_info);
8721  }
8722 
8723  if (ok) {
8724  ok = rscompat_names(&compat_info);
8725  }
8726 
8727  if (ok) {
8728  ok = load_ruleset_techs(techfile, &compat_info);
8729  }
8730  if (ok) {
8731  ok = load_ruleset_styles(stylefile, &compat_info);
8732  }
8733  if (ok) {
8734  ok = load_ruleset_cities(cityfile, &compat_info);
8735  }
8736  if (ok) {
8737  ok = load_ruleset_governments(govfile, &compat_info);
8738  }
8739  if (ok) {
8740  // terrain must precede nations and units
8741  ok = load_ruleset_terrain(terrfile, &compat_info);
8742  }
8743  if (ok) {
8744  ok = load_ruleset_units(unitfile, &compat_info);
8745  }
8746  if (ok) {
8747  ok = load_ruleset_buildings(buildfile, &compat_info);
8748  }
8749  if (ok) {
8750  ok = load_ruleset_nations(nationfile, &compat_info);
8751  }
8752  if (ok) {
8753  ok = load_ruleset_effects(effectfile, &compat_info);
8754  }
8755  if (ok) {
8756  ok = load_ruleset_game(gamefile, act, &compat_info);
8757  }
8758 
8759  if (ok) {
8760  // Init nations we just loaded.
8762 
8763  // Needed by role_unit_precalcs().
8765 
8766  // Prepare caches we want to sanity check.
8770 
8772  && sanity_check_ruleset_data(compat_info.compat_mode);
8773  }
8774 
8775  if (ok) {
8776  // Only load settings for a sane ruleset
8777  ok = settings_ruleset(gamefile, "settings", act);
8778 
8779  if (ok) {
8780  secfile_check_unused(gamefile);
8781  }
8782  }
8783 
8784  nullcheck_secfile_destroy(techfile);
8785  nullcheck_secfile_destroy(stylefile);
8786  nullcheck_secfile_destroy(cityfile);
8787  nullcheck_secfile_destroy(govfile);
8788  nullcheck_secfile_destroy(terrfile);
8789  nullcheck_secfile_destroy(unitfile);
8790  nullcheck_secfile_destroy(buildfile);
8791  nullcheck_secfile_destroy(nationfile);
8792  nullcheck_secfile_destroy(effectfile);
8793  nullcheck_secfile_destroy(gamefile);
8794 
8795  delete[] extra_sections;
8796  delete[] base_sections;
8797  delete[] road_sections;
8798  delete[] resource_sections;
8799  delete[] terrain_sections;
8800  extra_sections = nullptr;
8801  base_sections = nullptr;
8802  road_sections = nullptr;
8803  resource_sections = nullptr;
8804  terrain_sections = nullptr;
8805 
8806  if (ok) {
8807  rscompat_postprocess(&compat_info);
8808  }
8809 
8810  if (ok) {
8811  char **buffer = buffer_script ? &script_buffer : nullptr;
8812 
8814 
8816 
8817  ok = (openload_script_file("script", rsdir, buffer, false) == TRI_YES);
8818  }
8819 
8820  if (ok) {
8821  enum fc_tristate pret;
8822  char **buffer = buffer_script ? &parser_buffer : nullptr;
8823 
8824  pret = openload_script_file("parser", rsdir, buffer,
8825  compat_info.compat_mode);
8826 
8827  if (pret == TRI_MAYBE && buffer_script) {
8828  parser_buffer = fc_strdup("-- This file is for lua-functionality for "
8829  "parsing luadata.txt\n-- of this ruleset.");
8830  }
8831 
8832  ok = (pret != TRI_NO);
8833  }
8834 
8835  if (ok && !buffer_script) {
8836  ok = (openload_script_file("default", rsdir, nullptr, false) == TRI_YES);
8837  }
8838 
8839  if (ok && act) {
8840  // Populate remaining caches.
8843  unit_class_iterate(pclass) { set_unit_class_caches(pclass); }
8845  unit_type_iterate(ptype)
8846  {
8847  ptype->unknown_move_cost = utype_unknown_move_cost(ptype);
8848  set_unit_type_caches(ptype);
8849  }
8852 
8853  // Build advisors unit class cache corresponding to loaded rulesets
8855  CALL_FUNC_EACH_AI(units_ruleset_init);
8856 
8857  /* We may need to adjust the number of AI players
8858  * if the number of available nations changed. */
8859  (void) aifill(game.info.aifill);
8860  }
8861 
8862  return ok;
8863 }
8864 
8869 {
8870  struct section_file *file;
8871  bool ok = true;
8872 
8873  file = openload_ruleset_file("game", game.server.rulesetdir);
8874  if (file == nullptr) {
8875  qCCritical(ruleset_category, "Could not load game.ruleset:\n%s",
8876  secfile_error());
8877  ok = false;
8878  }
8879  if (ok) {
8880  settings_ruleset(file, "settings", true);
8881  secfile_destroy(file);
8882  }
8883 
8884  return ok;
8885 }
8886 
8890 void send_rulesets(struct conn_list *dest)
8891 {
8893 
8894  // ruleset_control also indicates to client that ruleset sending starts.
8895  send_ruleset_control(dest);
8896 
8897  send_ruleset_game(dest);
8898  send_ruleset_disasters(dest);
8902  send_ruleset_actions(dest);
8905  send_ruleset_techs(dest);
8908  send_ruleset_units(dest);
8910  send_ruleset_extras(dest);
8911  send_ruleset_bases(dest);
8912  send_ruleset_roads(dest);
8913  send_ruleset_resources(dest);
8914  send_ruleset_terrain(dest);
8915  send_ruleset_goods(dest);
8916  send_ruleset_buildings(dest);
8917  send_ruleset_nations(dest);
8918  send_ruleset_styles(dest);
8919  send_ruleset_clauses(dest);
8920  send_ruleset_cities(dest);
8922  send_ruleset_musics(dest);
8924  send_ruleset_cache(dest);
8925 
8926  // Indicate client that all rulesets have now been sent.
8927  lsend_packet_rulesets_ready(dest);
8928 
8929  /* changed game settings will be send in
8930  * connecthand.c:establish_new_connection() */
8931 
8933 }
int achievement_index(const struct achievement *pach)
Return the achievement index.
int achievement_number(const struct achievement *pach)
Return the achievement id.
#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
struct action * action_by_rule_name(const char *name)
Return the action with the given name.
Definition: actions.cpp:1169
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_enabler * action_enabler_new()
Create a new action enabler.
Definition: actions.cpp:1810
void action_enabler_add(struct action_enabler *enabler)
Add an action enabler to the current ruleset.
Definition: actions.cpp:1854
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
void actions_rs_pre_san_gen()
Generate action related data based on the currently loaded ruleset.
Definition: actions.cpp:984
struct action_auto_perf * action_auto_perf_slot_number(const int num)
Returns action auto performer rule slot number num so it can be filled.
Definition: actions.cpp:5832
#define action_auto_perf_iterate_end
Definition: actions.h:479
#define action_enablers_iterate_end
Definition: actions.h:425
#define ACTION_AUTO_MOVED_ADJ
Definition: actions.h:504
#define action_id_get_sub_target_kind(act_id)
Definition: actions.h:526
#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 action_enablers_iterate(_enabler_)
Definition: actions.h:417
#define action_iterate(_act_)
Definition: actions.h:378
#define action_auto_perf_iterate(_act_perf_)
Definition: actions.h:468
#define ACTION_AUTO_UPKEEP_FOOD
Definition: actions.h:501
#define ACTION_NONE
Definition: actions.h:220
void adv_units_ruleset_init()
Initialise the unit data from the ruleset for the advisors.
Definition: advruleset.cpp:29
#define CALL_FUNC_EACH_AI(_func,...)
Definition: ai.h:393
bool base_flag_is_retired(enum base_flag_id flag)
Returns TRUE iff the given flag is retired.
Definition: base.cpp:78
Base_type_id base_number(const struct base_type *pbase)
Return the base index.
Definition: base.cpp:135
void base_type_init(struct extra_type *pextra, int idx)
Initialize base_type structures.
Definition: base.cpp:157
bool territory_claiming_base(const struct base_type *pbase)
Does this base type claim territory?
Definition: base.cpp:196
#define BV_CLR_ALL(bv)
Definition: bitvector.h:62
#define BV_SET(bv, bit)
Definition: bitvector.h:44
bool BV_ISSET(const BV &bv, int bit)
Definition: bitvector.h:37
#define BV_CLR(bv, bit)
Definition: bitvector.h:49
struct citystyle * city_styles
Definition: city.cpp:78
void city_styles_alloc(int num)
Allocate memory for this amount of city styles.
Definition: city.cpp:3312
const char * get_output_identifier(Output_type_id output)
Return an id string for the output type.
Definition: city.cpp:592
const char * city_style_rule_name(const int style)
Return the (untranslated) rule name of the city style.
Definition: city.cpp:1651
void city_production_caravan_shields_init()
Initialize the cache of what city production can use shields from caravans.
Definition: city.cpp:1664
#define output_type_iterate(output)
Definition: city.h:764
#define output_type_iterate_end
Definition: city.h:771
static QString ruleset
Definition: civmanual.cpp:152
void conn_list_compression_thaw(const struct conn_list *pconn_list)
Thaw a connection list.
Definition: connection.cpp:665
void conn_list_compression_freeze(const struct conn_list *pconn_list)
Freeze a connection list.
Definition: connection.cpp:656
#define MAX_LEN_CONTENT
Definition: connection.h:45
struct clause_info * clause_info_get(enum clause_type type)
Free memory associated with clause infos.
Definition: diptreaty.cpp:257
const char * disaster_rule_name(struct disaster_type *pdis)
Return untranslated name of this disaster type.
Definition: disaster.cpp:91
Disaster_type_id disaster_number(const struct disaster_type *pdis)
Return the disaster id.
Definition: disaster.cpp:49
Disaster_type_id disaster_index(const struct disaster_type *pdis)
Return the disaster index.
Definition: disaster.cpp:62
#define disaster_type_iterate(_p)
Definition: disaster.h:70
#define disaster_type_iterate_end
Definition: disaster.h:76
struct @19::@20 reqs
void send_ruleset_cache(struct conn_list *dest)
Send the ruleset cache data over the network.
Definition: effects.cpp:466
struct effect * effect_new(enum effect_type type, int value, struct multiplier *pmul)
Add effect to ruleset cache.
Definition: effects.cpp:165
void effect_req_append(struct effect *peffect, struct requirement req)
Append requirement to effect.
Definition: effects.cpp:203
struct extra_type_list * extra_type_list_of_unit_hiders()
Returns extra types that hide units.
Definition: extras.cpp:234
struct extra_type * extra_type_by_rule_name(const char *name)
Returns extra type matching rule name or nullptr if there is no extra type with such name.
Definition: extras.cpp:183
void set_user_extra_flag_name(enum extra_flag_id id, const char *name, const char *helptxt)
Sets user defined name for extra flag.
Definition: extras.cpp:859
struct extra_type * extra_by_number(int id)
Return extras type of given id.
Definition: extras.cpp:154
bool is_extra_caused_by_worker_action(const struct extra_type *pextra)
Is the extra caused by some kind of worker action?
Definition: extras.cpp:931
int extra_number(const struct extra_type *pextra)
Return the extra id.
Definition: extras.cpp:132
bool extra_has_flag(const struct extra_type *pextra, enum extra_flag_id flag)
Check if extra has given flag.
Definition: extras.cpp:779
void extra_to_caused_by_list(struct extra_type *pextra, enum extra_cause cause)
Add extra type to list of extra caused by given cause.
Definition: extras.cpp:274
void extra_to_removed_by_list(struct extra_type *pextra, enum extra_rmcause rmcause)
Add extra type to list of extra removed by given cause.
Definition: extras.cpp:296
struct extra_type_list * extra_type_list_by_cause(enum extra_cause cause)
Returns extra type for given cause.
Definition: extras.cpp:224
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_base_get(_e_)
Definition: extras.h:170
#define extra_road_get(_e_)
Definition: extras.h:171
#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
#define MAX_DISASTER_TYPES
Definition: fc_types.h:46
#define MAX_VET_LEVELS
Definition: fc_types.h:41
#define MAX_BASE_TYPES
Definition: fc_types.h:43
@ 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_GRANARY_INIS
Definition: fc_types.h:67
#define MAX_NUM_NATIONS
Definition: fc_types.h:55
#define MAX_ROAD_TYPES
Definition: fc_types.h:44
#define MAX_NUM_BUILDING_LIST
Definition: fc_types.h:38
#define MAX_NUM_REQS
Definition: fc_types.h:325
#define MAX_GOODS_TYPES
Definition: fc_types.h:45
#define EC_NATURAL_DEFENSIVE
Definition: fc_types.h:937
#define EC_SPECIAL
Definition: fc_types.h:935
int action_id
Definition: fc_types.h:306
#define SP_MAX
Definition: fc_types.h:324
#define EC_NONE
Definition: fc_types.h:934
#define EC_DEFENSIVE
Definition: fc_types.h:936
#define MAX_CALENDAR_FRAGMENTS
Definition: fc_types.h:57
#define MAX_NUM_TECH_CLASSES
Definition: fc_types.h:58
#define MAX_NUM_LEADERS
Definition: fc_types.h:50
#define MAX_NUM_MULTIPLIERS
Definition: fc_types.h:49
#define MAX_NUM_UNIT_LIST
Definition: fc_types.h:37
#define MAX_EXTRA_TYPES
Definition: fc_types.h:42
#define MAX_ACHIEVEMENT_TYPES
Definition: fc_types.h:47
#define MAX_LEN_NAME
Definition: fc_types.h:61
#define MAX_NUM_TECH_LIST
Definition: fc_types.h:36
#define MAX_LEN_CITYNAME
Definition: fc_types.h:62
#define UCL_LAST
Definition: fc_types.h:332
#define Q_(String)
Definition: fcintl.h:53
#define _(String)
Definition: fcintl.h:50
#define Qn_(String)
Definition: fcintl.h:66
#define N_(String)
Definition: fcintl.h:52
const struct ft_color ftc_warning
void game_ruleset_init()
Initialize the objects which will read from a ruleset.
Definition: game.cpp:489
void game_ruleset_free()
Frees all memory which in objects which are read from a ruleset.
Definition: game.cpp:534
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_GRANARY_FOOD_INI
Definition: game.h:754
#define RS_DEFAULT_CIVIL_WAR_UNHAPPY
Definition: game.h:787
#define RS_DEFAULT_NUKE_DEFENDER_SURVIVAL_CHANCE_PCT
Definition: game.h:794
#define RS_MIN_BORDER_RADIUS_SQ_CITY_PERMANENT
Definition: game.h:735
#define RS_MAX_TECH_UPKEEP_DIVIDER
Definition: game.h:814
#define RS_MIN_ILLNESS_POLLUTION_PCT
Definition: game.h:721
#define RS_DEFAULT_NUKE_POP_LOSS_PCT
Definition: game.h:791
#define RS_MAX_BORDER_RADIUS_SQ_CITY
Definition: game.h:728
#define RS_DEFAULT_BASE_POLLUTION
Definition: game.h:773
#define RS_MIN_ILLNESS_TRADE_INFECTION_PCT
Definition: game.h:717
#define RS_MAX_ILLNESS_BASE_FACTOR
Definition: game.h:710
#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_MIN_NUKE_POP_LOSS_PCT
Definition: game.h:792
#define RS_MIN_INCITE_IMPROVEMENT_FCT
Definition: game.h:743
#define RS_MIN_FOOD_COST
Definition: game.h:783
#define RS_MIN_BASE_BRIBE_COST
Definition: game.h:799
#define RS_MAX_NUKE_POP_LOSS_PCT
Definition: game.h:793
#define RS_DEFAULT_INCITE_IMPROVEMENT_FCT
Definition: game.h:742
#define RS_MAX_INCITE_IMPROVEMENT_FCT
Definition: game.h:744
#define RS_MIN_RANSOM_GOLD
Definition: game.h:803
#define RS_ACTION_NO_MAX_DISTANCE
Definition: game.h:833
#define RS_DEFAULT_BASE_BRIBE_COST
Definition: game.h:798
#define RS_MAX_INCITE_BASE_COST
Definition: game.h:740
#define RS_DEFAULT_TECH_UPKEEP_DIVIDER
Definition: game.h:812
#define RS_DEFAULT_HAPPY_COST
Definition: game.h:778
#define RS_MIN_UPGRADE_VETERAN_LOSS
Definition: game.h:809
#define RS_MIN_ILLNESS_MIN_SIZE
Definition: game.h:713
#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 RS_MAX_FOOD_COST
Definition: game.h:784
#define RS_MAX_HAPPY_COST
Definition: game.h:780
#define GAME_DEFAULT_CELEBRATESIZE
Definition: game.h:461
#define RS_MIN_ILLNESS_BASE_FACTOR
Definition: game.h:709
#define RS_DEFAULT_STEAL_MAP_REVEALS_CITIES
Definition: game.h:826
#define RS_MIN_TECH_UPKEEP_DIVIDER
Definition: game.h:813
#define RS_MAX_RANSOM_GOLD
Definition: game.h:804
#define RS_MIN_HAPPY_COST
Definition: game.h:779
#define RS_MIN_BORDER_RADIUS_SQ_CITY
Definition: game.h:727
#define GAME_DEFAULT_RULESETDIR
Definition: game.h:630
#define RS_DEFAULT_CIVIL_WAR_CELEB
Definition: game.h:786
#define RS_MAX_BASE_TECH_COST
Definition: game.h:818
#define RS_DEFAULT_BASE_TECH_COST
Definition: game.h:816
#define RS_DEFAULT_USER_ACTION_TARGET_KIND
Definition: game.h:828
#define RS_MIN_NUKE_DEFENDER_SURVIVAL_CHANCE_PCT
Definition: game.h:795
#define RS_MAX_BORDER_RADIUS_SQ_CITY_PERMANENT
Definition: game.h:736
#define RS_DEFAULT_UPGRADE_VETERAN_LOSS
Definition: game.h:808
#define RS_MAX_NUKE_DEFENDER_SURVIVAL_CHANCE_PCT
Definition: game.h:796
#define RS_MAX_INCITE_UNIT_FCT
Definition: game.h:748
#define RS_MIN_VIS_RADIUS_SQ
Definition: game.h:770
#define RS_DEFAULT_CALENDAR_SKIP_0
Definition: game.h:724
#define RS_MAX_ILLNESS_MIN_SIZE
Definition: game.h:714
#define RS_DEFAULT_CITY_RADIUS_SQ
Definition: game.h:765
#define RS_MAX_BORDER_SIZE_EFFECT
Definition: game.h:732
#define RS_DEFAULT_BORDER_SIZE_EFFECT
Definition: game.h:730
#define RS_MAX_BASE_BRIBE_COST
Definition: game.h:800
#define RS_MIN_INCITE_BASE_COST
Definition: game.h:739
#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 RS_MIN_CITY_RADIUS_SQ
Definition: game.h:766
#define GAME_START_YEAR
Definition: game.h:680
#define RS_MIN_CITY_CENTER_OUTPUT
Definition: game.h:761
#define RS_MAX_GRANARY_FOOD_INC
Definition: game.h:758
#define RS_MAX_CITY_CENTER_OUTPUT
Definition: game.h:762
#define RS_MAX_CITY_RADIUS_SQ
Definition: game.h:767
#define RS_DEFAULT_POS_YEAR_LABEL
Definition: game.h:702
#define RS_MIN_INCITE_UNIT_FCT
Definition: game.h:747
#define RS_MIN_BORDER_SIZE_EFFECT
Definition: game.h:731
#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_MAX_ILLNESS_POLLUTION_PCT
Definition: game.h:722
#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_MAX_INCITE_TOTAL_FCT
Definition: game.h:752
#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_MIN_INCITE_TOTAL_FCT
Definition: game.h:751
#define RS_DEFAULT_ILLNESS_POLLUTION_PCT
Definition: game.h:720
#define RS_MAX_UPGRADE_VETERAN_LOSS
Definition: game.h:810
#define RS_MAX_VIS_RADIUS_SQ
Definition: game.h:771
#define RS_MIN_GRANARY_FOOD_INC
Definition: game.h:757
#define RS_MAX_ILLNESS_TRADE_INFECTION_PCT
Definition: game.h:718
#define RS_DEFAULT_ILLNESS_MIN_SIZE
Definition: game.h:712
#define RS_MIN_BASE_TECH_COST
Definition: game.h:817
#define RS_DEFAULT_BORDER_RADIUS_SQ_CITY
Definition: game.h:726
const struct nation_type * ruler_title_nation(const struct ruler_title *pruler_title)
Return the nation of the rule title.
Definition: government.cpp:340
Government_type_id government_count()
Return the number of governments.
Definition: government.cpp:64
const char * government_rule_name(const struct government *pgovern)
Return the (untranslated) rule name of the government.
Definition: government.cpp:126
QHash< const struct nation_type *, struct ruler_title * > * government_ruler_titles(const struct government *pgovern)
Returns all ruler titles for a government type.
Definition: government.cpp:290
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
struct government * government_by_rule_name(const char *name)
Returns the government that has the given (untranslated) rule name.
Definition: government.cpp:48
void governments_alloc(int num)
Allocate the governments.
Definition: government.cpp:437
struct ruler_title * government_ruler_title_new(struct government *pgovern, const struct nation_type *pnation, const char *ruler_male_title, const char *ruler_female_title)
Add a new ruler title for the nation.
Definition: government.cpp:300
std::vector< government > governments
Definition: government.cpp:28
Government_type_id government_number(const struct government *pgovern)
Return the government index.
Definition: government.cpp:84
Government_type_id government_index(const struct government *pgovern)
Return the government index.
Definition: government.cpp:75
#define G_LAST
Definition: government.h:31
const char * improvement_rule_name(const struct impr_type *pimprove)
Return the (untranslated) rule name of the improvement.
struct impr_type * improvement_by_rule_name(const char *name)
Does a linear search of improvement_types[].name.vernacular Returns nullptr when none match.
void improvement_feature_cache_init()
Cache features of the improvement.
Definition: improvement.cpp:77
struct impr_type * improvement_by_number(const Impr_type_id id)
Returns the improvement type for the given index/ID.
Impr_type_id improvement_number(const struct impr_type *pimprove)
Return the improvement index.
#define improvement_iterate_end
Definition: improvement.h:199
#define improvement_iterate(_p)
Definition: improvement.h:193
#define B_NEVER
Definition: improvement.h:35
#define B_LAST
Definition: improvement.h:33
const char * name
Definition: inputfile.cpp:118
#define fc_assert_ret(condition)
Definition: log.h:112
#define fc_assert(condition)
Definition: log.h:89
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
#define log_debug(message,...)
Definition: log.h:65
struct terrain_misc terrain_control
Definition: map.cpp:40
int utype_unknown_move_cost(const struct unit_type *utype)
This function calculates the movement cost to unknown tiles.
Definition: movement.cpp:93
void init_move_fragments()
Call whenever terrain_control.move_fragments / SINGLE_MOVE changes.
Definition: movement.cpp:777
#define SINGLE_MOVE
Definition: movement.h:17
const char * multiplier_rule_name(const struct multiplier *pmul)
Return the (untranslated) rule name of the multiplier.
Multiplier_type_id multiplier_number(const struct multiplier *pmul)
Returns multiplier number.
Definition: multipliers.cpp:64
struct multiplier * multiplier_by_rule_name(const char *name)
Returns multiplier matching rule name, or nullptr if there is no multiplier with such a name.
Multiplier_type_id multiplier_index(const struct multiplier *pmul)
Returns multiplier index.
Definition: multipliers.cpp:77
#define multipliers_iterate(_mul_)
Definition: multipliers.h:45
#define multipliers_iterate_end
Definition: multipliers.h:51
static void name_set(struct name_translation *ptrans, const char *domain, const char *vernacular_name)
static const char * untranslated_name(const struct name_translation *ptrans)
static const char * rule_name_get(const struct name_translation *ptrans)
static void names_set(struct name_translation *ptrans, const char *domain, const char *vernacular_name, const char *rule_name)
Definition: path.cpp:10
struct nation_set * nation_set_by_number(int id)
Return the nation set with the given index.
Definition: nation.cpp:640
void nation_group_set_match(struct nation_group *pgroup, int match)
Set how much the AI will try to select a nation in the same group.
Definition: nation.cpp:910
struct nation_type * nation_by_number(const Nation_type_id nation)
Return the nation with the given index.
Definition: nation.cpp:450
struct nation_leader * nation_leader_new(struct nation_type *pnation, const char *name, bool is_male)
Create a new leader for the nation.
Definition: nation.cpp:215
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
int nation_set_count()
Return the number of nation sets.
Definition: nation.cpp:577
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 is_nation_playable(const struct nation_type *nation)
Return whether a nation is "playable"; i.e., whether a human player can choose this nation.
Definition: nation.cpp:177
struct nation_city * nation_city_new(struct nation_type *pnation, const char *name)
Create a new default city for the nation (server only function).
Definition: nation.cpp:318
int nation_group_count()
Return the number of nation groups.
Definition: nation.cpp:809
struct nation_group * nation_group_new(const char *name)
Add new group into the array of groups.
Definition: nation.cpp:831
int nation_set_number(const struct nation_set *pset)
Return the nation set index.
Definition: nation.cpp:591
void nation_city_set_terrain_preference(struct nation_city *pncity, const struct terrain *pterrain, enum nation_city_preference prefer)
Set the default nation city preference for the terrain.
Definition: nation.cpp:366
struct nation_group * nation_group_by_rule_name(const char *name)
Return the nation group that has the given (untranslated) rule name.
Definition: nation.cpp:882
void nation_city_set_river_preference(struct nation_city *pncity, enum nation_city_preference prefer)
Set the default nation city preference about rivers.
Definition: nation.cpp:378
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
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_set * nation_set_new(const char *set_name, const char *set_rule_name, const char *set_description)
Add new set into the array of nation sets.
Definition: nation.cpp:599
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
Nation_type_id nation_index(const struct nation_type *pnation)
Return the nation index.
Definition: nation.cpp:464
const char * nation_leader_name(const struct nation_leader *pleader)
Return the name of the nation leader.
Definition: nation.cpp:257
const char * nation_group_untranslated_name(const struct nation_group *pgroup)
Return the untranslated name of a nation group (including qualifier, if any).
Definition: nation.cpp:932
const struct nation_leader_list * nation_leaders(const struct nation_type *pnation)
Returns the list the nation leader names.
Definition: nation.cpp:206
void nation_group_set_hidden(struct nation_group *pgroup, bool hidden)
Set whether this group should appear in the nation selection UI.
Definition: nation.cpp:900
struct nation_set * nation_set_by_rule_name(const char *name)
Return the nation set that has the given (untranslated) rule name.
Definition: nation.cpp:652
void nations_alloc(int num)
Allocate space for the given number of nations.
Definition: nation.cpp:520
enum barbarian_type nation_barbarian_type(const struct nation_type *nation)
Returns which kind of barbarians can use this nation.
Definition: nation.cpp:188
int nation_group_number(const struct nation_group *pgroup)
Return the nation group index.
Definition: nation.cpp:823
#define nation_leader_list_iterate(leaderlist, pleader)
Definition: nation.h:45
#define nation_sets_iterate_end
Definition: nation.h:286
#define nation_set_list_iterate_end
Definition: nation.h:56
#define nation_group_list_iterate(grouplist, pgroup)
Definition: nation.h:63
#define nation_sets_iterate(NAME_pset)
Definition: nation.h:283
nation_city_preference
Definition: nation.h:31
@ NCP_DISLIKE
Definition: nation.h:31
@ NCP_LIKE
Definition: nation.h:31
#define nation_leader_list_iterate_end
Definition: nation.h:47
#define nation_group_list_iterate_end
Definition: nation.h:65
#define nation_set_list_iterate(setlist, pset)
Definition: nation.h:54
#define nation_groups_iterate(NAME_pgroup)
Definition: nation.h:292
#define nation_groups_iterate_end
Definition: nation.h:296
void notify_conn(struct conn_list *dest, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
See notify_conn_packet - this is just the "non-v" version, with varargs.
Definition: notify.cpp:235
void packet_strvec_compute(char str[MAX_LEN_PACKET], QVector< QString > *qstrvec)
Definition: packets.cpp:806
#define MAX_LEN_MSG
Definition: packets.h:37
struct city_list * cities
Definition: packhand.cpp:122
int len
Definition: packhand.cpp:127
void send_nation_availability(struct conn_list *dest, bool nationset_change)
Tell clients which nations can be picked given current server settings.
Definition: plrhand.cpp:2574
void playercolor_init()
Initialise the player colors.
Definition: plrhand.cpp:3269
void count_playable_nations()
Update the server's cached number of playable nations.
Definition: plrhand.cpp:2529
void playercolor_free()
Free the memory allocated for the player color.
Definition: plrhand.cpp:3278
void playercolor_add(struct rgbcolor *prgbcolor)
Add a color to the list of all available player colors.
Definition: plrhand.cpp:3299
int playercolor_count()
Number of player colors defined.
Definition: plrhand.cpp:3319
struct section_file * secfile_load(const QString &filename, bool allow_duplicates)
Create a section file from a file.
Definition: registry.cpp:21
const char * secfile_error()
Returns the last error which occurred in a string.
const char * section_name(const struct section *psection)
Returns the section name.
void secfile_destroy(struct section_file *secfile)
Free a section file.
bool entry_bool_get(const struct entry *pentry, bool *value)
Gets an boolean value.
void secfile_check_unused(const struct section_file *secfile)
Print log messages for any entries in the file which have not been looked up – ie,...
bool secfile_lookup_int(const struct section_file *secfile, int *ival, const char *path,...)
Lookup a integer value in the secfile.
struct entry * secfile_entry_lookup(const struct section_file *secfile, const char *path,...)
Returns the entry at "fullpath" or nullptr if not matched.
int * secfile_lookup_int_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
Lookup a integer vector in the secfile.
const char * entry_name(const struct entry *pentry)
Returns the name of this entry.
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
Lookup a string value in the secfile.
const char ** secfile_lookup_str_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
Lookup a string vector in the secfile.
bool entry_str_get(const struct entry *pentry, const char **value)
Gets an string value.
const char * secfile_name(const struct section_file *secfile)
Return the filename the section file was loaded as, or "(anonymous)" if this sectionfile was created ...
bool secfile_lookup_bool_default(const struct section_file *secfile, bool def, const char *path,...)
Lookup a boolean value in the secfile.
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
Lookup a string value in the secfile.
struct entry * secfile_entry_by_path(const struct section_file *secfile, const char *path)
Returns the entry by the name or nullptr if not matched.
int secfile_lookup_int_default(const struct section_file *secfile, int def, const char *path,...)
Lookup a integer value in the secfile.
struct entry * section_entry_by_name(const struct section *psection, const QString &name)
Returns the first entry matching the name.
bool entry_int_get(const struct entry *pentry, int *value)
Gets an integer value.
struct section_list * secfile_sections_by_name_prefix(const struct section_file *secfile, const char *prefix)
Returns the list of sections which match the name prefix.
bool secfile_lookup_bool(const struct section_file *secfile, bool *bval, const char *path,...)
Lookup a boolean value in the secfile.
int secfile_lookup_int_def_min_max(const struct section_file *secfile, int defval, int minval, int maxval, const char *path,...)
Lookup a integer value in the secfile.
enum entry_type entry_type_get(const struct entry *pentry)
Returns the type of this entry or ENTRY_ILLEGAL or error.
@ ENTRY_FILEREFERENCE
Definition: registry_ini.h:538
@ ENTRY_INT
Definition: registry_ini.h:535
@ ENTRY_FLOAT
Definition: registry_ini.h:536
@ ENTRY_STR
Definition: registry_ini.h:537
@ ENTRY_ILLEGAL
Definition: registry_ini.h:539
@ ENTRY_BOOL
Definition: registry_ini.h:534
#define secfile_lookup_enum_vec(secfile, dim, specenum_type, path,...)
Definition: registry_ini.h:473
#define section_list_iterate(seclist, psection)
Definition: registry_ini.h:46
#define secfile_lookup_enum_default(secfile, defval, specenum_type, path, ...)
Definition: registry_ini.h:448
#define section_list_iterate_end
Definition: registry_ini.h:48
struct requirement req_from_str(const char *type, const char *range, bool survives, bool present, bool quiet, const char *value)
Parse a requirement type and value string into a requirement structure.
struct requirement req_from_values(int type, int range, bool survives, bool present, bool quiet, int value)
Set the values of a req from serializable integers.
#define requirement_vector_iterate_end
Definition: requirements.h:80
#define requirement_vector_iterate(req_vec, preq)
Definition: requirements.h:78
bool rgbcolor_load(struct section_file *file, struct rgbcolor **prgbcolor, const char *path,...)
Lookup an RGB color definition ([colorpath].red, [colorpath].green and [colorpath]....
Definition: rgbcolor.cpp:78
Road_type_id road_number(const struct road_type *proad)
Return the road id.
Definition: road.cpp:23
void road_integrators_cache_init()
Initialize the road integrators cache.
Definition: road.cpp:97
void road_type_init(struct extra_type *pextra, int idx)
Initialize road_type structures.
Definition: road.cpp:81
int rscompat_check_capabilities(struct section_file *file, const char *filename, struct rscompat_info *info)
Ruleset files should have a capabilities string datafile.options This checks the string and that the ...
Definition: rscompat.cpp:50
const char * rscompat_req_name_3_1(const char *type, const char *old_name)
Replace deprecated requirement type names with currently valid ones.
Definition: rscompat.cpp:1502
void rscompat_extra_adjust_3_1(struct rscompat_info *compat, struct extra_type *pextra)
Adjust freeciv-3.0 ruleset extra definitions to freeciv-3.1.
Definition: rscompat.cpp:1524
bool rscompat_auto_attack_3_1(struct rscompat_info *compat, struct action_auto_perf *auto_perf, size_t psize, enum unit_type_flag_id *protecor_flag)
Replace deprecated auto_attack configuration.
Definition: rscompat.cpp:1239
bool rscompat_old_effect_3_1(const char *type, struct section_file *file, const char *sec_name, struct rscompat_info *compat)
Check if effect name refers to one of the removed effects, and handle it if it does.
Definition: rscompat.cpp:606
bool rscompat_names(struct rscompat_info *info)
Do compatibility things with names before they are referred to.
Definition: rscompat.cpp:325
const char * rscompat_utype_flag_name_3_1(struct rscompat_info *compat, const char *old_type)
Replace deprecated unit type flag names with currently valid ones.
Definition: rscompat.cpp:1515
bool rscompat_old_slow_invasions_3_1(struct rscompat_info *compat, bool slow_invasions)
Replace slow_invasions and friends.
Definition: rscompat.cpp:1277
void rscompat_postprocess(struct rscompat_info *info)
Do compatibility things after regular ruleset loading.
Definition: rscompat.cpp:640
bool sanity_check_ruleset_data(bool ignore_retired)
Some more sanity checking once all rulesets are loaded.
Definition: rssanity.cpp:716
bool autoadjust_ruleset_data()
Apply some automatic defaults to already loaded rulesets.
Definition: rssanity.cpp:1389
#define check_cityname(name)
Definition: ruleset.cpp:101
static void ruleset_load_traits(struct trait_limits *out, struct section_file *file, const char *secname, const char *field_prefix)
Load trait values to array.
Definition: ruleset.cpp:1003
static bool load_rulesetdir(const char *rsdir, bool compat_mode, rs_conversion_logger logger, bool act, bool buffer_script, bool load_luadata)
Loads the rulesets from directory.
Definition: ruleset.cpp:8661
#define STYLE_SECTION_PREFIX
Definition: ruleset.cpp:84
static bool load_terrain_names(struct section_file *file, struct rscompat_info *compat)
Load names of terrain types so other rulesets can refer to terrains with their name.
Definition: ruleset.cpp:2501
char * get_script_buffer()
Return current script.lua buffer.
Definition: ruleset.cpp:244
struct requirement_vector * lookup_req_list(struct section_file *file, struct rscompat_info *compat, const char *sec, const char *sub, const char *rfor)
Load a requirement list.
Definition: ruleset.cpp:338
static bool load_style_names(struct section_file *file, struct rscompat_info *compat)
Load names of nation styles so other rulesets can refer to styles with their name.
Definition: ruleset.cpp:5318
#define MUSICSTYLE_SECTION_PREFIX
Definition: ruleset.cpp:78
static bool load_ruleset_governments(struct section_file *file, struct rscompat_info *compat)
This loads information from given governments.ruleset.
Definition: ruleset.cpp:4020
#define MULTIPLIER_SECTION_PREFIX
Definition: ruleset.cpp:98
static struct requirement_vector reqs_list
Definition: ruleset.cpp:114
static void send_ruleset_techs(struct conn_list *dest)
Send the techs ruleset information (all individual advances) to the specified connections.
Definition: ruleset.cpp:7497
#define section_strlcpy(dst, src)
Definition: ruleset.cpp:106
static bool load_action_range(struct section_file *file, action_id act)
Load range of an action.
Definition: ruleset.cpp:5986
#define check_name(name)
Definition: ruleset.cpp:100
static bool lookup_unit_list(struct section_file *file, const char *prefix, const char *entry, std::array< unit_type *, MAX_NUM_UNIT_LIST > &output, const char *filename)
Lookup a prefix.entry string vector in the file and fill in the array, which should hold MAX_NUM_UNIT...
Definition: ruleset.cpp:602
static void send_ruleset_units(struct conn_list *dest)
Send the units ruleset information (all individual units) to the specified connections.
Definition: ruleset.cpp:7319
static void send_ruleset_governments(struct conn_list *dest)
Send the government ruleset information to the specified connections.
Definition: ruleset.cpp:8170
static bool load_ruleset_techs(struct section_file *file, struct rscompat_info *compat)
Load technologies related ruleset data.
Definition: ruleset.cpp:1251
static void send_ruleset_resources(struct conn_list *dest)
Send the resource ruleset information to the specified connections.
Definition: ruleset.cpp:7742
static bool load_ruleset_buildings(struct section_file *file, struct rscompat_info *compat)
Load buildings related ruleset data.
Definition: ruleset.cpp:2389
static bool lookup_building_list(struct section_file *file, const char *prefix, const char *entry, int *output, const char *filename)
Lookup a prefix.entry string vector in the file and fill in the array, which should hold MAX_NUM_BUIL...
Definition: ruleset.cpp:726
static void nullcheck_secfile_destroy(struct section_file *file)
Destroy secfile.
Definition: ruleset.cpp:8640
static void send_ruleset_clauses(struct conn_list *dest)
Send the clause type ruleset information to the specified connections.
Definition: ruleset.cpp:8355
static void send_ruleset_game(struct conn_list *dest)
Send information in packet_ruleset_game (miscellaneous rules) to the specified connections.
Definition: ruleset.cpp:8490
char * parser_buffer
Definition: ruleset.cpp:193
static QString valid_ruleset_filename(const char *subdir, const char *name, const char *extension, bool optional)
datafilename() wrapper: tries to match in two ways.
Definition: ruleset.cpp:200
#define NATION_SECTION_PREFIX
Definition: ruleset.cpp:83
static bool load_ruleset_effects(struct section_file *file, struct rscompat_info *compat)
Load effects.ruleset file.
Definition: ruleset.cpp:5780
static void send_ruleset_nations(struct conn_list *dest)
Send the nations ruleset information (info on each nation) to the specified connections.
Definition: ruleset.cpp:8216
static void send_ruleset_roads(struct conn_list *dest)
Send the road ruleset information (all individual road types) to the specified connections.
Definition: ruleset.cpp:7912
char * get_parser_buffer()
Return current parser.lua buffer.
Definition: ruleset.cpp:249
static bool is_on_allowed_list(const char *name, const char **list, size_t len)
Check if a string is in a vector (case-insensitively).
Definition: ruleset.cpp:4412
static void send_ruleset_tech_classes(struct conn_list *dest)
Send the techs class information to the specified connections.
Definition: ruleset.cpp:7477
static void send_ruleset_action_enablers(struct conn_list *dest)
Send the action enabler ruleset information to the specified connections.
Definition: ruleset.cpp:8074
static void send_ruleset_control(struct conn_list *dest)
Send information in packet_ruleset_control (numbers of units etc, and other miscellany) to specified ...
Definition: ruleset.cpp:4212
bool load_rulesets(const char *restore, const char *alt, bool compat_mode, rs_conversion_logger logger, bool act, bool buffer_script, bool load_luadata)
Loads the rulesets.
Definition: ruleset.cpp:8582
#define GOODS_SECTION_PREFIX
Definition: ruleset.cpp:90
#define TERRAIN_SECTION_PREFIX
Definition: ruleset.cpp:92
static struct section_file * openload_ruleset_file(const char *whichset, const char *rsdir)
Do initial section_file_load on a ruleset file.
Definition: ruleset.cpp:255
static void send_ruleset_musics(struct conn_list *dest)
Send the music-style ruleset information (each style) to the specified connections.
Definition: ruleset.cpp:8460
static void strvec_store(QVector< QString > *psv, const char *const *vec, size_t size)
Stores the string vector from a normal vector.
Definition: ruleset.cpp:854
#define DISASTER_SECTION_PREFIX
Definition: ruleset.cpp:95
static void send_ruleset_goods(struct conn_list *dest)
Send the goods ruleset information (all individual goods types) to the specified connections.
Definition: ruleset.cpp:7956
static const char name_too_long[]
Definition: ruleset.cpp:104
static char(* base_sections)[MAX_SECTION_LABEL]
Definition: ruleset.cpp:111
#define CITYSTYLE_SECTION_PREFIX
Definition: ruleset.cpp:77
static bool lookup_tech(struct section_file *file, struct advance **result, const char *prefix, const char *entry, const char *filename, const char *description)
Lookup a string prefix.entry in the file and return the corresponding advances pointer.
Definition: ruleset.cpp:541
static bool load_game_names(struct section_file *file, struct rscompat_info *compat)
Load names from game.ruleset so other rulesets can refer to objects with their name.
Definition: ruleset.cpp:1032
static int secfile_lookup_int_default_min_max(struct section_file *file, int def, int min, int max, const char *path,...) fc__attribute((__format__(__printf__
Print an error message if the value is out of range.
Definition: ruleset.cpp:5898
static void send_ruleset_specialists(struct conn_list *dest)
Send the specialists ruleset information (all individual specialist types) to the specified connectio...
Definition: ruleset.cpp:7448
#define ADVANCE_SECTION_PREFIX
Definition: ruleset.cpp:74
#define EFFECT_SECTION_PREFIX
Definition: ruleset.cpp:79
static void send_ruleset_action_auto_performers(struct conn_list *dest)
Send action auto performer ruleset information to the specified connections.
Definition: ruleset.cpp:8108
static char(* extra_sections)[MAX_SECTION_LABEL]
Definition: ruleset.cpp:110
static char * lookup_string(struct section_file *file, const char *prefix, const char *suffix)
Lookup optional string, returning allocated memory or nullptr.
Definition: ruleset.cpp:833
static bool load_government_names(struct section_file *file, struct rscompat_info *compat)
Load names of governments so other rulesets can refer to governments with their name.
Definition: ruleset.cpp:3937
static int char * script_buffer
Definition: ruleset.cpp:192
static void send_ruleset_team_names(struct conn_list *dest)
Send all team names defined in the ruleset file(s) to the specified connections.
Definition: ruleset.cpp:8550
static void send_ruleset_cities(struct conn_list *dest)
Send the city-style ruleset information (each style) to the specified connections.
Definition: ruleset.cpp:8428
static bool lookup_building(struct section_file *file, const char *prefix, const char *entry, struct impr_type **result, const char *filename, const char *description)
Lookup a string prefix.entry in the file and return the corresponding improvement pointer.
Definition: ruleset.cpp:571
static struct extra_type * lookup_resource(const char *filename, const char *name, const char *jsection)
Look up the resource section name and return its pointer.
Definition: ruleset.cpp:897
#define ACTION_ENABLER_SECTION_PREFIX
Definition: ruleset.cpp:97
#define BASE_SECTION_PREFIX
Definition: ruleset.cpp:87
static enum fc_tristate openload_script_file(const char *whichset, const char *rsdir, char **buffer, bool optional)
Parse script file.
Definition: ruleset.cpp:283
static bool load_building_names(struct section_file *file, struct rscompat_info *compat)
Load names of buildings so other rulesets can refer to buildings with their name.
Definition: ruleset.cpp:2334
#define EXTRA_SECTION_PREFIX
Definition: ruleset.cpp:86
void send_rulesets(struct conn_list *dest)
Send all ruleset information to the specified connections.
Definition: ruleset.cpp:8890
#define CLAUSE_SECTION_PREFIX
Definition: ruleset.cpp:85
#define UNIT_SECTION_PREFIX
Definition: ruleset.cpp:94
#define ACHIEVEMENT_SECTION_PREFIX
Definition: ruleset.cpp:96
static bool load_ruleset_cities(struct section_file *file, struct rscompat_info *compat)
Load cities.ruleset file.
Definition: ruleset.cpp:5571
static bool load_ruleset_styles(struct section_file *file, struct rscompat_info *compat)
Load styles.ruleset file.
Definition: ruleset.cpp:5385
static bool load_ruleset_units(struct section_file *file, struct rscompat_info *compat)
Load units related ruleset data.
Definition: ruleset.cpp:1765
bool reload_rulesets_settings()
Reload the game settings saved in the ruleset file.
Definition: ruleset.cpp:8868
void rulesets_deinit()
Completely deinitialize ruleset system.
Definition: ruleset.cpp:8651
static bool lookup_time(const struct section_file *secfile, int *turns, const char *sec_name, const char *property_name, const char *filename, const char *item_name, bool *ok)
Look up a value comparable to activity_count (road_time, etc).
Definition: ruleset.cpp:955
static void send_ruleset_styles(struct conn_list *dest)
Send the nation style ruleset information (each style) to the specified connections.
Definition: ruleset.cpp:8337
#define NATION_GROUP_SECTION_PREFIX
Definition: ruleset.cpp:82
#define RULES_SUFFIX
Definition: ruleset.cpp:71
static void send_ruleset_disasters(struct conn_list *dest)
Send the disaster ruleset information (all individual disaster types) to the specified connections.
Definition: ruleset.cpp:7989
static bool lookup_terrain(struct section_file *file, const char *entry, const char *filename, struct terrain *pthis, struct terrain **result)
Look up the terrain by name and return its pointer.
Definition: ruleset.cpp:915
static bool lookup_tech_list(struct section_file *file, const char *prefix, const char *entry, int *output, const char *filename)
Lookup a prefix.entry string vector in the file and fill in the array, which should hold MAX_NUM_TECH...
Definition: ruleset.cpp:657
#define MAX_SECTION_LABEL
Definition: ruleset.cpp:105
#define BUILDING_SECTION_PREFIX
Definition: ruleset.cpp:76
static bool load_ruleset_game(struct section_file *file, bool act, struct rscompat_info *compat)
Load ruleset file.
Definition: ruleset.cpp:6041
static const char * check_leader_names(struct nation_type *pnation)
Check for duplicate leader names in nation.
Definition: ruleset.cpp:4250
static bool load_nation_names(struct section_file *file, struct rscompat_info *compat)
Load names of nations so other rulesets can refer to nations with their name.
Definition: ruleset.cpp:4274
static void send_ruleset_achievements(struct conn_list *dest)
Send the achievement ruleset information (all individual achievement types) to the specified connecti...
Definition: ruleset.cpp:8020
#define SCRIPT_SUFFIX
Definition: ruleset.cpp:72
static void send_ruleset_bases(struct conn_list *dest)
Send the base ruleset information (all individual base types) to the specified connections.
Definition: ruleset.cpp:7886
static bool load_ruleset_terrain(struct section_file *file, struct rscompat_info *compat)
Load terrain types related ruleset data.
Definition: ruleset.cpp:2833
static char(* resource_sections)[MAX_SECTION_LABEL]
Definition: ruleset.cpp:108
static bool load_action_actor_consuming_always(struct section_file *file, action_id act)
Load if the action always consumes the actor.
Definition: ruleset.cpp:6024
static bool load_tech_names(struct section_file *file, struct rscompat_info *compat)
Load names of technologies so other rulesets can refer to techs with their name.
Definition: ruleset.cpp:1125
#define SPECIALIST_SECTION_PREFIX
Definition: ruleset.cpp:91
static bool lookup_cbonus_list(struct rscompat_info *compat, struct combat_bonus_list *list, struct section_file *file, const char *sec, const char *sub)
Load combat bonus list.
Definition: ruleset.cpp:478
static bool load_action_kind(struct section_file *file, action_id act)
Load kind of an action.
Definition: ruleset.cpp:6008
static struct section_file * openload_luadata_file(const char *rsdir)
Load optional luadata.txt.
Definition: ruleset.cpp:311
static void send_ruleset_multipliers(struct conn_list *dest)
Send the multiplier ruleset information to the specified connections.
Definition: ruleset.cpp:8391
static void send_ruleset_actions(struct conn_list *dest)
Send action ruleset information to the specified connections.
Definition: ruleset.cpp:8043
static bool load_city_name_list(struct section_file *file, struct nation_type *pnation, const char *secfile_str1, const char *secfile_str2, const char **allowed_terrains, size_t atcount)
This function loads a city name list from a section file.
Definition: ruleset.cpp:4430
static struct government * lookup_government(struct section_file *file, const char *entry, const char *filename, struct government *fallback)
Lookup entry in the file and return the corresponding government index.
Definition: ruleset.cpp:809
static bool load_action_auto_uflag_block(struct section_file *file, struct action_auto_perf *auto_perf, const char *uflags_path, const char *filename)
Load a list of unit type flags that must be absent from the actor unit if an action auto performer sh...
Definition: ruleset.cpp:5474
static bool load_ruleset_nations(struct section_file *file, struct rscompat_info *compat)
Load nations.ruleset file.
Definition: ruleset.cpp:4597
static bool load_action_auto_actions(struct section_file *file, struct action_auto_perf *auto_perf, const char *actions_path, const char *filename)
Load the list of actions an action auto performer should try.
Definition: ruleset.cpp:5515
static void send_ruleset_unit_classes(struct conn_list *dest)
Send the units ruleset information (all individual unit classes) to the specified connections.
Definition: ruleset.cpp:7266
#define TECH_CLASS_SECTION_PREFIX
Definition: ruleset.cpp:75
#define RESOURCE_SECTION_PREFIX
Definition: ruleset.cpp:89
static bool lookup_unit_type(struct section_file *file, const char *prefix, const char *entry, const struct unit_type **result, const char *filename, const char *description)
Lookup a string prefix.entry in the file and set result to the corresponding unit_type.
Definition: ruleset.cpp:780
static void send_ruleset_extras(struct conn_list *dest)
Send the extra ruleset information (all individual extra types) to the specified connections.
Definition: ruleset.cpp:7765
#define rs_sanity_veteran(_path, _entry, _i, _condition, _action)
static QVector< QString > * lookup_strvec(struct section_file *file, const char *prefix, const char *suffix)
Lookup optional string vector, returning allocated memory or nullptr.
Definition: ruleset.cpp:874
static char(* road_sections)[MAX_SECTION_LABEL]
Definition: ruleset.cpp:112
static void send_ruleset_terrain(struct conn_list *dest)
Send the terrain ruleset information (terrain_control, and the individual terrain types) to the speci...
Definition: ruleset.cpp:7633
#define GOVERNMENT_SECTION_PREFIX
Definition: ruleset.cpp:80
static bool load_unit_names(struct section_file *file, struct rscompat_info *compat)
Load names of units so other rulesets can refer to units with their name.
Definition: ruleset.cpp:1475
static void send_ruleset_trade_routes(struct conn_list *dest)
Send the trade route types ruleset information (all individual trade route types) to the specified co...
Definition: ruleset.cpp:8148
static void notify_ruleset_fallback(const char *msg)
Make it clear to everyone that requested ruleset has not been loaded.
Definition: ruleset.cpp:8574
static void send_ruleset_buildings(struct conn_list *dest)
Send the buildings ruleset information (all individual improvements and wonders) to the specified con...
Definition: ruleset.cpp:7592
#define UNIT_CLASS_SECTION_PREFIX
Definition: ruleset.cpp:93
static bool ruleset_load_names(struct name_translation *pname, const char *domain, struct section_file *file, const char *sec_name)
Load "name" and (optionally) "rule_name" into a struct name_translation.
Definition: ruleset.cpp:982
#define ROAD_SECTION_PREFIX
Definition: ruleset.cpp:88
static char(* terrain_sections)[MAX_SECTION_LABEL]
Definition: ruleset.cpp:109
static bool load_action_range_max(struct section_file *file, action_id act)
Load max range of an action.
Definition: ruleset.cpp:5951
static bool load_muuk_as_action_auto(struct section_file *file, struct action_auto_perf *auto_perf, const char *item, const char *filename)
Load missing unit upkeep ruleset settings as action auto performers.
Definition: ruleset.cpp:5551
static bool load_action_ui_name(struct section_file *file, int act, const char *entry_name)
Load ui_name of one action.
Definition: ruleset.cpp:5936
#define NATION_SET_SECTION_PREFIX
Definition: ruleset.cpp:81
static bool load_ruleset_veteran(struct section_file *file, const char *path, struct veteran_system **vsystem, char *err, size_t err_len, bool compat)
Load veteran levels.
Definition: ruleset.cpp:1645
#define RS_DEFAULT_TECH_TRADE_LOSS_HOLES
Definition: ruleset.h:72
#define RS_DEFAULT_TECH_COST_STYLE
Definition: ruleset.h:79
#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
void(* rs_conversion_logger)(const char *msg)
Definition: ruleset.h:43
#define RS_DEFAULT_TECH_LOSS_HOLES
Definition: ruleset.h:74
#define RS_DEFAULT_HISTORY_INTEREST_PML
Definition: ruleset.h:86
#define RS_DEFAULT_TECH_UPKEEP_STYLE
Definition: ruleset.h:81
#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 RS_DEFAULT_MUUK_SHIELD_WIPE
Definition: ruleset.h:69
#define RS_DEFAULT_INITIAL_DIPLOMATIC_STATE
Definition: ruleset.h:77
#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 RS_DEFAULT_TECH_LEAKAGE
Definition: ruleset.h:80
#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
static struct compatibility compat[]
Definition: savecompat.cpp:109
bool script_server_init()
Initialize the scripting state.
void script_server_free()
Free the scripting data.
bool script_server_load_file(const char *filename, char **buf)
Load script to a buffer.
bool script_server_do_file(struct connection *caller, const char *filename)
Parse and execute the script at filename in the same instance as the ruleset.
bool settings_ruleset(struct section_file *file, const char *section, bool act)
Load game settings from ruleset file 'game.ruleset'.
Definition: settings.cpp:4058
const QStringList & get_data_dirs()
Returns a list of data directory paths, in the order in which they should be searched.
Definition: shared.cpp:533
bool check_strlen(const char *str, size_t len, const char *errmsg)
Check the length of the given string.
Definition: shared.cpp:364
QString fileinfoname(const QStringList &dirs, const QString &filename)
Returns a filename to access the specified file from a directory by searching all specified directori...
Definition: shared.cpp:661
void remove_leading_trailing_spaces(char *s)
Removes leading and trailing spaces in string pointed to by 's'.
Definition: shared.cpp:353
fc_tristate
Definition: shared.h:42
@ TRI_YES
Definition: shared.h:42
@ TRI_NO
Definition: shared.h:42
@ TRI_MAYBE
Definition: shared.h:42
#define ARRAY_SIZE(x)
Definition: shared.h:79
const char * specialist_rule_name(const struct specialist *sp)
Return the (untranslated) rule name of the specialist type.
Definition: specialist.cpp:142
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
#define DEFAULT_SPECIALIST
Definition: specialist.h:37
size_t size
Definition: specvec.h:64
const char * aifill(int amount)
Fill or remove players to meet the given aifill.
Definition: srv_main.cpp:2440
void update_nations_with_startpos()
Update information about which nations have start positions on the map.
Definition: srv_main.cpp:2239
struct requirement_vector reqs
Definition: actions.h:461
enum action_auto_perf_cause cause
Definition: actions.h:457
action_id alternatives[MAX_NUM_ACTIONS]
Definition: actions.h:465
action_id action
Definition: actions.h:364
struct requirement_vector actor_reqs
Definition: actions.h:365
struct requirement_vector target_reqs
Definition: actions.h:366
action_id id
Definition: actions.h:306
bool actor_consuming_always
Definition: actions.h:337
int max_distance
Definition: actions.h:320
bool quiet
Definition: actions.h:327
enum action_result result
Definition: actions.h:308
char ui_name[MAX_LEN_NAME]
Definition: actions.h:323
enum action_actor_kind actor_kind
Definition: actions.h:310
bv_actions blocked_by
Definition: actions.h:331
enum action_target_kind target_kind
Definition: actions.h:311
int min_distance
Definition: actions.h:320
Definition: tech.h:113
struct advance * require[AR_SIZE]
Definition: tech.h:120
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
bv_base_flags flags
Definition: base.h:51
int vision_invis_sq
Definition: base.h:48
int vision_subs_sq
Definition: base.h:49
char citizens_graphic[MAX_LEN_NAME]
Definition: city.h:468
char graphic_alt[MAX_LEN_NAME]
Definition: city.h:467
char graphic[MAX_LEN_NAME]
Definition: city.h:466
char citizens_graphic_alt[MAX_LEN_NAME]
Definition: city.h:469
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
bool enabled
Definition: diptreaty.h:48
enum unit_type_flag_id flag
Definition: unittype.h:432
bv_extras conflicts
Definition: extras.h:116
int id
Definition: extras.h:75
struct name_translation name
Definition: extras.h:76
int build_cost
Definition: improvement.h:68
char graphic_str[MAX_LEN_NAME]
Definition: improvement.h:64
int upkeep
Definition: improvement.h:69
enum impr_genus_id genus
Definition: improvement.h:71
char graphic_alt[MAX_LEN_NAME]
Definition: improvement.h:65
struct requirement_vector obsolete_by
Definition: improvement.h:67
int sabotage
Definition: improvement.h:70
char soundtag_alt[MAX_LEN_NAME]
Definition: improvement.h:75
struct requirement_vector reqs
Definition: improvement.h:66
struct name_translation name
Definition: improvement.h:61
bv_impr_flags flags
Definition: improvement.h:72
QVector< QString > * helptext
Definition: improvement.h:73
char soundtag[MAX_LEN_NAME]
Definition: improvement.h:74
Definition: climisc.h:66
struct requirement_vector reqs
Definition: style.h:28
QString music_peaceful
Definition: style.h:26
QString music_combat
Definition: style.h:27
Nation default cities.
Definition: nation.cpp:297
bool hidden
Definition: nation.h:152
Functions for handling the nations.
Definition: nation.cpp:33
struct name_translation noun_plural
Definition: nation.h:81
struct name_translation adjective
Definition: nation.h:80
struct nation_type::@48::@50 server
char * legend
Definition: nation.h:86
enum barbarian_type barb_type
Definition: nation.h:89
struct universal source
Definition: requirements.h:68
int g
Definition: rgbcolor.h:27
int b
Definition: rgbcolor.h:27
int r
Definition: rgbcolor.h:27
Definition: road.h:54
struct requirement_vector first_reqs
Definition: road.h:64
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
bv_roads integrates
Definition: road.h:66
bv_road_flags flags
Definition: road.h:67
int move_cost
Definition: road.h:57
enum road_compat compat
Definition: road.h:62
bool compat_mode
Definition: rscompat.h:24
rs_conversion_logger log_cb
Definition: rscompat.h:25
Definition: servers.h:55
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 fixed
Definition: traits.h:39
int min
Definition: traits.h:37
int max
Definition: traits.h:38
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
struct nation_style * style_by_rule_name(const char *name)
Returns style matching rule name or nullptr if there is no style with such name.
Definition: style.cpp:103
struct music_style * music_style_by_number(int id)
Return music style of given id.
Definition: style.cpp:158
void styles_alloc(int count)
Initialise styles structures.
Definition: style.cpp:30
struct nation_style * style_by_number(int id)
Return style of given id.
Definition: style.cpp:74
int style_number(const struct nation_style *pstyle)
Return the style id.
Definition: style.cpp:54
void music_styles_alloc(int count)
Initialise music styles structures.
Definition: style.cpp:121
int style_index(const struct nation_style *pstyle)
Return the style index.
Definition: style.cpp:64
#define music_styles_iterate(_p)
Definition: style.h:68
#define music_styles_iterate_end
Definition: style.h:75
#define styles_iterate(_p)
Definition: style.h:40
#define styles_iterate_end
Definition: style.h:46
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
size_t fc_strlcpy(char *dest, const char *src, size_t n)
fc_strlcpy() provides utf-8 version of (non-standard) function strlcpy() It is intended as more user-...
Definition: support.cpp:412
int fc_strcasecmp(const char *str0, const char *str1)
Compare strings like strcmp(), but ignoring case.
Definition: support.cpp:89
size_t fc_strlcat(char *dest, const char *src, size_t n)
fc_strlcat() provides utf-8 version of (non-standard) function strlcat() It is intended as more user-...
Definition: support.cpp:448
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition: support.cpp:512
#define sz_strlcpy(dest, src)
Definition: support.h:140
int fc__attribute((nonnull(1, 3)))
#define fc_strdup(str)
Definition: support.h:111
const char * team_slot_defined_name(const struct team_slot *tslot)
Returns the name defined in the ruleset for this slot.
Definition: team.cpp:261
int team_slot_index(const struct team_slot *tslot)
Returns the index of the team slots.
Definition: team.cpp:120
int team_slot_count()
Returns the total number of team slots (including used slots).
Definition: team.cpp:101
struct team_slot * team_slot_by_number(int team_id)
Return the possibly unused and uninitialized team slot.
Definition: team.cpp:157
void team_slot_set_defined_name(struct team_slot *tslot, const char *team_name)
Set the name defined in the ruleset for this slot.
Definition: team.cpp:272
#define team_slots_iterate_end
Definition: team.h:66
#define team_slots_iterate(_tslot)
Definition: team.h:62
struct tech_class * tech_class_by_rule_name(const char *name)
Does a linear search of tech_classes[].name.vernacular Returns nullptr when none match.
Definition: tech.cpp:335
void set_user_tech_flag_name(enum tech_flag_id id, const char *name, const char *helptxt)
Sets user defined name for tech flag.
Definition: tech.cpp:378
struct advance * valid_advance(struct advance *padvance)
Returns pointer when the advance "exists" in this game, returns nullptr otherwise.
Definition: tech.cpp:138
struct advance * advance_by_rule_name(const char *name)
Does a linear search of advances[].name.vernacular Returns nullptr when none match.
Definition: tech.cpp:180
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
void techs_precalc_data()
Function to precalculate needed data for technologies.
Definition: tech.cpp:207
const char * tech_flag_helptxt(enum tech_flag_id id)
Return the (untranslated) helptxt of the user tech flag.
Definition: tech.cpp:413
const char * tech_flag_id_name_cb(enum tech_flag_id flag)
Tech flag name callback, called from specenum code.
Definition: tech.cpp:401
Tech_type_id advance_count()
Return the number of advances/technologies.
Definition: tech.cpp:68
Tech_type_id advance_number(const struct advance *padvance)
Return the advance index.
Definition: tech.cpp:85
#define tech_class_index(_ptclass_)
Definition: tech.h:167
#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_iterate(_start, _p)
Definition: tech.h:232
#define A_FIRST
Definition: tech.h:37
#define A_NONE
Definition: tech.h:36
#define tech_class_iterate(_p)
Definition: tech.h:172
#define advance_iterate_end
Definition: tech.h:238
#define A_LAST
Definition: tech.h:38
Terrain_type_id terrain_count()
Return the number of terrains.
Definition: terrain.cpp:93
struct terrain * terrain_by_number(const Terrain_type_id type)
Return the terrain for the given terrain index.
Definition: terrain.cpp:128
const char * terrain_flag_id_name_cb(enum terrain_flag_id flag)
Terrain flag name callback, called from specenum code.
Definition: terrain.cpp:696
struct resource_type * resource_type_init(struct extra_type *pextra)
Initialize resource_type structure.
Definition: terrain.cpp:209
struct terrain * terrain_by_rule_name(const char *name)
Return the terrain type matching the name, or T_UNKNOWN if none matches.
Definition: terrain.cpp:140
Terrain_type_id terrain_index(const struct terrain *pterrain)
Return the terrain index.
Definition: terrain.cpp:110
const char * terrain_flag_helptxt(enum terrain_flag_id id)
Return the (untranslated) helptxt of the user terrain flag.
Definition: terrain.cpp:708
void set_user_terrain_flag_name(enum terrain_flag_id id, const char *name, const char *helptxt)
Sets user defined name for terrain flag.
Definition: terrain.cpp:673
Terrain_type_id terrain_number(const struct terrain *pterrain)
Return the terrain index.
Definition: terrain.cpp:119
#define terrain_type_iterate(_p)
Definition: terrain.h:331
#define MAX_RESOURCE_TYPES
Definition: terrain.h:61
#define T_NONE
Definition: terrain.h:50
#define TERRAIN_UNKNOWN_IDENTIFIER
Definition: terrain.h:181
#define terrain_type_iterate_end
Definition: terrain.h:337
#define RESOURCE_NONE_IDENTIFIER
Definition: terrain.h:41
#define RESOURCE_NULL_IDENTIFIER
Definition: terrain.h:40
#define MAX_NUM_TERRAINS
Definition: terrain.h:58
#define T_FIRST
Definition: terrain.h:54
#define MAX_NUM_USER_TER_FLAGS
Definition: terrain.h:140
#define ACTIVITY_FACTOR
Definition: tile.h:151
Q_LOGGING_CATEGORY(tileset_category, "freeciv.tileset")
Functions for handling the tilespec files which describe the files and contents of tilesets.
const char * goods_rule_name(struct goods_type *pgood)
Return untranslated name of this goods type.
enum traderoute_illegal_cancelling traderoute_cancelling_type_by_name(const char *name)
Get traderoute cancelling type by name.
Goods_type_id goods_number(const struct goods_type *pgood)
Return the goods id.
struct trade_route_settings * trade_route_settings_by_type(enum trade_route_type type)
Get trade route settings related to type.
Goods_type_id goods_index(const struct goods_type *pgood)
Return the goods index.
enum trade_route_type trade_route_type_by_name(const char *name)
Get trade route type by name.
@ TRI_LAST
Definition: traderoutes.h:27
#define goods_type_iterate_end
Definition: traderoutes.h:224
#define goods_type_iterate(_p)
Definition: traderoutes.h:218
trade_route_type
Definition: traderoutes.h:30
@ TRT_NATIONAL
Definition: traderoutes.h:31
@ TRT_LAST
Definition: traderoutes.h:41
#define TRAIT_DEFAULT_VALUE
Definition: traits.h:27
void set_unit_class_caches(struct unit_class *pclass)
Set caches for unit class.
Definition: unittype.cpp:2349
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
Unit_type_id utype_count()
Return the number of unit types.
Definition: unittype.cpp:74
void set_unit_type_caches(struct unit_type *ptype)
Set caches for unit types.
Definition: unittype.cpp:2408
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
struct unit_class * unit_class_by_rule_name(const char *s)
Returns the unit class that has the given (untranslated) rule name.
Definition: unittype.cpp:1463
struct veteran_system * veteran_system_new(int count)
Allocate new veteran system structure with given veteran level count.
Definition: unittype.cpp:2281
void veteran_system_definition(struct veteran_system *vsystem, int level, const char *vlist_name, int vlist_power, int vlist_move, int vlist_raise, int vlist_wraise)
Fill veteran level in given veteran system with given information.
Definition: unittype.cpp:2310
int utype_veteran_levels(const struct unit_type *punittype)
Return veteran levels of the given unit type.
Definition: unittype.cpp:2254
void role_unit_precalcs()
Initialize; it is safe to call this multiple times (e.g., if units have changed due to rulesets in cl...
Definition: unittype.cpp:1838
struct unit_type * unit_type_by_rule_name(const char *name)
Returns the unit type that has the given (untranslated) rule name.
Definition: unittype.cpp:1444
Unit_type_id utype_number(const struct unit_type *punittype)
Return the unit type index.
Definition: unittype.cpp:91
Unit_type_id utype_index(const struct unit_type *punittype)
Return the unit type index.
Definition: unittype.cpp:82
void set_user_unit_class_flag_name(enum unit_class_flag_id id, const char *name, const char *helptxt)
Sets user defined name for unit class flag.
Definition: unittype.cpp:1493
const char * uclass_rule_name(const struct unit_class *pclass)
Return the (untranslated) rule name of the unit class.
Definition: unittype.cpp:1333
Unit_Class_id uclass_number(const struct unit_class *pclass)
Return the unit_class index.
Definition: unittype.cpp:2120
void unit_type_action_cache_init()
Cache what unit types may be allowed do what actions, both at all and when certain properties are tru...
Definition: unittype.cpp:722
void set_user_unit_type_flag_name(enum unit_type_flag_id id, const char *name, const char *helptxt)
Sets user defined name for unit flag.
Definition: unittype.cpp:1556
const struct veteran_level * utype_veteran_level(const struct unit_type *punittype, int level)
Return veteran level properties of given unit in given veterancy level.
Definition: unittype.cpp:2224
static bool uclass_has_flag(const struct unit_class *punitclass, enum unit_class_flag_id flag)
Definition: unittype.h:704
#define utype_class(_t_)
Definition: unittype.h:691
#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 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 unit_type_iterate(_p)
Definition: unittype.h:785
#define U_LAST
Definition: unittype.h:31
#define uclass_index(_c_)
Definition: unittype.h:684
#define unit_class_iterate_end
Definition: unittype.h:829
#define unit_type_iterate_end
Definition: unittype.h:791
#define MAX_NUM_USER_UCLASS_FLAGS
Definition: unittype.h:98