Freeciv-3.4
Loading...
Searching...
No Matches
ruleload.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include <stdarg.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22
23/* utility */
24#include "bitvector.h"
25#include "deprecations.h"
26#include "fcintl.h"
27#include "log.h"
28#include "mem.h"
29#include "registry.h"
30#include "shared.h"
31#include "string_vector.h"
32#include "support.h"
33
34/* common */
35#include "accessarea.h"
36#include "achievements.h"
37#include "actions.h"
38#include "ai.h"
39#include "base.h"
40#include "capability.h"
41#include "city.h"
42#include "counters.h"
43#include "effects.h"
44#include "extras.h"
45#include "fc_types.h"
46#include "featured_text.h"
47#include "game.h"
48#include "government.h"
49#include "map.h"
50#include "movement.h"
51#include "multipliers.h"
52#include "name_translation.h"
53#include "nation.h"
54#include "packets.h"
55#include "player.h"
56#include "requirements.h"
57#include "rgbcolor.h"
58#include "road.h"
59#include "sex.h"
60#include "specialist.h"
61#include "style.h"
62#include "tech.h"
63#include "tiledef.h"
64#include "traderoutes.h"
65#include "unit.h"
66#include "unittype.h"
67
68/* server */
69#include "citytools.h"
70#include "notify.h"
71#include "plrhand.h"
72#include "rscompat.h"
73#include "rssanity.h"
74#include "settings.h"
75#include "srv_main.h"
76
77/* server/advisors */
78#include "advruleset.h"
79
80/* server/scripting */
81#include "script_server.h"
82
83#include "ruleload.h"
84
85/* RULESET_SUFFIX already used, no leading dot here */
86#define RULES_SUFFIX "ruleset"
87#define SCRIPT_SUFFIX "lua"
88
89#define ADVANCE_SECTION_PREFIX "advance_"
90#define TECH_CLASS_SECTION_PREFIX "techclass_"
91#define BUILDING_SECTION_PREFIX "building_"
92#define CITYSTYLE_SECTION_PREFIX "citystyle_"
93#define MUSICSTYLE_SECTION_PREFIX "musicstyle_"
94#define UEFF_SECTION_PREFIX "ueff_"
95#define EFFECT_SECTION_PREFIX "effect_"
96#define GOVERNMENT_SECTION_PREFIX "government_"
97#define NATION_SET_SECTION_PREFIX "nset" /* without underscore? */
98#define NATION_GROUP_SECTION_PREFIX "ngroup" /* without underscore? */
99#define NATION_SECTION_PREFIX "nation" /* without underscore? */
100#define STYLE_SECTION_PREFIX "style_"
101#define CLAUSE_SECTION_PREFIX "clause_"
102#define EXTRA_SECTION_PREFIX "extra_"
103#define BASE_SECTION_PREFIX "base_"
104#define ROAD_SECTION_PREFIX "road_"
105#define RESOURCE_SECTION_PREFIX "resource_"
106#define TILEDEF_SECTION_PREFIX "tiledef_"
107#define GOODS_SECTION_PREFIX "goods_"
108#define SPECIALIST_SECTION_PREFIX "specialist_"
109#define SUPER_SPECIALIST_SECTION_PREFIX "super_specialist_"
110#define TERRAIN_SECTION_PREFIX "terrain_"
111#define UNIT_CLASS_SECTION_PREFIX "unitclass_"
112#define UNIT_SECTION_PREFIX "unit_"
113#define DISASTER_SECTION_PREFIX "disaster_"
114#define ACHIEVEMENT_SECTION_PREFIX "achievement_"
115#define ENABLER_SECTION_PREFIX "enabler_"
116#define ACTION_SECTION_PREFIX "action_"
117#define MULTIPLIER_SECTION_PREFIX "multiplier_"
118#define COUNTER_SECTION_PREFIX "counter_"
119
120#define check_name(name) (check_strlen(name, MAX_LEN_NAME, nullptr))
121#define check_cityname(name) (check_strlen(name, MAX_LEN_CITYNAME, nullptr))
122
123/* Avoid re-reading files */
124static const char name_too_long[] = "Name \"%s\" too long; truncating.";
125#define MAX_SECTION_LABEL 64
126#define section_strlcpy(dst, src) \
127 (void) loud_strlcpy(dst, src, MAX_SECTION_LABEL, name_too_long)
128static char *resource_sections = nullptr;
129static char *terrain_sections = nullptr;
130static char *extra_sections = nullptr;
131static char *base_sections = nullptr;
132static char *road_sections = nullptr;
133static char *tiledef_sections = nullptr;
134
136
137static bool load_rulesetdir(const char *rsdir, bool compat_mode,
139 bool act, bool buffer_script, bool load_luadata);
140static struct section_file *openload_ruleset_file(const char *whichset,
141 const char *rsdir);
142
143static bool load_game_names(struct section_file *file,
144 struct rscompat_info *compat);
145static bool load_action_names(struct section_file *file,
146 struct rscompat_info *compat);
147static bool load_tech_names(struct section_file *file,
148 struct rscompat_info *compat);
149static bool load_unit_names(struct section_file *file,
150 struct rscompat_info *compat);
151static bool load_building_names(struct section_file *file,
152 struct rscompat_info *compat);
153static bool load_government_names(struct section_file *file,
154 struct rscompat_info *compat);
155static bool load_terrain_names(struct section_file *file,
156 struct rscompat_info *compat);
157static bool load_style_names(struct section_file *file,
158 struct rscompat_info *compat);
159static bool load_nation_names(struct section_file *file,
160 struct rscompat_info *compat);
161static bool load_city_name_list(struct section_file *file,
162 struct nation_type *pnation,
163 const char *secfile_str1,
164 const char *secfile_str2,
165 const char **allowed_terrains,
166 size_t atcount);
167
168static bool load_ruleset_techs(struct section_file *file,
169 struct rscompat_info *compat);
170static bool load_ruleset_units(struct section_file *file,
171 struct rscompat_info *compat);
172static bool load_ruleset_buildings(struct section_file *file,
173 struct rscompat_info *compat);
174static bool load_ruleset_governments(struct section_file *file,
175 struct rscompat_info *compat);
176static bool load_ruleset_terrain(struct section_file *file,
177 struct rscompat_info *compat);
178static bool load_ruleset_styles(struct section_file *file,
179 struct rscompat_info *compat);
180static bool load_ruleset_cities(struct section_file *file,
181 struct rscompat_info *compat);
182static bool load_ruleset_effects(struct section_file *file,
183 struct rscompat_info *compat);
184static bool load_ruleset_game(struct section_file *file, bool act,
185 struct rscompat_info *compat);
186static bool load_ruleset_actions(struct section_file *file,
187 struct section_file *gamefile,
188 struct rscompat_info *compat);
189
190static void send_ruleset_tech_classes(struct conn_list *dest);
191static void send_ruleset_techs(struct conn_list *dest);
192static void send_ruleset_unit_classes(struct conn_list *dest);
193static void send_ruleset_units(struct conn_list *dest);
194static void send_ruleset_buildings(struct conn_list *dest);
195static void send_ruleset_terrain(struct conn_list *dest);
196static void send_ruleset_resources(struct conn_list *dest);
197static void send_ruleset_extras(struct conn_list *dest);
198static void send_ruleset_bases(struct conn_list *dest);
199static void send_ruleset_roads(struct conn_list *dest);
200static void send_ruleset_tiledefs(struct conn_list *dest);
201static void send_ruleset_goods(struct conn_list *dest);
202static void send_ruleset_governments(struct conn_list *dest);
203static void send_ruleset_styles(struct conn_list *dest);
204static void send_ruleset_clauses(struct conn_list *dest);
205static void send_ruleset_musics(struct conn_list *dest);
206static void send_ruleset_cities(struct conn_list *dest);
207static void send_ruleset_game(struct conn_list *dest);
208static void send_ruleset_team_names(struct conn_list *dest);
209
210static bool load_ruleset_veteran(struct section_file *file,
211 const char *path,
212 struct veteran_system **vsystem, char *err,
213 size_t err_len);
214static bool load_specialist(const struct section *psection,
215 struct specialist *s,
216 struct section_file *file);
218 int def, int min, int max,
219 const char *path, ...)
221
222char *script_buffer = nullptr;
223char *parser_buffer = nullptr;
224
225/**********************************************************************/
230 const char *file, const char *function,
232 const char *format, ...)
233{
234 va_list args;
235 char buf[MAX_LEN_LOG_LINE];
236
237 if (logger == nullptr && !log_do_output_for_level(level)) {
238 return;
239 }
240
241 va_start(args, format);
242 if (logger != nullptr) {
243 fc_vsnprintf(buf, sizeof(buf), format, args);
244 logger(buf);
245 } else {
246 vdo_log(file, function, line, FALSE, level, buf, sizeof(buf), format, args);
247 }
248 va_end(args);
249
250 if (LOG_FATAL >= level) {
252 }
253}
254
255/**********************************************************************/
259{
260 int purged = 0;
261
262 action_iterate(act_id) {
263 struct action *paction = action_by_number(act_id);
264
266 == 0) {
267 /* Not relevant. */
268 continue;
269 }
270
271 /* Impossible hard requirement. */
273 /* Make sure that all action enablers are disabled. */
275 ae) {
276 ae->rulesave.ruledit_disabled = TRUE;
277 purged++;
279
280 log_normal("Purged all action enablers for %s",
282 }
283
284 /* Impossible requirement vector requirement. */
286 ae) {
287 if (!ae->rulesave.ruledit_disabled
289 || req_vec_is_impossible_to_fulfill(&ae->target_reqs))) {
290 ae->rulesave.ruledit_disabled = TRUE;
291 purged++;
292 log_normal("Purged unused action enabler for %s",
294 }
297
298 return purged;
299}
300
301/**********************************************************************/
305{
306 int purged = 0;
307 enum effect_type type;
308
313 eft->rulesave.do_not_save = TRUE;
314 purged++;
315 log_normal("Purged unused effect for %s",
316 effect_type_name(eft->type));
317 }
319 }
320
321 return purged;
322}
323
324/**********************************************************************/
328{
329 int purged = 0;
330
333
334 return purged;
335}
336
337/**********************************************************************/
342 const char *msg)
343{
344 struct req_vec_problem *problem;
345 bool result;
346
348 reqs);
349
350 if (problem == nullptr) {
351 /* No problem. */
352 return FALSE;
353 }
354
355 if (problem->num_suggested_solutions == 0) {
356 /* No solution. */
358 return FALSE;
359 }
360
361 if (problem->num_suggested_solutions == 1
362 && problem->suggested_solutions[0].operation == RVCO_REMOVE) {
363 /* Remove !present req that never is there. */
364 log_normal("%s", msg);
365 result = req_vec_change_apply(&problem->suggested_solutions[0],
368 return result;
369 }
370
371 /* Not handled. Don't know what this is. */
372 fc_assert(problem->num_suggested_solutions == 1);
374 return FALSE;
375}
376
377/**********************************************************************/
382 const char *msg)
383{
384 struct req_vec_problem *problem;
385 bool result;
386
388 reqs);
389
390 if (problem == nullptr) {
391 /* No problem. */
392 return FALSE;
393 }
394
395 if (problem->num_suggested_solutions == 0) {
396 /* No solution. */
398 return FALSE;
399 }
400
401 if (problem->num_suggested_solutions == 2
402 && problem->suggested_solutions[0].operation == RVCO_REMOVE
403 && problem->suggested_solutions[1].operation == RVCO_REMOVE
404 && are_requirements_equal(&problem->suggested_solutions[0].req,
405 &problem->suggested_solutions[1].req)) {
406 /* Simple duplication is handled. */
407 log_normal("%s", msg);
408 result = req_vec_change_apply(&problem->suggested_solutions[1],
411 return result;
412 }
413
414 /* Requirements of different kinds making each other redundant isn't
415 * supported yet. It could be done by always removing the most general
416 * requirement. So unit type is kept when redundant with unit flag, unit
417 * class and unit class flag etc. */
419 return FALSE;
420}
421
422/**********************************************************************/
427 const char *msg)
428{
429 return (purge_unused_req_vec(reqs, msg)
431}
432
433/**********************************************************************/
438{
439 int purged = 0;
440
441 action_iterate(act_id) {
442 struct action *paction = action_by_number(act_id);
443 char actor_reqs[MAX_LEN_NAME * 2];
444 char target_reqs[MAX_LEN_NAME * 2];
445
446 /* Error log text */
447 fc_snprintf(actor_reqs, sizeof(actor_reqs),
448 "Purged redundant requirement in"
449 " %s in action enabler for %s",
450 "actor_reqs", action_rule_name(paction));
451 fc_snprintf(target_reqs, sizeof(target_reqs),
452 "Purged redundant requirement in"
453 " %s in action enabler for %s",
454 "target_reqs", action_rule_name(paction));
455
456 /* Do the purging. */
458 ae) {
459 while (!ae->rulesave.ruledit_disabled
460 && (purge_redundant_req_vec(&ae->actor_reqs, actor_reqs)
461 || purge_redundant_req_vec(&ae->target_reqs,
462 target_reqs))) {
463 purged++;
464 }
467
468 return purged;
469}
470
471/**********************************************************************/
476{
477 int purged = 0;
478 enum effect_type type;
479
482 char msg[MAX_LEN_NAME * 2];
483
484 /* Error log text */
485 fc_snprintf(msg, sizeof(msg),
486 "Purged redundant requirement in effect of type %s",
488
489 /* Do the purging. */
491 while (purge_redundant_req_vec(&eft->reqs, msg)) {
492 purged++;
493 }
495 }
496
497 return purged;
498}
499
500/**********************************************************************/
505{
506 int purged = 0;
507
510
511 if (purged > 0) {
512 /* An unused requirement may be an obligatory hard requirement. */
514 }
515
516 return purged;
517}
518
519/**********************************************************************/
523static const char *valid_ruleset_filename(const char *subdir,
524 const char *name,
525 const char *extension,
526 bool optional)
527{
528 char filename[512];
529 const char *dfilename;
530
531 fc_assert_ret_val(subdir && name && extension, nullptr);
532
533 fc_snprintf(filename, sizeof(filename), "%s" DIR_SEPARATOR "%s.%s",
535 log_verbose("Trying \"%s\".", filename);
536 dfilename = fileinfoname(get_data_dirs(), filename);
537 if (dfilename) {
538 return dfilename;
539 }
540
541 fc_snprintf(filename, sizeof(filename), "default" DIR_SEPARATOR "%s.%s", name, extension);
542 log_verbose("Trying \"%s\": default ruleset directory.", filename);
543 dfilename = fileinfoname(get_data_dirs(), filename);
544 if (dfilename) {
545 return dfilename;
546 }
547
548 fc_snprintf(filename, sizeof(filename), "%s_%s.%s",
550 log_verbose("Trying \"%s\": alternative ruleset filename syntax.",
551 filename);
552 dfilename = fileinfoname(get_data_dirs(), filename);
553 if (dfilename) {
554 return dfilename;
555 } else if (!optional) {
556 ruleset_error(nullptr, LOG_ERROR,
557 /* TRANS: message about an installation error. */
558 _("Could not find a readable \"%s.%s\" ruleset file."),
559 name, extension);
560 }
561
562 return nullptr;
563}
564
565/**********************************************************************/
569{
570 return script_buffer;
571}
572
573/**********************************************************************/
577{
578 return parser_buffer;
579}
580
581/**********************************************************************/
585static struct section_file *openload_ruleset_file(const char *whichset,
586 const char *rsdir)
587{
588 char sfilename[512];
591 struct section_file *secfile;
592
593 if (dfilename == nullptr) {
594 return nullptr;
595 }
596
597 /* Need to save a copy of the filename for following message, since
598 section_file_load() may call datafilename() for includes. */
600 secfile = secfile_load(sfilename, FALSE);
601
602 if (secfile == nullptr) {
603 ruleset_error(nullptr, LOG_ERROR, "Could not load ruleset '%s':\n%s",
605 }
606
607 return secfile;
608}
609
610/**********************************************************************/
613static enum fc_tristate openload_script_file(const char *whichset, const char *rsdir,
614 char **buffer, bool optional)
615{
618
619 if (dfilename == nullptr) {
620 return optional ? TRI_MAYBE : TRI_NO;
621 }
622
623 if (buffer == nullptr) {
624 if (!script_server_do_file(nullptr, dfilename)) {
625 ruleset_error(nullptr, LOG_ERROR,
626 "\"%s\": could not load ruleset script.",
627 dfilename);
628
629 return TRI_NO;
630 }
631 } else {
633 }
634
635 return TRI_YES;
636}
637
638/**********************************************************************/
641static struct section_file *openload_luadata_file(const char *rsdir)
642{
643 struct section_file *secfile;
644 char sfilename[512];
645 const char *dfilename = valid_ruleset_filename(rsdir, "luadata",
646 "txt", TRUE);
647
648 if (dfilename == nullptr) {
649 return nullptr;
650 }
651
652 /* Need to save a copy of the filename for following message, since
653 section_file_load() may call datafilename() for includes. */
655 secfile = secfile_load(sfilename, FALSE);
656
657 if (secfile == nullptr) {
658 ruleset_error(nullptr, LOG_ERROR, "Could not load luadata '%s':\n%s",
660 }
661
662 return secfile;
663}
664
665/**********************************************************************/
670 const char *sec,
671 const char *sub,
672 const char *rfor)
673{
674 const char *type, *name;
675 int j;
676 const char *filename;
677
678 filename = secfile_name(file);
679
681
682 for (j = 0; (type = secfile_lookup_str_default(file, nullptr, "%s.%s%d.type",
683 sec, sub, j)); j++) {
684 char buf[MAX_LEN_NAME];
685 const char *range;
686 bool survives, present, quiet;
687 struct entry *pentry;
688 struct requirement req;
689
690 if (!(pentry = secfile_entry_lookup(file, "%s.%s%d.name",
691 sec, sub, j))) {
692 ruleset_error(nullptr, LOG_ERROR, "%s", secfile_error());
693
694 return nullptr;
695 }
696 name = nullptr;
697 switch (entry_type_get(pentry)) {
698 case ENTRY_BOOL:
699 {
700 bool val;
701
702 if (entry_bool_get(pentry, &val)) {
703 fc_snprintf(buf, sizeof(buf), "%d", val);
704 name = buf;
705 }
706 }
707 break;
708 case ENTRY_INT:
709 {
710 int val;
711
712 if (entry_int_get(pentry, &val)) {
713 fc_snprintf(buf, sizeof(buf), "%d", val);
714 name = buf;
715 }
716 }
717 break;
718 case ENTRY_STR:
720 break;
721 case ENTRY_FLOAT:
723 ruleset_error(nullptr, LOG_ERROR,
724 "\"%s\": trying to have an floating point entry as a requirement name in '%s.%s%d'.",
725 filename, sec, sub, j);
726 break;
729 break;
732 break;
733 case ENTRY_ILLEGAL:
735 break;
736 }
737 if (name == nullptr) {
738 ruleset_error(nullptr, LOG_ERROR,
739 "\"%s\": error in handling requirement name for '%s.%s%d'.",
740 filename, sec, sub, j);
741 return nullptr;
742 }
743
744 if (!(range = secfile_lookup_str(file, "%s.%s%d.range", sec, sub, j))) {
745 ruleset_error(nullptr, LOG_ERROR, "%s", secfile_error());
746
747 return nullptr;
748 }
749
750 survives = FALSE;
751 if ((pentry = secfile_entry_lookup(file, "%s.%s%d.survives",
752 sec, sub, j))
754 ruleset_error(nullptr, LOG_ERROR,
755 "\"%s\": invalid boolean value for survives for "
756 "'%s.%s%d'.", filename, sec, sub, j);
757 }
758
759 present = TRUE;
760 if ((pentry = secfile_entry_lookup(file, "%s.%s%d.present",
761 sec, sub, j))
763 ruleset_error(nullptr, LOG_ERROR,
764 "\"%s\": invalid boolean value for present for "
765 "'%s.%s%d'.", filename, sec, sub, j);
766 }
767 quiet = FALSE;
768 if ((pentry = secfile_entry_lookup(file, "%s.%s%d.quiet",
769 sec, sub, j))
770 && !entry_bool_get(pentry, &quiet)) {
771 ruleset_error(nullptr, LOG_ERROR,
772 "\"%s\": invalid boolean value for quiet for "
773 "'%s.%s%d'.", filename, sec, sub, j);
774 }
775
777 if (req.source.kind == universals_n_invalid()) {
778 ruleset_error(nullptr, LOG_ERROR,
779 "\"%s\" [%s] has invalid or unknown req: "
780 "\"%s\" \"%s\".",
781 filename, sec, type, name);
782
783 return nullptr;
784 }
785
787 }
788
789 return &reqs_list;
790}
791
792/**********************************************************************/
796 struct section_file *file,
797 const char *sec,
798 const char *sub)
799{
800 const char *flag;
801 int j;
802 const char *filename;
803 bool success = TRUE;
804
805 filename = secfile_name(file);
806
807 for (j = 0; (flag = secfile_lookup_str_default(file, nullptr, "%s.%s%d.flag",
808 sec, sub, j)); j++) {
809 struct combat_bonus *bonus = fc_malloc(sizeof(*bonus));
810 const char *type;
811
813 if (!unit_type_flag_id_is_valid(bonus->flag)) {
814 log_error("\"%s\": unknown flag name \"%s\" in '%s.%s'.",
815 filename, flag, sec, sub);
816 FC_FREE(bonus);
817 success = FALSE;
818 continue;
819 }
820 type = secfile_lookup_str(file, "%s.%s%d.type", sec, sub, j);
822 if (!combat_bonus_type_is_valid(bonus->type)) {
823 log_error("\"%s\": unknown bonus type \"%s\" in '%s.%s'.",
824 filename, type, sec, sub);
825 FC_FREE(bonus);
826 success = FALSE;
827 continue;
828 }
829 if (!secfile_lookup_int(file, &bonus->value, "%s.%s%d.value",
830 sec, sub, j)) {
831 log_error("\"%s\": failed to get value from '%s.%s%d'.",
832 filename, sec, sub, j);
833 FC_FREE(bonus);
834 success = FALSE;
835 continue;
836 }
838 "%s.%s%d.quiet",
839 sec, sub, j);
841 }
842
843 return success;
844}
845
846/**********************************************************************/
854static bool lookup_tech(struct section_file *file,
855 struct advance **result,
856 const char *prefix, const char *entry,
857 const char *filename,
858 const char *description)
859{
860 const char *sval;
861
862 sval = secfile_lookup_str_default(file, nullptr, "%s.%s", prefix, entry);
863 if (!sval || !strcmp(sval, "Never")) {
864 *result = A_NEVER;
865 } else {
866 *result = advance_by_rule_name(sval);
867
868 if (A_NEVER == *result) {
869 ruleset_error(nullptr, LOG_ERROR,
870 "\"%s\" %s %s: couldn't match \"%s\".",
871 filename, (description ? description : prefix), entry, sval);
872 return FALSE;
873 }
874 }
875
876 return TRUE;
877}
878
879/**********************************************************************/
886static bool lookup_unit_list(struct section_file *file, const char *prefix,
887 const char *entry,
888 struct unit_type **output,
889 const char *filename)
890{
891 const char **slist;
892 size_t nval;
893 int i;
894 bool ok = TRUE;
895
896 /* Pre-fill with nullptr: */
897 for (i = 0; i < MAX_NUM_UNIT_LIST; i++) {
898 output[i] = nullptr;
899 }
900 slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
901 if (nval == 0) {
902 /* 'No vector' is considered same as empty vector */
903 if (slist != nullptr) {
904 free(slist);
905 }
906 return TRUE;
907 }
908 if (nval > MAX_NUM_UNIT_LIST) {
909 ruleset_error(nullptr, LOG_ERROR,
910 "\"%s\": string vector %s.%s too long (%d, max %d)",
911 filename, prefix, entry, (int) nval, MAX_NUM_UNIT_LIST);
912 ok = FALSE;
913 } else if (nval == 1 && strcmp(slist[0], "") == 0) {
914 free(slist);
915 return TRUE;
916 }
917 if (ok) {
918 for (i = 0; i < nval; i++) {
919 const char *sval = slist[i];
921
922 if (!punittype) {
923 ruleset_error(nullptr, LOG_ERROR,
924 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
925 filename, prefix, entry, i, sval);
926 ok = FALSE;
927 break;
928 }
929 output[i] = punittype;
930 log_debug("\"%s\" %s.%s (%d): %s (%d)", filename, prefix, entry, i, sval,
932 }
933 }
934 free(slist);
935
936 return ok;
937}
938
939/**********************************************************************/
946static bool lookup_tech_list(struct section_file *file, const char *prefix,
947 const char *entry, int *output,
948 const char *filename)
949{
950 const char **slist;
951 size_t nval;
952 int i;
953 bool ok = TRUE;
954
955 /* pre-fill with A_LAST: */
956 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
957 output[i] = A_LAST;
958 }
959 slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
960 if (slist == nullptr || nval == 0) {
961 return TRUE;
962 } else if (nval > MAX_NUM_TECH_LIST) {
963 ruleset_error(nullptr, LOG_ERROR,
964 "\"%s\": string vector %s.%s too long (%d, max %d)",
965 filename, prefix, entry, (int) nval, MAX_NUM_TECH_LIST);
966 ok = FALSE;
967 }
968
969 if (ok) {
970 if (nval == 1 && strcmp(slist[0], "") == 0) {
971 FC_FREE(slist);
972 return TRUE;
973 }
974 for (i = 0; i < nval && ok; i++) {
975 const char *sval = slist[i];
977
978 if (padvance == nullptr) {
979 ruleset_error(nullptr, LOG_ERROR,
980 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
981 filename, prefix, entry, i, sval);
982 ok = FALSE;
983 }
984 if (!valid_advance(padvance)) {
985 ruleset_error(nullptr, LOG_ERROR,
986 "\"%s\" %s.%s (%d): \"%s\" is removed.",
987 filename, prefix, entry, i, sval);
988 ok = FALSE;
989 }
990
991 if (ok) {
992 output[i] = advance_number(padvance);
993 log_debug("\"%s\" %s.%s (%d): %s (%d)", filename, prefix, entry, i, sval,
995 }
996 }
997 }
998 FC_FREE(slist);
999
1000 return ok;
1001}
1002
1003/**********************************************************************/
1010static bool lookup_building_list(struct section_file *file,
1011 const char *prefix, const char *entry,
1012 int *output, const char *filename)
1013{
1014 const char **slist;
1015 size_t nval;
1016 int i;
1017 bool ok = TRUE;
1018
1019 /* pre-fill with B_LAST: */
1020 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
1021 output[i] = B_LAST;
1022 }
1023 slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
1025 ruleset_error(nullptr, LOG_ERROR,
1026 "\"%s\": string vector %s.%s too long (%d, max %d)",
1027 filename, prefix, entry, (int) nval, MAX_NUM_BUILDING_LIST);
1028 ok = FALSE;
1029 } else if (nval == 0 || (nval == 1 && strcmp(slist[0], "") == 0)) {
1030 if (slist != nullptr) {
1031 FC_FREE(slist);
1032 }
1033 return TRUE;
1034 }
1035 if (ok) {
1036 for (i = 0; i < nval; i++) {
1037 const char *sval = slist[i];
1038 struct impr_type *pimprove = improvement_by_rule_name(sval);
1039
1040 if (pimprove == nullptr) {
1041 ruleset_error(nullptr, LOG_ERROR,
1042 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
1043 filename, prefix, entry, i, sval);
1044 ok = FALSE;
1045 break;
1046 }
1047 output[i] = improvement_number(pimprove);
1048 log_debug("%s.%s,%d %s %d", prefix, entry, i, sval, output[i]);
1049 }
1050 }
1051 free(slist);
1052
1053 return ok;
1054}
1055
1056/**********************************************************************/
1062static bool lookup_unit_type(struct section_file *file,
1063 const char *prefix,
1064 const char *entry,
1065 const struct unit_type **result,
1066 const char *filename,
1067 const char *description)
1068{
1069 const char *sval;
1070
1071 sval = secfile_lookup_str_default(file, "None", "%s.%s", prefix, entry);
1072
1073 if (strcmp(sval, "None") == 0) {
1074 *result = nullptr;
1075 } else {
1076 *result = unit_type_by_rule_name(sval);
1077 if (*result == nullptr) {
1078 ruleset_error(nullptr, LOG_ERROR,
1079 "\"%s\" %s %s: couldn't match \"%s\".",
1080 filename, (description ? description : prefix), entry, sval);
1081
1082 return FALSE;
1083 }
1084 }
1085
1086 return TRUE;
1087}
1088
1089/**********************************************************************/
1093static struct government *lookup_government(struct section_file *file,
1094 const char *entry,
1095 const char *filename,
1096 struct government *fallback)
1097{
1098 const char *sval;
1099 struct government *gov;
1100
1101 sval = secfile_lookup_str_default(file, nullptr, "%s", entry);
1102 if (!sval) {
1103 gov = fallback;
1104 } else {
1106 }
1107 if (!gov) {
1108 ruleset_error(nullptr, LOG_ERROR,
1109 "\"%s\" %s: couldn't match \"%s\".",
1110 filename, entry, sval);
1111 }
1112 return gov;
1113}
1114
1115/**********************************************************************/
1118static char *lookup_string(struct section_file *file, const char *prefix,
1119 const char *suffix)
1120{
1121 const char *sval = secfile_lookup_str(file, "%s.%s", prefix, suffix);
1122
1123 if (sval != nullptr) {
1124 char copy[strlen(sval) + 1];
1125
1126 strcpy(copy, sval);
1128 if (strlen(copy) > 0) {
1129 return fc_strdup(copy);
1130 }
1131 }
1132
1133 return nullptr;
1134}
1135
1136/**********************************************************************/
1139static struct strvec *lookup_strvec(struct section_file *file,
1140 const char *prefix, const char *suffix)
1141{
1142 size_t dim;
1143 const char **vec = secfile_lookup_str_vec(file, &dim,
1144 "%s.%s", prefix, suffix);
1145
1146 if (vec != nullptr) {
1147 struct strvec *dest = strvec_new();
1148
1149 strvec_store(dest, vec, dim);
1150 free(vec);
1151 return dest;
1152 }
1153
1154 return nullptr;
1155}
1156
1157/**********************************************************************/
1160static struct extra_type *lookup_resource(const char *filename,
1161 const char *name,
1162 const char *jsection)
1163{
1164 struct extra_type *pres;
1165
1167
1168 if (pres == nullptr) {
1169 ruleset_error(nullptr, LOG_ERROR,
1170 "\"%s\" [%s] has unknown \"%s\".",
1171 filename, jsection, name);
1172 }
1173
1174 return pres;
1175}
1176
1177/**********************************************************************/
1181static bool lookup_terrain(struct section_file *file,
1182 const char *entry,
1183 const char *filename,
1184 struct terrain *pthis,
1185 struct terrain **result,
1186 bool null_acceptable)
1187{
1188 const int j = terrain_index(pthis);
1189 const char *jsection = &terrain_sections[j * MAX_SECTION_LABEL];
1190 const char *name = secfile_lookup_str(file, "%s.%s", jsection, entry);
1191 struct terrain *pterr;
1192
1193 if (name == nullptr && !null_acceptable) {
1194 return FALSE;
1195 }
1196
1197 if (name == nullptr
1198 || *name == '\0'
1199 || (0 == strcmp(name, "none"))
1200 || (0 == strcmp(name, "no"))) {
1201 *result = T_NONE;
1202
1203 return TRUE;
1204 }
1205 if (0 == strcmp(name, "yes")) {
1206 *result = pthis;
1207
1208 return TRUE;
1209 }
1210
1212 *result = pterr;
1213
1214 if (pterr == nullptr) {
1215 ruleset_error(nullptr, LOG_ERROR,
1216 "\"%s\" [%s] has unknown \"%s\".",
1217 secfile_name(file), jsection, name);
1218 return FALSE;
1219 }
1220
1221 return TRUE;
1222}
1223
1224/**********************************************************************/
1231static bool lookup_time(const struct section_file *secfile, int *turns,
1232 const char *sec_name, const char *property_name,
1233 const char *filename, const char *item_name,
1234 bool *ok)
1235{
1236 /* Assumes that PACKET_UNIT_INFO.activity_count in packets.def is UINT16 */
1237 const int max_turns = 65535 / ACTIVITY_FACTOR;
1238
1239 if (!secfile_lookup_int(secfile, turns, "%s.%s", sec_name, property_name)) {
1240 return FALSE;
1241 }
1242
1243 if (*turns > max_turns) {
1244 ruleset_error(nullptr, LOG_ERROR,
1245 "\"%s\": \"%s\": \"%s\" value %d too large (max %d)",
1246 filename, item_name ? item_name : sec_name,
1247 property_name, *turns, max_turns);
1248 *ok = FALSE;
1249 }
1250
1251 return TRUE; /* We found _something */
1252}
1253
1254/**********************************************************************/
1258 const char *domain,
1259 struct section_file *file,
1260 const char *sec_name)
1261{
1262 const char *name = secfile_lookup_str(file, "%s.name", sec_name);
1263 const char *rule_name = secfile_lookup_str(file, "%s.rule_name", sec_name);
1264
1265 if (!name) {
1266 ruleset_error(nullptr, LOG_ERROR,
1267 "\"%s\" [%s]: no \"name\" specified.",
1268 secfile_name(file), sec_name);
1269 return FALSE;
1270 }
1271
1272 names_set(pname, domain, name, rule_name);
1273
1274 return TRUE;
1275}
1276
1277/**********************************************************************/
1281 struct section_file *file,
1282 const char *secname, const char *field_prefix)
1283{
1284 enum trait tr;
1285
1286 /* FIXME: Use specenum trait names without duplicating them here.
1287 * Just needs to take care of case.
1288 * This list is also duplicated in rulesave.c:save_traits() */
1289 const char *trait_names[] = {
1290 "expansionist",
1291 "trader",
1292 "aggressive",
1293 "builder",
1294 nullptr
1295 };
1296
1297 for (tr = trait_begin();
1298 tr != trait_end() && trait_names[tr] != nullptr;
1299 tr = trait_next(tr)) {
1300 out[tr].min = secfile_lookup_int_default(file, -1, "%s.%s%s_min",
1301 secname,
1303 trait_names[tr]);
1304 out[tr].max = secfile_lookup_int_default(file, -1, "%s.%s%s_max",
1305 secname,
1307 trait_names[tr]);
1308 out[tr].fixed = secfile_lookup_int_default(file, -1, "%s.%s%s_default",
1309 secname,
1311 trait_names[tr]);
1312 }
1313
1314 fc_assert(tr == trait_end()); /* number of trait_names correct */
1315}
1316
1317/**********************************************************************/
1321static bool load_game_names(struct section_file *file,
1322 struct rscompat_info *compat)
1323{
1324 struct section_list *sec;
1325 int nval;
1326 const char *filename = secfile_name(file);
1327 bool ok = TRUE;
1328
1329 /* Section: datafile */
1331 if (compat->version <= 0) {
1332 return FALSE;
1333 }
1334
1335 secfile_entry_ignore_by_path(file, "datafile.description"); /* Unused */
1336 secfile_entry_ignore_by_path(file, "datafile.ruledit"); /* Unused */
1337
1339 nval = (sec != nullptr ? section_list_size(sec) : 0);
1341 int num = nval; /* No "size_t" to printf */
1342
1343 ruleset_error(nullptr, LOG_ERROR,
1344 "\"%s\": Too many achievement types (%d, max %d)",
1345 filename, num, MAX_ACHIEVEMENT_TYPES);
1346 ok = FALSE;
1347 } else {
1349 }
1350
1351 if (ok) {
1354
1355 if (!ruleset_load_names(&pach->name, nullptr, file, sec_name)) {
1356 ruleset_error(nullptr, LOG_ERROR,
1357 "\"%s\": Cannot load achievement names",
1358 filename);
1359 ok = FALSE;
1360 break;
1361 }
1363 }
1364
1366
1367 if (ok) {
1369
1370 nval = (sec != nullptr ? section_list_size(sec) : 0);
1371 if (nval > MAX_GOODS_TYPES) {
1372 int num = nval; /* No "size_t" to printf */
1373
1374 ruleset_error(nullptr, LOG_ERROR,
1375 "\"%s\": Too many goods types (%d, max %d)",
1376 filename, num, MAX_GOODS_TYPES);
1378 ok = FALSE;
1379 } else if (nval < 1) {
1380 ruleset_error(nullptr, LOG_ERROR,
1381 "\"%s\": At least one goods type needed",
1382 filename);
1384 ok = FALSE;
1385 } else {
1387 }
1388
1389 if (ok) {
1391 const char *sec_name
1393
1394 if (!ruleset_load_names(&pgood->name, nullptr, file, sec_name)) {
1395 ruleset_error(nullptr, LOG_ERROR,
1396 "\"%s\": Cannot load goods names",
1397 filename);
1398 ok = FALSE;
1399 break;
1400 }
1402 }
1404 }
1405
1406 if (ok) {
1407
1409
1410 nval = (sec != nullptr ? section_list_size(sec) : 0);
1411 if (nval > MAX_COUNTERS) {
1412 size_t num = nval;
1413
1414 ruleset_error(nullptr, LOG_ERROR,
1415 "\"%s\": Too many counters (" SIZE_T_PRINTF ", max %d)",
1416 filename, num, MAX_COUNTERS);
1417 ok = FALSE;
1418 }
1419
1420 if (ok) {
1421 int count_idx;
1422
1424
1425 for (count_idx = 0; count_idx < nval; count_idx++) {
1426
1428 const char *sec_name
1430
1431 if (!ruleset_load_names(&pcount->name, nullptr, file, sec_name)) {
1432 ruleset_error(nullptr, LOG_ERROR,
1433 "\"%s\": Cannot load counters names",
1434 filename);
1435 ok = FALSE;
1436 break;
1437 }
1438 }
1439 }
1440
1442 }
1443
1444 return ok;
1445}
1446
1447/**********************************************************************/
1451static bool load_action_names(struct section_file *file,
1452 struct rscompat_info *compat)
1453{
1454 const char *filename = secfile_name(file);
1455 bool ok = TRUE;
1456
1457 if (!rscompat_check_cap_and_version(file, filename, compat)) {
1458 return FALSE;
1459 }
1460
1461 secfile_entry_ignore_by_path(file, "datafile.description"); /* Unused */
1462 secfile_entry_ignore_by_path(file, "datafile.ruledit"); /* Unused */
1463
1464 return ok;
1465}
1466
1467/**********************************************************************/
1471static bool load_tech_names(struct section_file *file,
1472 struct rscompat_info *compat)
1473{
1474 struct section_list *sec = nullptr;
1475 /* Number of techs in the ruleset (means without A_NONE). */
1476 int num_techs = 0;
1477 int i;
1478 const char *filename = secfile_name(file);
1479 bool ok = TRUE;
1480 const char *flag;
1481
1482 if (!rscompat_check_cap_and_version(file, filename, compat)) {
1483 return FALSE;
1484 }
1485
1486 secfile_entry_ignore_by_path(file, "datafile.description"); /* Unused */
1487 secfile_entry_ignore_by_path(file, "datafile.ruledit"); /* Unused */
1488
1489 /* User tech flag names */
1490 for (i = 0;
1491 (flag = secfile_lookup_str_default(file, nullptr, "control.flags%d.name", i)) ;
1492 i++) {
1493 const char *helptxt
1494 = secfile_lookup_str_default(file, nullptr, "control.flags%d.helptxt",
1495 i);
1497 ruleset_error(nullptr, LOG_ERROR,
1498 "\"%s\": Duplicate tech flag name '%s'",
1499 filename, flag);
1500 ok = FALSE;
1501 break;
1502 }
1503 if (i > MAX_NUM_USER_TECH_FLAGS) {
1504 ruleset_error(nullptr, LOG_ERROR,
1505 "\"%s\": Too many user tech flags!",
1506 filename);
1507 ok = FALSE;
1508 break;
1509 }
1510
1511 set_user_tech_flag_name(TECH_USER_1 + i, flag, helptxt);
1512 }
1513
1514 if (ok) {
1515 size_t nval;
1516
1517 for (; i < MAX_NUM_USER_TECH_FLAGS; i++) {
1518 set_user_tech_flag_name(TECH_USER_1 + i, nullptr, nullptr);
1519 }
1520
1521 /* Tech classes */
1523
1524 nval = (sec != nullptr ? section_list_size(sec) : 0);
1525 if (nval > MAX_NUM_TECH_CLASSES) {
1526 int num = nval; /* No "size_t" to printf */
1527
1528 ruleset_error(nullptr, LOG_ERROR,
1529 "\"%s\": Too many tech classes (%d, max %d)",
1530 filename, num, MAX_NUM_TECH_CLASSES);
1532 ok = FALSE;
1533 } else {
1535 }
1536
1537 if (ok) {
1539 const char *sec_name
1541
1542 if (!ruleset_load_names(&ptclass->name, nullptr, file, sec_name)) {
1543 ruleset_error(nullptr, LOG_ERROR,
1544 "\"%s\": Cannot load tech class names",
1545 filename);
1546 ok = FALSE;
1547 break;
1548 }
1550 }
1551 }
1552
1553 if (ok) {
1554 /* The techs: */
1556 if (sec == nullptr || 0 == (num_techs = section_list_size(sec))) {
1557 ruleset_error(nullptr, LOG_ERROR,
1558 "\"%s\": No Advances?!?", filename);
1559 ok = FALSE;
1560 } else {
1561 log_verbose("%d advances (including possibly unused)", num_techs);
1562 if (num_techs + A_FIRST > A_LAST) {
1563 ruleset_error(nullptr, LOG_ERROR,
1564 "\"%s\": Too many advances (%d, max %d)",
1565 filename, num_techs, A_LAST - A_FIRST);
1566 ok = FALSE;
1567 }
1568 }
1569 }
1570
1571 if (ok) {
1572 game.control.num_tech_types = num_techs + A_FIRST; /* includes A_NONE */
1573
1574 i = 0;
1575 advance_iterate(adv) {
1576 if (!ruleset_load_names(&adv->name, nullptr, file,
1578 ok = FALSE;
1579 break;
1580 }
1581 i++;
1583 }
1585
1586 return ok;
1587}
1588
1589/**********************************************************************/
1592static bool load_ruleset_techs(struct section_file *file,
1593 struct rscompat_info *compat)
1594{
1595 struct section_list *sec;
1596 const char **slist;
1597 int i;
1598 size_t nval;
1600 const char *filename = secfile_name(file);
1601 bool ok = TRUE;
1602
1604
1605 i = 0;
1607 const char *sec_name = section_name(section_list_get(sec, i));
1608
1609 ptclass->cost_pct = secfile_lookup_int_default(file, 100, "%s.%s",
1610 sec_name, "cost_pct");
1611
1612 i++;
1614
1616
1617 i = 0;
1618 advance_iterate(a) {
1619 const char *sec_name = section_name(section_list_get(sec, i));
1620 const char *sval;
1621 int j, ival;
1622 struct requirement_vector *research_reqs;
1623
1624 if (!lookup_tech(file, &a->require[AR_ONE], sec_name, "req1",
1625 filename, rule_name_get(&a->name))
1626 || !lookup_tech(file, &a->require[AR_TWO], sec_name, "req2",
1627 filename, rule_name_get(&a->name))
1628 || !lookup_tech(file, &a->require[AR_ROOT], sec_name, "root_req",
1629 filename, rule_name_get(&a->name))) {
1630 ok = FALSE;
1631 break;
1632 }
1633
1634 if ((A_NEVER == a->require[AR_ONE] && A_NEVER != a->require[AR_TWO])
1635 || (A_NEVER != a->require[AR_ONE] && A_NEVER == a->require[AR_TWO])) {
1636 ruleset_error(nullptr, LOG_ERROR,
1637 "\"%s\" [%s] \"%s\": \"Never\" with non-\"Never\".",
1638 filename, sec_name, rule_name_get(&a->name));
1639 ok = FALSE;
1640 break;
1641 }
1642 if (a_none == a->require[AR_ONE] && a_none != a->require[AR_TWO]) {
1643 ruleset_error(nullptr, LOG_ERROR,
1644 "\"%s\" [%s] \"%s\": should have \"None\" second.",
1645 filename, sec_name, rule_name_get(&a->name));
1646 ok = FALSE;
1647 break;
1648 }
1649
1650 if (game.control.num_tech_classes == 0) {
1651 a->tclass = nullptr;
1652 } else {
1653 const char *classname;
1654
1655 classname = lookup_string(file, sec_name, "class");
1656 if (classname != nullptr) {
1659 if (a->tclass == nullptr) {
1660 ruleset_error(nullptr, LOG_ERROR,
1661 "\"%s\" [%s] \"%s\": Unknown tech class \"%s\".",
1662 filename, sec_name, rule_name_get(&a->name), classname);
1663 ok = FALSE;
1664 break;
1665 }
1666 } else {
1667 a->tclass = nullptr; /* Default */
1668 }
1669 }
1670
1671 research_reqs = lookup_req_list(file, sec_name, "research_reqs",
1672 rule_name_get(&a->name));
1673 if (research_reqs == nullptr) {
1674 ok = FALSE;
1675 break;
1676 }
1677
1678 requirement_vector_copy(&a->research_reqs, research_reqs);
1679
1680 BV_CLR_ALL(a->flags);
1681
1682 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name);
1683 for (j = 0; j < nval; j++) {
1684 sval = slist[j];
1685 if (strcmp(sval, "") == 0) {
1686 continue;
1687 }
1690 ruleset_error(nullptr, LOG_ERROR,
1691 "\"%s\" [%s] \"%s\": bad flag name \"%s\".",
1692 filename, sec_name, rule_name_get(&a->name), sval);
1693 ok = FALSE;
1694 break;
1695 } else {
1696 BV_SET(a->flags, ival);
1697 }
1698 }
1699 free(slist);
1700
1701 if (!ok) {
1702 break;
1703 }
1704
1705 sz_strlcpy(a->graphic_str,
1706 secfile_lookup_str_default(file, "-", "%s.graphic", sec_name));
1707 sz_strlcpy(a->graphic_alt,
1709 "%s.graphic_alt", sec_name));
1710
1711 a->helptext = lookup_strvec(file, sec_name, "helptext");
1712 a->bonus_message = lookup_string(file, sec_name, "bonus_message");
1713 a->cost = secfile_lookup_int_default(file, -1, "%s.%s",
1714 sec_name, "cost");
1715 a->num_reqs = 0;
1716
1717 i++;
1719
1720 /* Propagate a root tech up into the tech tree. If a technology
1721 * X has Y has a root tech, then any technology requiring X (in the
1722 * normal way or as a root tech) also has Y as a root tech.
1723 * Later techs may gain a whole set of root techs in this way. The one
1724 * we store in AR_ROOT is a more or less arbitrary one of these,
1725 * also signalling that the set is non-empty; after this, you'll still
1726 * have to walk the tech tree to find them all. */
1727restart:
1728
1729 if (ok) {
1730 advance_iterate(a) {
1731 if (valid_advance(a)
1732 && A_NEVER != a->require[AR_ROOT]) {
1733 bool out_of_order = FALSE;
1734
1735 /* Now find any tech depending on this technology and update its
1736 * root_req. */
1737 advance_iterate(b) {
1738 if (valid_advance(b)
1739 && A_NEVER == b->require[AR_ROOT]
1740 && (a == b->require[AR_ONE] || a == b->require[AR_TWO])) {
1741 b->require[AR_ROOT] = a->require[AR_ROOT];
1742 b->inherited_root_req = TRUE;
1743 if (b < a) {
1745 }
1746 }
1748
1749 if (out_of_order) {
1750 /* HACK: If we just changed the root_tech of a lower-numbered
1751 * technology, we need to go back so that we can propagate the
1752 * root_tech up to that technology's parents... */
1753 goto restart;
1754 }
1755 }
1757
1758 /* Now rename A_NEVER to A_NONE for consistency */
1760 if (A_NEVER == a->require[AR_ROOT]) {
1761 a->require[AR_ROOT] = a_none;
1762 }
1764
1765 /* Some more consistency checking:
1766 Non-removed techs depending on removed techs is too
1767 broken to fix by default, so die.
1768 */
1769 advance_iterate(a) {
1770 if (valid_advance(a)) {
1771 /* We check for recursive tech loops later,
1772 * in build_required_techs_helper. */
1773 if (!valid_advance(a->require[AR_ONE])) {
1774 ruleset_error(nullptr, LOG_ERROR,
1775 "\"%s\" tech \"%s\": req1 leads to removed tech.",
1776 filename, advance_rule_name(a));
1777 ok = FALSE;
1778 break;
1779 }
1780 if (!valid_advance(a->require[AR_TWO])) {
1781 ruleset_error(nullptr, LOG_ERROR,
1782 "\"%s\" tech \"%s\": req2 leads to removed tech.",
1783 filename, advance_rule_name(a));
1784 ok = FALSE;
1785 break;
1786 }
1787 }
1789 }
1790
1792 if (ok) {
1794 }
1795
1796 return ok;
1797}
1798
1799/**********************************************************************/
1803static bool load_unit_names(struct section_file *file,
1804 struct rscompat_info *compat)
1805{
1806 struct section_list *sec = nullptr;
1807 int nval = 0;
1808 int i;
1809 const char *filename = secfile_name(file);
1810 const char *flag;
1811 bool ok = TRUE;
1812
1813 if (!rscompat_check_cap_and_version(file, filename, compat)) {
1814 return FALSE;
1815 }
1816
1817 secfile_entry_ignore_by_path(file, "datafile.description"); /* Unused */
1818 secfile_entry_ignore_by_path(file, "datafile.ruledit"); /* Unused */
1819
1820 /* User unit flag names */
1821 for (i = 0;
1822 (flag = secfile_lookup_str_default(file, nullptr, "control.flags%d.name", i)) ;
1823 i++) {
1824 const char *helptxt
1825 = secfile_lookup_str_default(file, nullptr, "control.flags%d.helptxt",
1826 i);
1827
1830 ruleset_error(nullptr, LOG_ERROR,
1831 "\"%s\": Duplicate unit flag name '%s'",
1832 filename, flag);
1833 ok = FALSE;
1834 break;
1835 }
1836 if (i > MAX_NUM_USER_UNIT_FLAGS) {
1837 ruleset_error(nullptr, LOG_ERROR,
1838 "\"%s\": Too many user unit type flags!",
1839 filename);
1840 ok = FALSE;
1841 break;
1842 }
1843
1845 }
1846
1847 if (ok) {
1848 /* Blank the remaining unit type user flags. */
1849 for (; i < MAX_NUM_USER_UNIT_FLAGS; i++) {
1850 set_user_unit_type_flag_name(UTYF_USER_FLAG_1 + i, nullptr, nullptr);
1851 }
1852 }
1853
1854 if (ok) {
1855 /* User unit class flag names */
1856 for (i = 0;
1857 (flag = secfile_lookup_str_default(file, nullptr,
1858 "control.class_flags%d.name",
1859 i));
1860 i++) {
1861 const char *helptxt = secfile_lookup_str_default(file, nullptr,
1862 "control.class_flags%d.helptxt", i);
1863
1866 ruleset_error(nullptr, LOG_ERROR,
1867 "\"%s\": Duplicate unit class flag name '%s'",
1868 filename, flag);
1869 ok = FALSE;
1870 break;
1871 }
1873 ruleset_error(nullptr, LOG_ERROR,
1874 "\"%s\": Too many user unit class flags!",
1875 filename);
1876 ok = FALSE;
1877 break;
1878 }
1879
1881 }
1882 }
1883
1884 if (ok) {
1885 /* Blank the remaining unit class user flags. */
1886 for (; i < MAX_NUM_USER_UCLASS_FLAGS; i++) {
1887 set_user_unit_class_flag_name(UCF_USER_FLAG_1 + i, nullptr, nullptr);
1888 }
1889 }
1890
1891 if (ok) {
1892 /* Unit classes */
1894 if (sec == nullptr || 0 == (nval = section_list_size(sec))) {
1895 ruleset_error(nullptr, LOG_ERROR,
1896 "\"%s\": No unit classes?!?", filename);
1897 ok = FALSE;
1898 } else {
1899 log_verbose("%d unit classes", nval);
1900 if (nval > UCL_LAST) {
1901 ruleset_error(nullptr, LOG_ERROR,
1902 "\"%s\": Too many unit classes (%d, max %d)",
1903 filename, nval, UCL_LAST);
1904 ok = FALSE;
1905 }
1906 }
1907 }
1908
1909 if (ok) {
1911
1913 const int pci = uclass_index(punitclass);
1914
1915 if (!ruleset_load_names(&punitclass->name, nullptr, file,
1917 ok = FALSE;
1918 break;
1919 }
1921 }
1923 sec = nullptr;
1924
1925 /* The names: */
1926 if (ok) {
1928 if (sec == nullptr || 0 == (nval = section_list_size(sec))) {
1929 ruleset_error(nullptr, LOG_ERROR,
1930 "\"%s\": No unit types?!?", filename);
1931 ok = FALSE;
1932 } else {
1933 log_verbose("%d unit types (including possibly unused)", nval);
1934 if (nval > U_LAST) {
1935 ruleset_error(nullptr, LOG_ERROR,
1936 "\"%s\": Too many unit types (%d, max %d)",
1937 filename, nval, U_LAST);
1938 ok = FALSE;
1939 }
1940 }
1941 }
1942
1943 if (ok) {
1945
1947 const int utypei = utype_index(punittype);
1948
1949 if (!ruleset_load_names(&punittype->name, nullptr, file,
1951 ok = FALSE;
1952 break;
1953 }
1955 }
1957
1958 return ok;
1959}
1960
1961/**********************************************************************/
1964static bool load_ruleset_veteran(struct section_file *file,
1965 const char *path,
1966 struct veteran_system **vsystem, char *err,
1967 size_t err_len)
1968{
1969 const char **vlist_name;
1972 int i;
1973 bool ret = TRUE;
1974
1975 /* The pointer should be uninitialised. */
1976 if (*vsystem != nullptr) {
1977 fc_snprintf(err, err_len, "Veteran system is defined?!");
1978 return FALSE;
1979 }
1980
1981 /* Load data. */
1983 "%s.veteran_names", path);
1985 "%s.veteran_power_fact", path);
1987 "%s.veteran_base_raise_chance", path);
1989 "%s.veteran_work_raise_chance",
1990 path);
1992 "%s.veteran_move_bonus", path);
1993
1994 if (count_name > MAX_VET_LEVELS) {
1995 ret = FALSE;
1996 fc_snprintf(err, err_len, "\"%s\": Too many veteran levels (section "
1997 "'%s': %lu, max %d)", secfile_name(file), path,
1998 (long unsigned)count_name, MAX_VET_LEVELS);
1999 } else if (count_name != count_power
2002 || count_name != count_move) {
2003 ret = FALSE;
2004 fc_snprintf(err, err_len, "\"%s\": Different lengths for the veteran "
2005 "settings in section '%s'", secfile_name(file),
2006 path);
2007 } else if (count_name == 0) {
2008 /* Nothing defined. */
2009 *vsystem = nullptr;
2010 } else {
2011 /* Generate the veteran system. */
2013
2014#define rs_sanity_veteran(_path, _entry, _i, _condition, _action) \
2015 if (_condition) { \
2016 log_error("Invalid veteran definition '%s.%s[%d]'!", \
2017 _path, _entry, _i); \
2018 log_debug("Failed check: '%s'. Update value: '%s'.", \
2019 #_condition, #_action); \
2020 _action; \
2021 }
2022 for (i = 0; i < count_name; i++) {
2023 /* Some sanity checks. */
2024 rs_sanity_veteran(path, "veteran_power_fact", i,
2025 (vlist_power[i] < 0), vlist_power[i] = 0);
2026 rs_sanity_veteran(path, "veteran_base_raise_chance", i,
2027 (vlist_raise[i] < 0), vlist_raise[i] = 0);
2028 rs_sanity_veteran(path, "veteran_work_raise_chance", i,
2029 (vlist_wraise[i] < 0), vlist_wraise[i] = 0);
2030 rs_sanity_veteran(path, "veteran_move_bonus", i,
2031 (vlist_move[i] < 0), vlist_move[i] = 0);
2032 if (i == 0) {
2033 /* First element.*/
2034 rs_sanity_veteran(path, "veteran_power_fact", i,
2035 (vlist_power[i] != 100), vlist_power[i] = 100);
2036 } else if (i == count_name - 1) {
2037 /* Last element. */
2038 rs_sanity_veteran(path, "veteran_power_fact", i,
2039 (vlist_power[i] < vlist_power[i - 1]),
2040 vlist_power[i] = vlist_power[i - 1]);
2041 rs_sanity_veteran(path, "veteran_base_raise_chance", i,
2042 (vlist_raise[i] != 0), vlist_raise[i] = 0);
2043 rs_sanity_veteran(path, "veteran_work_raise_chance", i,
2044 (vlist_wraise[i] != 0), vlist_wraise[i] = 0);
2045 } else {
2046 /* All elements in between. */
2047 rs_sanity_veteran(path, "veteran_power_fact", i,
2048 (vlist_power[i] < vlist_power[i - 1]),
2049 vlist_power[i] = vlist_power[i - 1]);
2050 rs_sanity_veteran(path, "veteran_base_raise_chance", i,
2051 (vlist_raise[i] > 100), vlist_raise[i] = 100);
2052 rs_sanity_veteran(path, "veteran_work_raise_chance", i,
2053 (vlist_wraise[i] > 100), vlist_wraise[i] = 100);
2054 }
2055
2058 vlist_wraise[i]);
2059 }
2060#undef rs_sanity_veteran
2061 }
2062
2063 if (vlist_name) {
2065 }
2066 if (vlist_power) {
2068 }
2069 if (vlist_raise) {
2071 }
2072 if (vlist_wraise) {
2074 }
2075 if (vlist_move) {
2077 }
2078
2079 return ret;
2080}
2081
2082/**********************************************************************/
2085static bool load_ruleset_units(struct section_file *file,
2086 struct rscompat_info *compat)
2087{
2088 int j, ival;
2089 size_t nval;
2090 struct section_list *sec, *csec;
2091 const char *sval, **slist;
2092 const char *filename = secfile_name(file);
2093 char msg[MAX_LEN_MSG];
2094 bool ok = TRUE;
2095
2096 if (!load_ruleset_veteran(file, "veteran_system", &game.veteran, msg,
2097 sizeof(msg))
2098 || game.veteran == nullptr) {
2099 ruleset_error(nullptr, LOG_ERROR,
2100 "Error loading the default veteran system: %s",
2101 msg);
2102 ok = FALSE;
2103 }
2104
2106 nval = (sec != nullptr ? section_list_size(sec) : 0);
2107
2109 nval = (csec != nullptr ? section_list_size(csec) : 0);
2110
2111 if (ok) {
2113 int i = uclass_index(uc);
2114 const char *sec_name = section_name(section_list_get(csec, i));
2115
2116 if (secfile_lookup_int(file, &uc->min_speed, "%s.min_speed", sec_name)) {
2117 uc->min_speed *= SINGLE_MOVE;
2118 } else {
2119 ruleset_error(nullptr, LOG_ERROR, "%s", secfile_error());
2120 ok = FALSE;
2121 break;
2122 }
2123 if (!secfile_lookup_int(file, &uc->hp_loss_pct,
2124 "%s.hp_loss_pct", sec_name)) {
2125 ruleset_error(nullptr, LOG_ERROR, "%s", secfile_error());
2126 ok = FALSE;
2127 break;
2128 }
2129
2130 uc->non_native_def_pct = secfile_lookup_int_default(file, 100,
2131 "%s.non_native_def_pct",
2132 sec_name);
2133
2134 BV_CLR_ALL(uc->flags);
2135 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name);
2136 for (j = 0; j < nval; j++) {
2137 sval = slist[j];
2138 if (strcmp(sval, "") == 0) {
2139 continue;
2140 }
2141
2144 ok = FALSE;
2147 ruleset_error(nullptr, LOG_ERROR,
2148 "\"%s\" unit_class \"%s\": unit_type flag \"%s\"!",
2149 filename, uclass_rule_name(uc), sval);
2150 } else {
2151 ruleset_error(nullptr, LOG_ERROR,
2152 "\"%s\" unit_class \"%s\": bad flag name \"%s\".",
2153 filename, uclass_rule_name(uc), sval);
2154 }
2155 break;
2156 } else {
2157 BV_SET(uc->flags, ival);
2158 }
2159 }
2160 free(slist);
2161
2162 uc->helptext = lookup_strvec(file, sec_name, "helptext");
2163
2164 if (!ok) {
2165 break;
2166 }
2168 }
2169
2170 if (ok) {
2171 /* Tech and Gov requirements; per unit veteran system */
2173 const int i = utype_index(u);
2174 const struct section *psection = section_list_get(sec, i);
2175 const char *sec_name = section_name(psection);
2176 struct requirement_vector *reqs;
2177
2178 reqs = lookup_req_list(file, sec_name, "reqs",
2179 utype_rule_name(u));
2180
2181 if (reqs == nullptr) {
2182 ok = FALSE;
2183 break;
2184 }
2185
2186 requirement_vector_copy(&u->build_reqs, reqs);
2187
2188 if (!load_ruleset_veteran(file, sec_name, &u->veteran,
2189 msg, sizeof(msg))) {
2190 ruleset_error(nullptr, LOG_ERROR,
2191 "Error loading the veteran system: %s",
2192 msg);
2193 ok = FALSE;
2194 break;
2195 }
2196
2197 if (!lookup_unit_type(file, sec_name, "obsolete_by",
2198 &u->obsoleted_by, filename,
2199 rule_name_get(&u->name))
2200 || !lookup_unit_type(file, sec_name, "convert_to",
2201 &u->converted_to, filename,
2202 rule_name_get(&u->name))) {
2203 ok = FALSE;
2204 break;
2205 }
2206 u->convert_time = 1; /* default */
2207 lookup_time(file, &u->convert_time, sec_name, "convert_time",
2208 filename, rule_name_get(&u->name), &ok);
2210 }
2211
2212 if (ok) {
2213 /* main stats: */
2215 const int i = utype_index(u);
2216 struct unit_class *pclass;
2217 const char *sec_name = section_name(section_list_get(sec, i));
2218 const char *str;
2219
2220 sval = secfile_lookup_str(file, "%s.class", sec_name);
2222 if (!pclass) {
2223 ruleset_error(nullptr, LOG_ERROR,
2224 "\"%s\" unit_type \"%s\": bad class \"%s\".",
2225 filename, utype_rule_name(u), sval);
2226 ok = FALSE;
2227 break;
2228 }
2229 u->uclass = pclass;
2230
2231 sz_strlcpy(u->sound_move,
2232 secfile_lookup_str_default(file, "-", "%s.sound_move",
2233 sec_name));
2234 sz_strlcpy(u->sound_move_alt,
2235 secfile_lookup_str_default(file, "-", "%s.sound_move_alt",
2236 sec_name));
2237 sz_strlcpy(u->sound_fight,
2238 secfile_lookup_str_default(file, "-", "%s.sound_fight",
2239 sec_name));
2240 sz_strlcpy(u->sound_fight_alt,
2241 secfile_lookup_str_default(file, "-", "%s.sound_fight_alt",
2242 sec_name));
2243
2244 if ((str = secfile_lookup_str(file, "%s.graphic", sec_name))) {
2245 sz_strlcpy(u->graphic_str, str);
2246 } else {
2247 ruleset_error(nullptr, LOG_ERROR, "%s", secfile_error());
2248 ok = FALSE;
2249 break;
2250 }
2251 sz_strlcpy(u->graphic_alt,
2252 secfile_lookup_str_default(file, "-", "%s.graphic_alt",
2253 sec_name));
2254 sz_strlcpy(u->graphic_alt2,
2255 secfile_lookup_str_default(file, "-", "%s.graphic_alt2",
2256 sec_name));
2257
2258 if (!secfile_lookup_int(file, &u->build_cost,
2259 "%s.build_cost", sec_name)
2260 || !secfile_lookup_int(file, &u->pop_cost,
2261 "%s.pop_cost", sec_name)
2262 || !secfile_lookup_int(file, &u->attack_strength,
2263 "%s.attack", sec_name)
2264 || !secfile_lookup_int(file, &u->defense_strength,
2265 "%s.defense", sec_name)
2266 || !secfile_lookup_int(file, &u->move_rate,
2267 "%s.move_rate", sec_name)
2268 || !secfile_lookup_int(file, &u->vision_radius_sq,
2269 "%s.vision_radius_sq", sec_name)
2270 || !secfile_lookup_int(file, &u->transport_capacity,
2271 "%s.transport_cap", sec_name)
2272 || !secfile_lookup_int(file, &u->firepower,
2273 "%s.firepower", sec_name)
2274 || !secfile_lookup_int(file, &u->fuel,
2275 "%s.fuel", sec_name)
2276 || !secfile_lookup_int(file, &u->happy_cost,
2277 "%s.uk_happy", sec_name)) {
2278 ruleset_error(nullptr, LOG_ERROR, "%s", secfile_error());
2279 ok = FALSE;
2280 break;
2281 }
2282 u->hp
2285 RS_MIN_HP,
2286 RS_MAX_HP,
2287 "%s.hitpoints", sec_name);
2288
2289 u->move_rate *= SINGLE_MOVE;
2290
2291 if (u->firepower <= 0) {
2292 ruleset_error(nullptr, LOG_ERROR,
2293 "\"%s\" unit_type \"%s\":"
2294 " firepower is %d,"
2295 " but must be at least 1. "
2296 " If you want no attack ability,"
2297 " set the unit's attack strength to 0.",
2298 filename, utype_rule_name(u), u->firepower);
2299 ok = FALSE;
2300 break;
2301 }
2302
2303 lookup_cbonus_list(u->bonuses, file, sec_name, "bonuses");
2304
2306 u->upkeep[o] = secfile_lookup_int_default(file, 0, "%s.uk_%s",
2307 sec_name,
2310
2311 slist = secfile_lookup_str_vec(file, &nval, "%s.cargo", sec_name);
2312
2313 BV_CLR_ALL(u->cargo);
2314 for (j = 0; j < nval; j++) {
2315 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
2316
2317 if (!uclass) {
2318 ruleset_error(nullptr, LOG_ERROR,
2319 "\"%s\" unit_type \"%s\":"
2320 "has unknown unit class %s as cargo.",
2321 filename, utype_rule_name(u), slist[j]);
2322 ok = FALSE;
2323 break;
2324 }
2325
2326 BV_SET(u->cargo, uclass_index(uclass));
2327 }
2328 free(slist);
2329
2330 if (!ok) {
2331 break;
2332 }
2333
2334 slist = secfile_lookup_str_vec(file, &nval, "%s.targets", sec_name);
2335 BV_CLR_ALL(u->targets);
2336 for (j = 0; j < nval; j++) {
2337 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
2338
2339 if (!uclass) {
2340 ruleset_error(nullptr, LOG_ERROR,
2341 "\"%s\" unit_type \"%s\":"
2342 "has unknown unit class %s as target.",
2343 filename, utype_rule_name(u), slist[j]);
2344 ok = FALSE;
2345 break;
2346 }
2347
2348 BV_SET(u->targets, uclass_index(uclass));
2349 }
2350 free(slist);
2351
2352 if (!ok) {
2353 break;
2354 }
2355
2356 slist = secfile_lookup_str_vec(file, &nval, "%s.embarks", sec_name);
2357 BV_CLR_ALL(u->embarks);
2358 for (j = 0; j < nval; j++) {
2359 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
2360
2361 if (!uclass) {
2362 ruleset_error(nullptr, LOG_ERROR,
2363 "\"%s\" unit_type \"%s\":"
2364 "has unknown unit class %s as embarkable.",
2365 filename, utype_rule_name(u), slist[j]);
2366 ok = FALSE;
2367 break;
2368 }
2369
2370 BV_SET(u->embarks, uclass_index(uclass));
2371 }
2372 free(slist);
2373
2374 if (!ok) {
2375 break;
2376 }
2377
2378 slist = secfile_lookup_str_vec(file, &nval, "%s.disembarks", sec_name);
2379 BV_CLR_ALL(u->disembarks);
2380 for (j = 0; j < nval; j++) {
2381 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
2382
2383 if (!uclass) {
2384 ruleset_error(nullptr, LOG_ERROR,
2385 "\"%s\" unit_type \"%s\":"
2386 "has unknown unit class %s as disembarkable.",
2387 filename, utype_rule_name(u), slist[j]);
2388 ok = FALSE;
2389 break;
2390 }
2391
2392 BV_SET(u->disembarks, uclass_index(uclass));
2393 }
2394 free(slist);
2395
2396 if (!ok) {
2397 break;
2398 }
2399
2400 /* Set also all classes that are never unreachable as targets,
2401 * embarks, and disembarks. */
2404 BV_SET(u->targets, uclass_index(preachable));
2405 BV_SET(u->embarks, uclass_index(preachable));
2406 BV_SET(u->disembarks, uclass_index(preachable));
2407 }
2409
2410 str = secfile_lookup_str_default(file, "Main", "%s.vision_layer",
2411 sec_name);
2413 if (!vision_layer_is_valid(u->vlayer)) {
2414 ruleset_error(nullptr, LOG_ERROR,
2415 "\"%s\" unit_type \"%s\":"
2416 "has unknown vision layer %s.",
2417 filename, utype_rule_name(u), str);
2418 ok = FALSE;
2419 break;
2420 }
2421
2422 u->helptext = lookup_strvec(file, sec_name, "helptext");
2423
2424 u->paratroopers_range = secfile_lookup_int_default(file,
2425 0, "%s.paratroopers_range", sec_name);
2426
2427 u->bombard_rate = secfile_lookup_int_default(file, 0,
2428 "%s.bombard_rate", sec_name);
2429 u->city_slots = secfile_lookup_int_default(file, 0,
2430 "%s.city_slots", sec_name);
2431 u->city_size = secfile_lookup_int_default(file, 1,
2432 "%s.city_size", sec_name);
2433 if ((sval
2434 = secfile_lookup_str_default(file, nullptr, "%s.specialist", sec_name))) {
2435 if (!(u->spec_type = specialist_by_rule_name(sval))) {
2436 ruleset_error(nullptr, LOG_ERROR,
2437 "\"%s\" unit_type \"%s\":"
2438 " bad specialist \"%s\".",
2439 filename, utype_rule_name(u), sval);
2440 ok = FALSE;
2441 }
2442 } else {
2443 u->spec_type = nullptr;
2444 }
2445
2447 "%s.tp_defense", sec_name);
2448 u->tp_defense = transp_def_type_by_name(sval, fc_strcasecmp);
2449 if (!transp_def_type_is_valid(u->tp_defense)) {
2450 ruleset_error(nullptr, LOG_ERROR,
2451 "\"%s\" unit_type \"%s\":"
2452 " bad tp_defense \"%s\".",
2453 filename, utype_rule_name(u), sval);
2454 ok = FALSE;
2455 break;
2456 }
2458 }
2459
2460 if (ok) {
2461 /* Flags */
2463 const int i = utype_index(u);
2464
2465 BV_CLR_ALL(u->flags);
2467
2468 slist = secfile_lookup_str_vec(file, &nval, "%s.flags",
2470 for (j = 0; j < nval; j++) {
2471 sval = slist[j];
2472 if (0 == strcmp(sval, "")) {
2473 continue;
2474 }
2477 ok = FALSE;
2480 ruleset_error(nullptr, LOG_ERROR,
2481 "\"%s\" unit_type \"%s\": unit_class flag!",
2482 filename, utype_rule_name(u));
2483 } else {
2484 ruleset_error(nullptr, LOG_ERROR,
2485 "\"%s\" unit_type \"%s\": bad flag name \"%s\".",
2486 filename, utype_rule_name(u), sval);
2487 }
2488 break;
2489 } else {
2490 BV_SET(u->flags, ival);
2491 }
2492 }
2493 free(slist);
2494
2495 if (!ok) {
2496 break;
2497 }
2499 }
2500
2501 /* Roles */
2502 if (ok) {
2504 const int i = utype_index(u);
2505
2506 BV_CLR_ALL(u->roles);
2507
2508 slist = secfile_lookup_str_vec(file, &nval, "%s.roles",
2510 for (j = 0; j < nval; j++) {
2511 sval = slist[j];
2512 if (strcmp(sval, "") == 0) {
2513 continue;
2514 }
2517 ruleset_error(nullptr, LOG_ERROR,
2518 "\"%s\" unit_type \"%s\": bad role name \"%s\".",
2519 filename, utype_rule_name(u), sval);
2520 ok = FALSE;
2521 break;
2522 } else {
2523 BV_SET(u->roles, ival - L_FIRST);
2524 }
2526 }
2527 free(slist);
2529 }
2530
2531 if (ok) {
2532 /* Some more consistency checking: */
2535 if (!valid_advance(padv)) {
2536 ruleset_error(nullptr, LOG_ERROR,
2537 "\"%s\" unit_type \"%s\": depends on removed tech \"%s\".",
2538 filename, utype_rule_name(u),
2540 ok = FALSE;
2541 break;
2542 }
2544
2545 if (!ok) {
2546 break;
2547 }
2549 }
2550
2553
2554 if (ok) {
2556 }
2557
2558 return ok;
2559}
2560
2561/**********************************************************************/
2565static bool load_building_names(struct section_file *file,
2566 struct rscompat_info *compat)
2567{
2568 struct section_list *sec;
2569 int i, nval = 0;
2570 const char *filename = secfile_name(file);
2571 bool ok = TRUE;
2572 const char *flag;
2573
2574 if (!rscompat_check_cap_and_version(file, filename, compat)) {
2575 return FALSE;
2576 }
2577
2578 secfile_entry_ignore_by_path(file, "datafile.description"); /* Unused */
2579 secfile_entry_ignore_by_path(file, "datafile.ruledit"); /* Unused */
2580
2581 /* The names: */
2583 if (sec == nullptr || 0 == (nval = section_list_size(sec))) {
2584 ruleset_error(nullptr, LOG_ERROR,
2585 "\"%s\": No improvements?!?", filename);
2586 ok = FALSE;
2587 } else {
2588 log_verbose("%d improvement types (including possibly unused)", nval);
2589 if (nval > B_LAST) {
2590 ruleset_error(nullptr, LOG_ERROR,
2591 "\"%s\": Too many improvements (%d, max %d)",
2592 filename, nval, B_LAST);
2593 ok = FALSE;
2594 }
2595 }
2596
2597 if (ok) {
2599
2600 for (i = 0; i < nval; i++) {
2601 struct impr_type *b = improvement_by_number(i);
2602
2603 if (!ruleset_load_names(&b->name, nullptr, file,
2605 ok = FALSE;
2606 break;
2607 }
2608 }
2609 }
2610
2611 /* User building flag names */
2612 for (i = 0;
2613 (flag = secfile_lookup_str_default(file, nullptr,
2614 "control.building_flags%d.name",
2615 i));
2616 i++) {
2617 const char *helptxt
2618 = secfile_lookup_str_default(file, nullptr,
2619 "control.building_flags%d.helptxt", i);
2620
2622 != impr_flag_id_invalid()) {
2623 ruleset_error(nullptr, LOG_ERROR,
2624 "\"%s\": Duplicate building flag name '%s'",
2625 filename, flag);
2626 ok = FALSE;
2627 break;
2628 }
2630 ruleset_error(nullptr, LOG_ERROR,
2631 "\"%s\": Too many user building flags!",
2632 filename);
2633 ok = FALSE;
2634 break;
2635 }
2636
2637 set_user_impr_flag_name(IF_USER_FLAG_1 + i, flag, helptxt);
2638 }
2639
2641
2642 return ok;
2643}
2644
2645/**********************************************************************/
2648static bool load_ruleset_buildings(struct section_file *file,
2649 struct rscompat_info *compat)
2650{
2651 struct section_list *sec;
2652 const char *item;
2653 int i, nval;
2654 const char *filename = secfile_name(file);
2655 bool ok = TRUE;
2656
2658 nval = (sec != nullptr ? section_list_size(sec) : 0);
2659
2660 for (i = 0; i < nval && ok; i++) {
2661 struct impr_type *b = improvement_by_number(i);
2662 const char *sec_name = section_name(section_list_get(sec, i));
2663 struct requirement_vector *reqs
2664 = lookup_req_list(file, sec_name, "reqs",
2666
2667 if (reqs == nullptr) {
2668 ok = FALSE;
2669 break;
2670 } else {
2671 const char *sval, **slist;
2672 int j, ival;
2673 size_t nflags;
2674
2675 item = secfile_lookup_str(file, "%s.genus", sec_name);
2677 if (!impr_genus_id_is_valid(b->genus)) {
2678 ruleset_error(nullptr, LOG_ERROR,
2679 "\"%s\" improvement \"%s\": couldn't match "
2680 "genus \"%s\".", filename,
2682 ok = FALSE;
2683 break;
2684 }
2685
2686 slist = secfile_lookup_str_vec(file, &nflags, "%s.flags", sec_name);
2687 BV_CLR_ALL(b->flags);
2688
2689 for (j = 0; j < nflags; j++) {
2690 sval = slist[j];
2691 if (strcmp(sval, "") == 0) {
2692 continue;
2693 }
2696 ruleset_error(nullptr, LOG_ERROR,
2697 "\"%s\" improvement \"%s\": bad flag name \"%s\".",
2698 filename, improvement_rule_name(b), sval);
2699 ok = FALSE;
2700 break;
2701 } else {
2702 BV_SET(b->flags, ival);
2703 }
2704 }
2705 free(slist);
2706
2707 if (!ok) {
2708 break;
2709 }
2710
2712
2713 {
2714 struct requirement_vector *obs_reqs
2715 = lookup_req_list(file, sec_name, "obsolete_by",
2717
2718 if (obs_reqs == nullptr) {
2719 ok = FALSE;
2720 break;
2721 } else {
2722 requirement_vector_copy(&b->obsolete_by, obs_reqs);
2723 }
2724 }
2725
2726 if (!secfile_lookup_int(file, &b->build_cost,
2727 "%s.build_cost", sec_name)
2728 || !secfile_lookup_int(file, &b->upkeep,
2729 "%s.upkeep", sec_name)
2730 || !secfile_lookup_int(file, &b->sabotage,
2731 "%s.sabotage", sec_name)) {
2732 ruleset_error(nullptr, LOG_ERROR, "%s", secfile_error());
2733 ok = FALSE;
2734 break;
2735 }
2736
2739 "%s.graphic", sec_name));
2742 "%s.graphic_alt", sec_name));
2745 "%s.graphic_alt2", sec_name));
2746
2749 "%s.sound", sec_name));
2752 "%s.sound_alt", sec_name));
2755 "%s.sound_alt2", sec_name));
2756 b->helptext = lookup_strvec(file, sec_name, "helptext");
2757 }
2758 }
2759
2761 if (ok) {
2763 }
2764
2765 return ok;
2766}
2767
2768/**********************************************************************/
2772static bool load_terrain_names(struct section_file *file,
2773 struct rscompat_info *compat)
2774{
2775 int nval = 0;
2776 struct section_list *sec = nullptr;
2777 const char *flag;
2778 int i;
2779 const char *filename = secfile_name(file);
2780 bool ok = TRUE;
2781
2782 if (!rscompat_check_cap_and_version(file, filename, compat)) {
2783 return FALSE;
2784 }
2785
2786 secfile_entry_ignore_by_path(file, "datafile.description"); /* Unused */
2787 secfile_entry_ignore_by_path(file, "datafile.ruledit"); /* Unused */
2788
2789 /* User terrain flag names */
2790 for (i = 0;
2791 (flag = secfile_lookup_str_default(file, nullptr, "control.flags%d.name", i)) ;
2792 i++) {
2793 const char *helptxt
2794 = secfile_lookup_str_default(file, nullptr, "control.flags%d.helptxt",
2795 i);
2796
2799 ruleset_error(nullptr, LOG_ERROR,
2800 "\"%s\": Duplicate terrain flag name '%s'",
2801 filename, flag);
2802 ok = FALSE;
2803 break;
2804 }
2805 if (i > MAX_NUM_USER_TER_FLAGS) {
2806 ruleset_error(nullptr, LOG_ERROR,
2807 "\"%s\": Too many user terrain flags!",
2808 filename);
2809 ok = FALSE;
2810 break;
2811 }
2812
2813 set_user_terrain_flag_name(TER_USER_1 + i, flag, helptxt);
2814 }
2815
2816 if (ok) {
2817 /* Blank the remaining terrain user flag slots. */
2818 for (; i < MAX_NUM_USER_TER_FLAGS; i++) {
2819 set_user_terrain_flag_name(TER_USER_1 + i, nullptr, nullptr);
2820 }
2821 }
2822
2823 /* User extra flag names */
2824 for (i = 0;
2825 (flag = secfile_lookup_str_default(file, nullptr,
2826 "control.extra_flags%d.name",
2827 i));
2828 i++) {
2829 const char *helptxt = secfile_lookup_str_default(file, nullptr,
2830 "control.extra_flags%d.helptxt", i);
2831
2833 != extra_flag_id_invalid()) {
2834 ruleset_error(nullptr, LOG_ERROR,
2835 "\"%s\": Duplicate extra flag name '%s'",
2836 filename, flag);
2837 ok = FALSE;
2838 break;
2839 }
2841 ruleset_error(nullptr, LOG_ERROR,
2842 "\"%s\": Too many user extra flags!",
2843 filename);
2844 ok = FALSE;
2845 break;
2846 }
2847
2848 set_user_extra_flag_name(EF_USER_FLAG_1 + i, flag, helptxt);
2849 }
2850
2851 if (ok) {
2852 /* Blank the remaining extra user flag slots. */
2853 for (; i < MAX_NUM_USER_EXTRA_FLAGS; i++) {
2854 set_user_extra_flag_name(EF_USER_FLAG_1 + i, nullptr, nullptr);
2855 }
2856
2857 /* Terrain names */
2858
2860 if (sec == nullptr || 0 == (nval = section_list_size(sec))) {
2861 ruleset_error(nullptr, LOG_ERROR,
2862 "\"%s\": ruleset doesn't have any terrains.",
2863 filename);
2864 ok = FALSE;
2865 } else {
2866 if (nval > MAX_NUM_TERRAINS) {
2867 ruleset_error(nullptr, LOG_ERROR,
2868 "\"%s\": Too many terrains (%d, max %d)",
2869 filename, nval, MAX_NUM_TERRAINS);
2870 ok = FALSE;
2871 }
2872 }
2873 }
2874
2875 if (ok) {
2877
2878 /* Avoid re-reading files */
2879 if (terrain_sections) {
2881 }
2883
2884 terrain_type_iterate(pterrain) {
2885 const int terri = terrain_index(pterrain);
2886 const char *sec_name = section_name(section_list_get(sec, terri));
2887
2888 if (!ruleset_load_names(&pterrain->name, nullptr, file, sec_name)) {
2889 ok = FALSE;
2890 break;
2891 }
2892
2895 }
2896
2898 sec = nullptr;
2899
2900 /* Extra names */
2901
2902 if (ok) {
2904 nval = (sec != nullptr ? section_list_size(sec) : 0);
2905 if (nval > MAX_EXTRA_TYPES) {
2906 ruleset_error(nullptr, LOG_ERROR,
2907 "\"%s\": Too many extra types (%d, max %d)",
2908 filename, nval, MAX_EXTRA_TYPES);
2909 ok = FALSE;
2910 }
2911 }
2912
2913 if (ok) {
2914 int idx;
2915
2917
2918 if (extra_sections) {
2920 }
2922
2923 if (ok) {
2924 for (idx = 0; idx < nval; idx++) {
2925 const char *sec_name = section_name(section_list_get(sec, idx));
2926 struct extra_type *pextra = extra_by_number(idx);
2927
2928 if (!ruleset_load_names(&pextra->name, nullptr, file, sec_name)) {
2929 ok = FALSE;
2930 break;
2931 }
2933 }
2934 }
2935 }
2936
2938 sec = nullptr;
2939
2940 /* Base names */
2941
2942 if (ok) {
2944 nval = (sec != nullptr ? section_list_size(sec) : 0);
2945 if (nval > MAX_EXTRA_TYPES) {
2946 ruleset_error(nullptr, LOG_ERROR,
2947 "\"%s\": Too many base types (%d, max %d)",
2948 filename, nval, MAX_EXTRA_TYPES);
2949 ok = FALSE;
2950 }
2951
2953 }
2954
2955 if (ok) {
2956 int idx;
2957
2958 if (base_sections) {
2960 }
2962
2963 /* Cannot use base_type_iterate() before bases are added to
2964 * EC_BASE caused_by list. Have to get them by extra_type_by_rule_name() */
2965 for (idx = 0; idx < nval; idx++) {
2966 const char *sec_name = section_name(section_list_get(sec, idx));
2967 const char *base_name = secfile_lookup_str(file, "%s.extra", sec_name);
2968
2969 if (base_name != nullptr) {
2971
2972 if (pextra != nullptr) {
2973 base_type_init(pextra, idx);
2975 } else {
2976 ruleset_error(nullptr, LOG_ERROR,
2977 "No extra definition matching base definition \"%s\"",
2978 base_name);
2979 ok = FALSE;
2980 }
2981 } else {
2982 ruleset_error(nullptr, LOG_ERROR,
2983 "Base section \"%s\" does not associate base with any extra",
2984 sec_name);
2985 ok = FALSE;
2986 }
2987 }
2988 }
2989
2991 sec = nullptr;
2992
2993 /* Road names */
2994
2995 if (ok) {
2997 nval = (sec != nullptr ? section_list_size(sec) : 0);
2998 if (nval > MAX_EXTRA_TYPES) {
2999 ruleset_error(nullptr, LOG_ERROR,
3000 "\"%s\": Too many road types (%d, max %d)",
3001 filename, nval, MAX_EXTRA_TYPES);
3002 ok = FALSE;
3003 }
3004
3006 }
3007
3008 if (ok) {
3009 int idx;
3010
3011 if (road_sections) {
3013 }
3015
3016 /* Cannot use extra_type_by_cause_iterate(EC_ROAD) before roads are added to
3017 * EC_ROAD caused_by list. Have to get them by extra_type_by_rule_name() */
3018 for (idx = 0; idx < nval; idx++) {
3019 const char *sec_name = section_name(section_list_get(sec, idx));
3020 const char *road_name = secfile_lookup_str(file, "%s.extra", sec_name);
3021
3022 if (road_name != nullptr) {
3024
3025 if (pextra != nullptr) {
3026 road_type_init(pextra, idx);
3028 } else {
3029 ruleset_error(nullptr, LOG_ERROR,
3030 "No extra definition matching road definition \"%s\"",
3031 road_name);
3032 ok = FALSE;
3033 }
3034 } else {
3035 ruleset_error(nullptr, LOG_ERROR,
3036 "Road section \"%s\" does not associate road with any extra",
3037 sec_name);
3038 ok = FALSE;
3039 }
3040 }
3041 }
3042
3044 sec = nullptr;
3045
3046 /* Resource names */
3047 if (ok) {
3049 nval = (sec != nullptr ? section_list_size(sec) : 0);
3050 if (nval > MAX_EXTRA_TYPES) {
3051 ruleset_error(nullptr, LOG_ERROR,
3052 "\"%s\": Too many resource types (%d, max %d)",
3053 filename, nval, MAX_EXTRA_TYPES);
3054 ok = FALSE;
3055 }
3056
3058 }
3059
3060 if (ok) {
3061 int idx;
3062
3063 if (resource_sections) {
3065 }
3067
3068 /* Cannot use resource_type_iterate() before resource are added to
3069 * EC_RESOURCE caused_by list. Have to get them by extra_type_by_rule_name() */
3070 for (idx = 0; idx < nval; idx++) {
3071 const char *sec_name = section_name(section_list_get(sec, idx));
3072 const char *resource_name;
3073 struct extra_type *pextra = nullptr;
3074
3076 = secfile_lookup_str_default(file, nullptr, "%s.extra", sec_name);
3077
3078 if (resource_name != nullptr) {
3080
3081 if (pextra != nullptr) {
3082 resource_type_init(pextra);
3084 } else {
3085 ruleset_error(nullptr, LOG_ERROR,
3086 "No extra definition matching resource definition \"%s\"",
3088 ok = FALSE;
3089 }
3090 } else {
3091 ruleset_error(nullptr, LOG_ERROR,
3092 "Resource section %s does not list extra this resource belongs to.",
3093 sec_name);
3094 ok = FALSE;
3095 }
3096 }
3097 }
3098
3100 sec = nullptr;
3101
3102 /* Tiledef names */
3103
3104 if (ok) {
3106 nval = (sec != nullptr ? section_list_size(sec) : 0);
3107 if (nval > MAX_TILEDEFS) {
3108 ruleset_error(nullptr, LOG_ERROR,
3109 "\"%s\": Too many tiledefs (%d, max %d)",
3110 filename, nval, MAX_TILEDEFS);
3111 ok = FALSE;
3112 }
3113 }
3114
3115 if (ok) {
3116 int idx;
3117
3119
3120 if (tiledef_sections) {
3122 }
3124
3125 if (ok) {
3126 for (idx = 0; idx < nval; idx++) {
3127 const char *sec_name = section_name(section_list_get(sec, idx));
3128 struct tiledef *td = tiledef_by_number(idx);
3129
3130 if (!ruleset_load_names(&td->name, nullptr, file, sec_name)) {
3131 ok = FALSE;
3132 break;
3133 }
3135 }
3136 }
3137 }
3138
3140
3141 return ok;
3142}
3143
3144/**********************************************************************/
3147static bool load_ruleset_terrain(struct section_file *file,
3148 struct rscompat_info *compat)
3149{
3150 size_t nval, nval2;
3151 int j;
3152 bool compat_road = FALSE;
3153 bool compat_rail = FALSE;
3154 bool compat_river = FALSE;
3155 const char **res;
3156 const char *filename = secfile_name(file);
3157 const char *text;
3158 int *res_freq;
3159 bool ok = TRUE;
3160
3161 /* Parameters */
3162
3163 terrain_control.ocean_reclaim_requirement_pct
3164 = secfile_lookup_int_default(file, 101,
3165 "parameters.ocean_reclaim_requirement");
3166 terrain_control.land_channel_requirement_pct
3167 = secfile_lookup_int_default(file, 101,
3168 "parameters.land_channel_requirement");
3169 terrain_control.terrain_thaw_requirement_pct
3170 = secfile_lookup_int_default(file, 101,
3171 "parameters.thaw_requirement");
3172 terrain_control.terrain_freeze_requirement_pct
3173 = secfile_lookup_int_default(file, 101,
3174 "parameters.freeze_requirement");
3175 terrain_control.lake_max_size
3177 "parameters.lake_max_size");
3178 terrain_control.min_start_native_area
3180 "parameters.min_start_native_area");
3181 terrain_control.move_fragments
3183 "parameters.move_fragments");
3184 if (terrain_control.move_fragments < 1) {
3185 ruleset_error(nullptr, LOG_ERROR,
3186 "\"%s\": move_fragments must be at least 1",
3187 filename);
3188 ok = FALSE;
3189 }
3191 terrain_control.igter_cost
3193 "parameters.igter_cost");
3194 if (terrain_control.igter_cost < 1) {
3195 ruleset_error(nullptr, LOG_ERROR,
3196 "\"%s\": igter_cost must be at least 1",
3197 filename);
3198 ok = FALSE;
3199 }
3200 terrain_control.infrapoints = FALSE; /* This will be updated if we find
3201 * an placeable extra. */
3202
3203 terrain_control.pythagorean_diagonal
3205 "parameters.pythagorean_diagonal");
3206
3209 "parameters.ocean_resources");
3210
3211 text = secfile_lookup_str_default(file,
3212 N_("?gui_type:Build Type A Base"),
3213 "extraui.ui_name_base_fortress");
3214 sz_strlcpy(terrain_control.gui_type_base0, text);
3215
3216 text = secfile_lookup_str_default(file,
3217 N_("?gui_type:Build Type B Base"),
3218 "extraui.ui_name_base_airbase");
3219 sz_strlcpy(terrain_control.gui_type_base1, text);
3220
3221 if (ok) {
3222 /* Terrain details */
3223
3224 terrain_type_iterate(pterrain) {
3225 const char **slist;
3226 const int i = terrain_index(pterrain);
3227 const char *tsection = &terrain_sections[i * MAX_SECTION_LABEL];
3228 const char *cstr;
3229 const char *ename;
3230
3231 sz_strlcpy(pterrain->graphic_str,
3232 secfile_lookup_str(file, "%s.graphic", tsection));
3233 sz_strlcpy(pterrain->graphic_alt,
3235 "%s.graphic_alt", tsection));
3236 sz_strlcpy(pterrain->graphic_alt2,
3238 "%s.graphic_alt2", tsection));
3239
3240 pterrain->identifier
3241 = secfile_lookup_str(file, "%s.identifier", tsection)[0];
3242 if ('\0' == pterrain->identifier) {
3243 ruleset_error(nullptr, LOG_ERROR,
3244 "\"%s\" [%s] identifier missing value.",
3245 filename, tsection);
3246 ok = FALSE;
3247 break;
3248 }
3249 if (TERRAIN_UNKNOWN_IDENTIFIER == pterrain->identifier) {
3250 ruleset_error(nullptr, LOG_ERROR,
3251 "\"%s\" [%s] cannot use '%c' as an identifier;"
3252 " it is reserved for unknown terrain.",
3253 filename, tsection, pterrain->identifier);
3254 ok = FALSE;
3255 break;
3256 }
3257 for (j = T_FIRST; j < i; j++) {
3258 if (pterrain->identifier == terrain_by_number(j)->identifier) {
3259 ruleset_error(nullptr, LOG_ERROR,
3260 "\"%s\" [%s] has the same identifier as [%s].",
3261 filename, tsection,
3263 ok = FALSE;
3264 break;
3265 }
3266 }
3267
3268 if (!ok) {
3269 break;
3270 }
3271
3272 cstr = secfile_lookup_str(file, "%s.class", tsection);
3273 pterrain->tclass = terrain_class_by_name(cstr, fc_strcasecmp);
3274 if (!terrain_class_is_valid(pterrain->tclass)) {
3275 ruleset_error(nullptr, LOG_ERROR,
3276 "\"%s\": [%s] unknown class \"%s\"",
3277 filename, tsection, cstr);
3278 ok = FALSE;
3279 break;
3280 }
3281
3282 if (!secfile_lookup_int(file, &pterrain->movement_cost,
3283 "%s.movement_cost", tsection)
3284 || !secfile_lookup_int(file, &pterrain->defense_bonus,
3285 "%s.defense_bonus", tsection)) {
3286 ruleset_error(nullptr, LOG_ERROR, "%s", secfile_error());
3287 ok = FALSE;
3288 break;
3289 }
3290
3292 pterrain->output[o]
3293 = secfile_lookup_int_default(file, 0, "%s.%s", tsection,
3296
3297 res = secfile_lookup_str_vec(file, &nval, "%s.resources", tsection);
3299 "%s.resource_freq", tsection);
3300 if (nval2 > 0 && nval2 != nval) {
3301 ruleset_error(nullptr, LOG_ERROR,
3302 "\"%s\": [%s] Different lengths for resources "
3303 "and resource frequencies",
3304 filename, tsection);
3305 ok = FALSE;
3306 }
3307 pterrain->resources = fc_calloc(nval + 1, sizeof(*pterrain->resources));
3308 pterrain->resource_freq = fc_calloc(nval + 1,
3309 sizeof(*pterrain->resource_freq));
3310 for (j = 0; j < nval; j++) {
3311 pterrain->resources[j] = lookup_resource(filename, res[j], tsection);
3312 if (pterrain->resources[j] == nullptr) {
3313 ok = FALSE;
3314 break;
3315 }
3316 pterrain->resource_freq[j] = j < nval2
3317 ? res_freq[j]
3319 if (pterrain->resource_freq[j] < RESOURCE_FREQUENCY_MINIMUM
3320 || pterrain->resource_freq[j] > RESOURCE_FREQUENCY_MAXIMUM) {
3321 ruleset_error(nullptr, LOG_ERROR,
3322 "\"%s\": [%s] Resource frequency '%d' "
3323 "outside allowed range",
3324 filename, tsection,
3325 pterrain->resource_freq[j]);
3326 ok = FALSE;
3327 break;
3328 }
3329 }
3330 pterrain->resources[nval] = nullptr;
3331 /* Terminating zero technically not necessary */
3332 pterrain->resource_freq[nval] = 0;
3333 free(res);
3334 res = nullptr;
3335 free(res_freq);
3336 res_freq = nullptr;
3337
3338 if (!ok) {
3339 break;
3340 }
3341
3343 pterrain->road_output_incr_pct[o]
3344 = secfile_lookup_int_default(file, 0, "%s.road_%s_incr_pct",
3347
3348 if (!lookup_time(file, &pterrain->base_time, tsection, "base_time",
3349 filename, nullptr, &ok)
3350 || !lookup_time(file, &pterrain->road_time, tsection, "road_time",
3351 filename, nullptr, &ok)) {
3352 ruleset_error(nullptr, LOG_ERROR, "%s", secfile_error());
3353 ok = FALSE;
3354 break;
3355 }
3356
3357 if (!lookup_terrain(file, "cultivate_result", filename, pterrain,
3358 &pterrain->cultivate_result, FALSE)) {
3359 ruleset_error(nullptr, LOG_ERROR, "%s: No cultivate_result", tsection);
3360 ok = FALSE;
3361 break;
3362 }
3363 if (pterrain->cultivate_result == pterrain) {
3364 ruleset_error(nullptr, LOG_ERROR,
3365 "%s: Cultivating result in terrain itself.",
3366 tsection);
3367 ok = FALSE;
3368 break;
3369 }
3370 if (!secfile_lookup_int(file, &pterrain->irrigation_food_incr,
3371 "%s.irrigation_food_incr", tsection)
3372 || !lookup_time(file, &pterrain->irrigation_time,
3373 tsection, "irrigation_time", filename, nullptr, &ok)) {
3374 ruleset_error(nullptr, LOG_ERROR, "%s", secfile_error());
3375 ok = FALSE;
3376 break;
3377 }
3378
3379 if (!lookup_terrain(file, "plant_result", filename, pterrain,
3380 &pterrain->plant_result, FALSE)) {
3381 ruleset_error(nullptr, LOG_ERROR, "%s: No plant_result", tsection);
3382 ok = FALSE;
3383 break;
3384 }
3385 if (pterrain->plant_result == pterrain) {
3386 ruleset_error(nullptr, LOG_ERROR,
3387 "%s: Planting result in terrain itself.",
3388 tsection);
3389 ok = FALSE;
3390 break;
3391 }
3392 if (!secfile_lookup_int(file, &pterrain->mining_shield_incr,
3393 "%s.mining_shield_incr", tsection)
3394 || !lookup_time(file, &pterrain->mining_time,
3395 tsection, "mining_time", filename, nullptr, &ok)) {
3396 ruleset_error(nullptr, LOG_ERROR, "%s", secfile_error());
3397 ok = FALSE;
3398 break;
3399 }
3400
3401 if (!lookup_time(file, &pterrain->cultivate_time,
3402 tsection, "cultivate_time", filename, nullptr, &ok)) {
3403 ruleset_error(nullptr, LOG_ERROR,
3404 "%s: Missing cultivate_time", tsection);
3405 ok = FALSE;
3406 break;
3407 }
3408 if ((pterrain->cultivate_result != nullptr
3409 && pterrain->cultivate_time <= 0)
3410 || (pterrain->cultivate_result == nullptr
3411 && pterrain->cultivate_time > 0)) {
3412 ruleset_error(nullptr, LOG_ERROR,
3413 "%s: cultivate_result and cultivate_time disagree "
3414 "whether cultivating is enabled", tsection);
3415 ok = FALSE;
3416 break;
3417 }
3418
3419 if (!lookup_time(file, &pterrain->plant_time,
3420 tsection, "plant_time", filename, nullptr, &ok)) {
3421 ruleset_error(nullptr, LOG_ERROR,
3422 "%s: Missing plant_time", tsection);
3423 ok = FALSE;
3424 break;
3425 }
3426 if ((pterrain->plant_result != nullptr
3427 && pterrain->plant_time <= 0)
3428 || (pterrain->plant_result == nullptr
3429 && pterrain->plant_time > 0)) {
3430 ruleset_error(nullptr, LOG_ERROR,
3431 "%s: plant_result and plant_time disagree "
3432 "whether planting is enabled", tsection);
3433 ok = FALSE;
3434 break;
3435 }
3436
3437 res = secfile_lookup_str_vec(file, &nval, "%s.animals", tsection);
3438 pterrain->num_animals = nval;
3439 if (pterrain->num_animals == 0) {
3440 pterrain->animals = nullptr;
3441 } else {
3442 pterrain->animals = fc_calloc(pterrain->num_animals,
3443 sizeof(*pterrain->animals));
3444 for (j = 0; j < pterrain->num_animals; j++) {
3445 pterrain->animals[j] = unit_type_by_rule_name(res[j]);
3446 if (pterrain->animals[j] == nullptr) {
3447 ok = FALSE;
3448 break;
3449 }
3450 }
3451 }
3452 free(res);
3453 res = nullptr;
3454 if (!ok) {
3455 break;
3456 }
3457
3458 if (!lookup_terrain(file, "transform_result", filename, pterrain,
3459 &pterrain->transform_result, TRUE)) {
3460 ok = FALSE;
3461 break;
3462 }
3463 if (!lookup_time(file, &pterrain->transform_time,
3464 tsection, "transform_time", filename, nullptr, &ok)) {
3465 ruleset_error(nullptr, LOG_ERROR, "%s", secfile_error());
3466 ok = FALSE;
3467 break;
3468 }
3469 if ((pterrain->transform_result != nullptr
3470 && pterrain->transform_time <= 0)
3471 || (pterrain->transform_result == nullptr
3472 && pterrain->transform_time > 0)) {
3473 ruleset_error(nullptr, LOG_ERROR,
3474 "%s: transform_result and transform_time disagree "
3475 "whether transforming is enabled", tsection);
3476 ok = FALSE;
3477 break;
3478 }
3479
3480 pterrain->placing_time = 1; /* Default */
3481 lookup_time(file, &pterrain->placing_time,
3482 tsection, "placing_time", filename, nullptr, &ok);
3483
3484 pterrain->pillage_time = 1; /* Default */
3485 lookup_time(file, &pterrain->pillage_time,
3486 tsection, "pillage_time", filename, nullptr, &ok);
3487
3488 if (!lookup_terrain(file, "warmer_wetter_result", filename, pterrain,
3489 &pterrain->warmer_wetter_result, TRUE)
3490 || !lookup_terrain(file, "warmer_drier_result", filename, pterrain,
3491 &pterrain->warmer_drier_result, TRUE)
3492 || !lookup_terrain(file, "cooler_wetter_result", filename, pterrain,
3493 &pterrain->cooler_wetter_result, TRUE)
3494 || !lookup_terrain(file, "cooler_drier_result", filename, pterrain,
3495 &pterrain->cooler_drier_result, TRUE)) {
3496 ok = FALSE;
3497 break;
3498 }
3499
3500 /* Set default removal times */
3501 extra_type_iterate(pextra) {
3502 pterrain->extra_removal_times[extra_index(pextra)] = 0;
3504
3505 for (j = 0; (ename = secfile_lookup_str_default(file, nullptr,
3506 "%s.extra_settings%d.extra",
3507 tsection, j)); j++) {
3508 const struct extra_type *pextra = extra_type_by_rule_name(ename);
3509
3510 if (pextra != nullptr) {
3511 char time_sections[512];
3512
3514 "%s.extra_settings%d", tsection, j);
3515
3516 lookup_time(file, &pterrain->extra_removal_times[extra_index(pextra)],
3517 time_sections, "removal_time", filename, nullptr, &ok);
3518 } else {
3519 ruleset_error(nullptr, LOG_ERROR,
3520 "\"%s\" [%s] has settings for unknown extra \"%s\".",
3521 filename, tsection, ename);
3522 ok = FALSE;
3523 break;
3524 }
3525 }
3526
3527 if (ok) {
3528 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", tsection);
3529 BV_CLR_ALL(pterrain->flags);
3530 for (j = 0; j < nval; j++) {
3531 const char *sval = slist[j];
3532 enum terrain_flag_id flag
3534
3535 if (!terrain_flag_id_is_valid(flag)) {
3536 ruleset_error(nullptr, LOG_ERROR,
3537 "\"%s\" [%s] has unknown flag \"%s\".",
3538 filename, tsection, sval);
3539 ok = FALSE;
3540 break;
3541 } else {
3542 BV_SET(pterrain->flags, flag);
3543 }
3544 }
3545
3546 free(slist);
3547 }
3548
3549 if (!ok) {
3550 break;
3551 }
3552
3553 {
3555
3559 pterrain->property[mtp]
3560 = secfile_lookup_int_default(file, 0, "%s.property_%s", tsection,
3562 }
3563 }
3564
3565 slist = secfile_lookup_str_vec(file, &nval, "%s.native_to", tsection);
3566 BV_CLR_ALL(pterrain->native_to);
3567 for (j = 0; j < nval; j++) {
3568 struct unit_class *class = unit_class_by_rule_name(slist[j]);
3569
3570 if (!class) {
3571 ruleset_error(nullptr, LOG_ERROR,
3572 "\"%s\" [%s] is native to unknown unit class \"%s\".",
3573 filename, tsection, slist[j]);
3574 ok = FALSE;
3575 break;
3576 } else {
3577 BV_SET(pterrain->native_to, uclass_index(class));
3578 }
3579 }
3580 free(slist);
3581
3582 if (!ok) {
3583 break;
3584 }
3585
3586 /* Get terrain color */
3587 {
3588 fc_assert_ret_val(pterrain->rgb == nullptr, FALSE);
3589
3590 if (!rgbcolor_load(file, &pterrain->rgb, "%s.color", tsection)) {
3591 ruleset_error(nullptr, LOG_ERROR,
3592 "Missing terrain color definition: %s",
3593 secfile_error());
3594 ok = FALSE;
3595 break;
3596 }
3597 }
3598
3599 pterrain->helptext = lookup_strvec(file, tsection, "helptext");
3601 }
3602
3603 if (ok) {
3604 /* Extra details */
3605 extra_type_iterate(pextra) {
3606 BV_CLR_ALL(pextra->conflicts);
3608
3609 extra_type_iterate(pextra) {
3610 int eidx = extra_index(pextra);
3611 const char *section = &extra_sections[eidx * MAX_SECTION_LABEL];
3612 const char **slist;
3613 struct requirement_vector *reqs;
3614 const char *catname;
3615 int cj;
3616 enum extra_cause cause;
3618 const char *eus_name;
3619 const char *vis_req_name;
3620 const struct advance *vis_req;
3621
3622 catname = secfile_lookup_str(file, "%s.category", section);
3623 if (catname == nullptr) {
3624 ruleset_error(nullptr, LOG_ERROR,
3625 "\"%s\" extra \"%s\" has no category.",
3626 filename, extra_rule_name(pextra));
3627 ok = FALSE;
3628 break;
3629 }
3630 pextra->category = extra_category_by_name(catname, fc_strcasecmp);
3631 if (!extra_category_is_valid(pextra->category)) {
3632 ruleset_error(nullptr, LOG_ERROR,
3633 "\"%s\" extra \"%s\" has invalid category \"%s\".",
3634 filename, extra_rule_name(pextra), catname);
3635 ok = FALSE;
3636 break;
3637 }
3638
3639 slist = secfile_lookup_str_vec(file, &nval, "%s.causes", section);
3640 pextra->causes = 0;
3641 for (cj = 0; cj < nval; cj++) {
3642 const char *sval = slist[cj];
3644
3645 if (!extra_cause_is_valid(cause)) {
3646 ruleset_error(nullptr, LOG_ERROR,
3647 "\"%s\" extra \"%s\": unknown cause \"%s\".",
3648 filename, extra_rule_name(pextra), sval);
3649 ok = FALSE;
3650 break;
3651 } else {
3652 pextra->causes |= (1 << cause);
3653 extra_to_caused_by_list(pextra, cause);
3654 }
3655 }
3656
3657 if (pextra->causes == 0) {
3658 /* Extras that do not have any causes added to EC_NONE list */
3660 }
3661
3662 if (!is_extra_caused_by(pextra, EC_BASE)
3663 && !is_extra_caused_by(pextra, EC_ROAD)
3664 && !is_extra_caused_by(pextra, EC_RESOURCE)) {
3665 /* Not a base, road, nor resource, so special */
3666 pextra->data.special_idx = extra_type_list_size(extra_type_list_by_cause(EC_SPECIAL));
3668 }
3669
3670 free(slist);
3671
3672 slist = secfile_lookup_str_vec(file, &nval, "%s.rmcauses", section);
3673 pextra->rmcauses = 0;
3674 for (j = 0; j < nval; j++) {
3675 const char *sval = slist[j];
3676
3678
3680 ruleset_error(nullptr, LOG_ERROR,
3681 "\"%s\" extra \"%s\": unknown rmcause \"%s\".",
3682 filename, extra_rule_name(pextra), sval);
3683 ok = FALSE;
3684 break;
3685 } else {
3686 pextra->rmcauses |= (1 << rmcause);
3688 }
3689 }
3690
3691 free(slist);
3692
3693 sz_strlcpy(pextra->activity_gfx,
3695 "%s.activity_gfx", section));
3696 sz_strlcpy(pextra->act_gfx_alt,
3698 "%s.act_gfx_alt", section));
3699 sz_strlcpy(pextra->act_gfx_alt2,
3701 "%s.act_gfx_alt2", section));
3702 sz_strlcpy(pextra->rmact_gfx,
3704 "%s.rmact_gfx", section));
3705 sz_strlcpy(pextra->rmact_gfx_alt,
3707 "%s.rmact_gfx_alt", section));
3708 sz_strlcpy(pextra->rmact_gfx_alt2,
3710 "%s.rmact_gfx_alt2", section));
3711 sz_strlcpy(pextra->graphic_str,
3712 secfile_lookup_str_default(file, "-", "%s.graphic", section));
3713 sz_strlcpy(pextra->graphic_alt,
3715 "%s.graphic_alt", section));
3716
3717 reqs = lookup_req_list(file, section, "reqs", extra_rule_name(pextra));
3718 if (reqs == nullptr) {
3719 ok = FALSE;
3720 break;
3721 }
3722 requirement_vector_copy(&pextra->reqs, reqs);
3723
3724 reqs = lookup_req_list(file, section, "rmreqs", extra_rule_name(pextra));
3725 if (reqs == nullptr) {
3726 ok = FALSE;
3727 break;
3728 }
3729 requirement_vector_copy(&pextra->rmreqs, reqs);
3730
3731 reqs = lookup_req_list(file, section, "appearance_reqs", extra_rule_name(pextra));
3732 if (reqs == nullptr) {
3733 ok = FALSE;
3734 break;
3735 }
3736 requirement_vector_copy(&pextra->appearance_reqs, reqs);
3737
3738 reqs = lookup_req_list(file, section, "disappearance_reqs", extra_rule_name(pextra));
3739 if (reqs == nullptr) {
3740 ok = FALSE;
3741 break;
3742 }
3743 requirement_vector_copy(&pextra->disappearance_reqs, reqs);
3744
3745 pextra->buildable = secfile_lookup_bool_default(file,
3747 "%s.buildable", section);
3748 pextra->generated = secfile_lookup_bool_default(file, TRUE,
3749 "%s.generated", section);
3750
3751 pextra->build_time = 0; /* default */
3752 lookup_time(file, &pextra->build_time, section, "build_time",
3753 filename, extra_rule_name(pextra), &ok);
3754 pextra->build_time_factor = secfile_lookup_int_default(file, 1,
3755 "%s.build_time_factor", section);
3756 pextra->removal_time = 0; /* default */
3757 lookup_time(file, &pextra->removal_time, section, "removal_time",
3758 filename, extra_rule_name(pextra), &ok);
3759 pextra->removal_time_factor = secfile_lookup_int_default(file, 1,
3760 "%s.removal_time_factor", section);
3761 pextra->infracost = secfile_lookup_int_default(file, 0,
3762 "%s.infracost", section);
3763 if (pextra->infracost > 0) {
3764 terrain_control.infrapoints = TRUE;
3765 }
3766
3767 pextra->defense_bonus = secfile_lookup_int_default(file, 0,
3768 "%s.defense_bonus",
3769 section);
3770 if (pextra->defense_bonus != 0) {
3771 if (extra_has_flag(pextra, EF_NATURAL_DEFENSE)) {
3773 } else {
3775 }
3776 }
3777
3778 eus_name = secfile_lookup_str_default(file, "Normal", "%s.unit_seen", section);
3780 if (!extra_unit_seen_type_is_valid(pextra->eus)) {
3781 ruleset_error(nullptr, LOG_ERROR,
3782 "\"%s\" extra \"%s\" has illegal unit_seen value \"%s\".",
3783 filename, extra_rule_name(pextra), eus_name);
3784 ok = FALSE;
3785 break;
3786 }
3787 if (pextra->eus == EUS_HIDDEN) {
3789 }
3790
3791 pextra->appearance_chance = secfile_lookup_int_default(file, RS_DEFAULT_EXTRA_APPEARANCE,
3792 "%s.appearance_chance",
3793 section);
3794 pextra->disappearance_chance = secfile_lookup_int_default(file,
3796 "%s.disappearance_chance",
3797 section);
3798
3799 pextra->no_aggr_near_city = secfile_lookup_int_default(file, -1,
3800 "%s.no_aggr_near_city",
3801 section);
3802
3803 slist = secfile_lookup_str_vec(file, &nval, "%s.native_to", section);
3804 BV_CLR_ALL(pextra->native_to);
3805 for (j = 0; j < nval; j++) {
3806 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
3807
3808 if (uclass == nullptr) {
3809 ruleset_error(nullptr, LOG_ERROR,
3810 "\"%s\" extra \"%s\" is native to unknown unit class \"%s\".",
3811 filename, extra_rule_name(pextra), slist[j]);
3812 ok = FALSE;
3813 break;
3814 } else {
3815 BV_SET(pextra->native_to, uclass_index(uclass));
3816 }
3817 }
3818 free(slist);
3819
3820 if (!ok) {
3821 break;
3822 }
3823
3824 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
3825 BV_CLR_ALL(pextra->flags);
3826 for (j = 0; j < nval; j++) {
3827 const char *sval = slist[j];
3828 enum extra_flag_id flag;
3829
3831
3832 if (!extra_flag_id_is_valid(flag)) {
3833 ruleset_error(nullptr, LOG_ERROR,
3834 "\"%s\" extra \"%s\": unknown flag \"%s\".",
3835 filename, extra_rule_name(pextra), sval);
3836 ok = FALSE;
3837 break;
3838 } else {
3839 BV_SET(pextra->flags, flag);
3840 }
3841 }
3842 free(slist);
3843
3844 if (pextra->no_aggr_near_city >= 0) {
3846 }
3847
3848 if (extra_has_flag(pextra, EF_CAUSE_ZOC)) {
3850 }
3851
3852 if (!ok) {
3853 break;
3854 }
3855
3856 slist = secfile_lookup_str_vec(file, &nval, "%s.conflicts", section);
3857 for (j = 0; j < nval; j++) {
3858 const char *sval = slist[j];
3860
3861 if (pextra2 == nullptr) {
3862 ruleset_error(nullptr, LOG_ERROR,
3863 "\"%s\" extra \"%s\": unknown conflict extra \"%s\".",
3864 filename, extra_rule_name(pextra), sval);
3865 ok = FALSE;
3866 break;
3867 } else {
3868 BV_SET(pextra->conflicts, extra_index(pextra2));
3869 BV_SET(pextra2->conflicts, extra_index(pextra));
3870 }
3871 }
3872
3873 free(slist);
3874
3875 if (!ok) {
3876 break;
3877 }
3878
3879 slist = secfile_lookup_str_vec(file, &nval, "%s.hidden_by", section);
3880 BV_CLR_ALL(pextra->hidden_by);
3881 for (j = 0; j < nval; j++) {
3882 const char *sval = slist[j];
3883 const struct extra_type *top = extra_type_by_rule_name(sval);
3884
3885 if (top == nullptr) {
3886 ruleset_error(nullptr, LOG_ERROR,
3887 "\"%s\" extra \"%s\" hidden by unknown extra \"%s\".",
3888 filename, extra_rule_name(pextra), sval);
3889 ok = FALSE;
3890 break;
3891 } else {
3892 BV_SET(pextra->hidden_by, extra_index(top));
3893 }
3894 }
3895 free(slist);
3896
3897 if (!ok) {
3898 break;
3899 }
3900
3901 slist = secfile_lookup_str_vec(file, &nval, "%s.bridged_over", section);
3902 BV_CLR_ALL(pextra->bridged_over);
3903 for (j = 0; j < nval; j++) {
3904 const char *sval = slist[j];
3905 const struct extra_type *top = extra_type_by_rule_name(sval);
3906
3907 if (top == nullptr) {
3908 ruleset_error(nullptr, LOG_ERROR,
3909 "\"%s\" extra \"%s\" bridged over unknown extra \"%s\".",
3910 filename, extra_rule_name(pextra), sval);
3911 ok = FALSE;
3912 break;
3913 } else {
3914 BV_SET(pextra->bridged_over, extra_index(top));
3915 }
3916 }
3917 free(slist);
3918
3919 if (!ok) {
3920 break;
3921 }
3922
3924 "%s.visibility_req", section);
3926
3927 if (vis_req == nullptr) {
3928 ruleset_error(nullptr, LOG_ERROR,
3929 "\"%s\" %s: unknown visibility_req %s.",
3930 filename, section, vis_req_name);
3931 ok = FALSE;
3932 break;
3933 }
3934
3935 pextra->visibility_req = advance_number(vis_req);
3936
3937 pextra->helptext = lookup_strvec(file, section, "helptext");
3939 }
3940
3941 if (ok) {
3942 int i = 0;
3943 /* Resource details */
3944
3946 char identifier[MAX_LEN_NAME];
3947 const char *id;
3949
3950 if (!presource->data.resource) {
3951 ruleset_error(nullptr, LOG_ERROR,
3952 "\"%s\" extra \"%s\" has \"Resource\" cause but no "
3953 "corresponding [resource_*] section",
3954 filename, extra_rule_name(presource));
3955 ok = FALSE;
3956 break;
3957 }
3958
3960 presource->data.resource->output[o]
3961 = secfile_lookup_int_default(file, 0, "%s.%s", rsection,
3964
3965 id = secfile_lookup_str_default(file, nullptr, "%s.identifier", rsection);
3966
3967 if (id == nullptr) {
3968 presource->data.resource->id_old_save = '\0';
3969 } else {
3970 sz_strlcpy(identifier, id);
3971
3972 presource->data.resource->id_old_save = identifier[0];
3973 if (RESOURCE_NULL_IDENTIFIER == presource->data.resource->id_old_save) {
3974 ruleset_error(nullptr, LOG_ERROR,
3975 "\"%s\" [%s] identifier missing value.",
3976 filename, rsection);
3977 ok = FALSE;
3978 break;
3979 }
3980 if (RESOURCE_NONE_IDENTIFIER == presource->data.resource->id_old_save) {
3981 ruleset_error(nullptr, LOG_ERROR,
3982 "\"%s\" [%s] cannot use '%c' as an identifier;"
3983 " it is reserved.",
3984 filename, rsection, presource->data.resource->id_old_save);
3985 ok = FALSE;
3986 break;
3987 }
3988 }
3989
3990 if (!ok) {
3991 break;
3992 }
3993
3994 i++;
3996
3997 for (j = 0; ok && j < game.control.num_resource_types; j++) {
3998 const char *section = &resource_sections[j * MAX_SECTION_LABEL];
3999 const char *extra_name = secfile_lookup_str(file, "%s.extra", section);
4001
4002 if (!is_extra_caused_by(pextra, EC_RESOURCE)) {
4003 ruleset_error(nullptr, LOG_ERROR,
4004 "\"%s\" resource section [%s]: extra \"%s\" does not "
4005 "have \"Resource\" in its causes",
4006 filename, section, extra_name);
4007 ok = FALSE;
4008 }
4009 }
4010 }
4011
4012 if (ok) {
4013 /* This can't be part of previous loop as we don't want random data from previous
4014 * ruleset to play havoc on us when we have only some resource identifiers loaded
4015 * from the new ruleset. */
4017 if (pres->data.resource->id_old_save != '\0') {
4019 if (pres->data.resource->id_old_save == pres2->data.resource->id_old_save
4020 && pres != pres2) {
4021 ruleset_error(nullptr, LOG_ERROR,
4022 "\"%s\" [%s] has the same identifier as [%s].",
4023 filename,
4026 ok = FALSE;
4027 break;
4028 }
4030
4031 if (!ok) {
4032 break;
4033 }
4034 }
4036 }
4037
4038 if (ok) {
4039 /* Base details */
4041 struct base_type *pbase = extra_base_get(pextra);
4042 const char *section;
4043 const char *gui_str;
4044
4045 if (!pbase) {
4046 ruleset_error(nullptr, LOG_ERROR,
4047 "\"%s\" extra \"%s\" has \"Base\" cause but no "
4048 "corresponding [base_*] section",
4049 filename, extra_rule_name(pextra));
4050 ok = FALSE;
4051 break;
4052 }
4054
4055 gui_str = secfile_lookup_str(file, "%s.gui_type", section);
4057 if (!base_gui_type_is_valid(pbase->gui_type)) {
4058 ruleset_error(nullptr, LOG_ERROR,
4059 "\"%s\" base \"%s\": unknown gui_type \"%s\".",
4060 filename, extra_rule_name(pextra), gui_str);
4061 ok = FALSE;
4062 break;
4063 }
4064
4065 pbase->border_sq = secfile_lookup_int_default(file, -1, "%s.border_sq",
4066 section);
4067 pbase->vision_main_sq = secfile_lookup_int_default(file, -1,
4068 "%s.vision_main_sq",
4069 section);
4070 pbase->vision_invis_sq = secfile_lookup_int_default(file, -1,
4071 "%s.vision_invis_sq",
4072 section);
4073 pbase->vision_subs_sq = secfile_lookup_int_default(file, -1,
4074 "%s.vision_subs_sq",
4075 section);
4076
4077 if (!ok) {
4078 break;
4079 }
4080
4083
4085 struct base_type *pbase2;
4086
4087 if (pextra == pextra2) {
4088 /* End of the fully initialized bases iteration. */
4089 break;
4090 }
4091
4094 BV_SET(pextra->conflicts, extra_index(pextra2));
4095 BV_SET(pextra2->conflicts, extra_index(pextra));
4096 }
4098 }
4100
4101 for (j = 0; ok && j < game.control.num_base_types; j++) {
4102 const char *section = &base_sections[j * MAX_SECTION_LABEL];
4103 const char *extra_name = secfile_lookup_str(file, "%s.extra", section);
4105
4106 if (!is_extra_caused_by(pextra, EC_BASE)) {
4107 ruleset_error(nullptr, LOG_ERROR,
4108 "\"%s\" base section [%s]: extra \"%s\" does not have "
4109 "\"Base\" in its causes",
4110 filename, section, extra_name);
4111 ok = FALSE;
4112 }
4113 }
4114 }
4115
4116 if (ok) {
4118 struct road_type *proad = extra_road_get(pextra);
4119 const char *section;
4120 const char **slist;
4121 const char *special;
4122 const char *modestr;
4123 struct requirement_vector *reqs;
4124 const char *gui_str;
4125
4126 if (!proad) {
4127 ruleset_error(nullptr, LOG_ERROR,
4128 "\"%s\" extra \"%s\" has \"Road\" cause but no "
4129 "corresponding [road_*] section",
4130 filename, extra_rule_name(pextra));
4131 ok = FALSE;
4132 break;
4133 }
4135
4136 gui_str = secfile_lookup_str(file, "%s.gui_type", section);
4138 if (!road_gui_type_is_valid(proad->gui_type)) {
4139 ruleset_error(nullptr, LOG_ERROR,
4140 "\"%s\" road \"%s\": unknown gui_type \"%s\".",
4141 filename, extra_rule_name(pextra), gui_str);
4142 ok = FALSE;
4143 break;
4144 }
4145
4146 reqs = lookup_req_list(file, section, "first_reqs", extra_rule_name(pextra));
4147 if (reqs == nullptr) {
4148 ok = FALSE;
4149 break;
4150 }
4151 requirement_vector_copy(&proad->first_reqs, reqs);
4152
4153 if (!secfile_lookup_int(file, &proad->move_cost,
4154 "%s.move_cost", section)) {
4155 ruleset_error(nullptr, LOG_ERROR, "Error: %s", secfile_error());
4156 ok = FALSE;
4157 break;
4158 }
4159
4160 modestr = secfile_lookup_str_default(file, "FastAlways", "%s.move_mode",
4161 section);
4163 if (!road_move_mode_is_valid(proad->move_mode)) {
4164 ruleset_error(nullptr, LOG_ERROR,
4165 "Illegal move_mode \"%s\" for road \"%s\"",
4166 modestr, extra_rule_name(pextra));
4167 ok = FALSE;
4168 break;
4169 }
4170
4172 proad->tile_incr_const[o] =
4173 secfile_lookup_int_default(file, 0, "%s.%s_incr_const",
4175 proad->tile_incr[o] =
4176 secfile_lookup_int_default(file, 0, "%s.%s_incr",
4178 proad->tile_bonus[o] =
4179 secfile_lookup_int_default(file, 0, "%s.%s_bonus",
4182
4183 special = secfile_lookup_str_default(file, "None", "%s.compat_special", section);
4184 if (!fc_strcasecmp(special, "Road")) {
4185 if (compat_road) {
4186 ruleset_error(nullptr, LOG_ERROR,
4187 "Multiple roads marked as compatibility \"Road\"");
4188 ok = FALSE;
4189 }
4190 compat_road = TRUE;
4191 proad->compat = ROCO_ROAD;
4192 } else if (!fc_strcasecmp(special, "Railroad")) {
4193 if (compat_rail) {
4194 ruleset_error(nullptr, LOG_ERROR,
4195 "Multiple roads marked as compatibility \"Railroad\"");
4196 ok = FALSE;
4197 }
4198 compat_rail = TRUE;
4199 proad->compat = ROCO_RAILROAD;
4200 } else if (!fc_strcasecmp(special, "River")) {
4201 if (compat_river) {
4202 ruleset_error(nullptr, LOG_ERROR,
4203 "Multiple roads marked as compatibility \"River\"");
4204 ok = FALSE;
4205 }
4207 proad->compat = ROCO_RIVER;
4208 } else if (!fc_strcasecmp(special, "None")) {
4209 proad->compat = ROCO_NONE;
4210 } else {
4211 ruleset_error(nullptr, LOG_ERROR,
4212 "Illegal compatibility special \"%s\" for road %s",
4213 special, extra_rule_name(pextra));
4214 ok = FALSE;
4215 }
4216
4217 if (!ok) {
4218 break;
4219 }
4220
4221 slist = secfile_lookup_str_vec(file, &nval, "%s.integrates", section);
4222 BV_CLR_ALL(proad->integrates);
4223 for (j = 0; j < nval; j++) {
4224 const char *sval = slist[j];
4226 struct road_type *top = nullptr;
4227
4228 if (textra != nullptr) {
4229 top = extra_road_get(textra);
4230 }
4231
4232 if (top == nullptr) {
4233 ruleset_error(nullptr, LOG_ERROR,
4234 "\"%s\" road \"%s\" integrates with unknown road \"%s\".",
4235 filename, extra_rule_name(pextra), sval);
4236 ok = FALSE;
4237 break;
4238 } else {
4239 BV_SET(proad->integrates, road_number(top));
4240 }
4241 }
4242 free(slist);
4243
4244 if (!ok) {
4245 break;
4246 }
4247
4248 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
4249 BV_CLR_ALL(proad->flags);
4250 for (j = 0; j < nval; j++) {
4251 const char *sval = slist[j];
4253
4254 if (!road_flag_id_is_valid(flag)) {
4255 ruleset_error(nullptr, LOG_ERROR,
4256 "\"%s\" road \"%s\": unknown flag \"%s\".",
4257 filename, extra_rule_name(pextra), sval);
4258 ok = FALSE;
4259 break;
4260 } else {
4261 BV_SET(proad->flags, flag);
4262 }
4263 }
4264 free(slist);
4265
4266 if (!ok) {
4267 break;
4268 }
4270
4271 for (j = 0; ok && j < game.control.num_road_types; j++) {
4272 const char *section = &road_sections[j * MAX_SECTION_LABEL];
4273 const char *extra_name = secfile_lookup_str(file, "%s.extra", section);
4275
4276 if (!is_extra_caused_by(pextra, EC_ROAD)) {
4277 ruleset_error(nullptr, LOG_ERROR,
4278 "\"%s\" road section [%s]: extra \"%s\" does not have "
4279 "\"Road\" in its causes",
4280 filename, section, extra_name);
4281 ok = FALSE;
4282 }
4283 }
4284 }
4285
4286 if (ok) {
4287 extra_type_iterate(pextra) {
4288 pextra->bridged = extra_type_list_new();
4290 if (BV_ISSET(pextra->bridged_over, pbridged->id)) {
4291 extra_type_list_append(pextra->bridged, pbridged);
4292 }
4295 }
4296
4297 if (ok) {
4298 /* Tiledef details */
4300 int tdidx = tiledef_index(td);
4302 const char **slist;
4303 int ej;
4304 const char *flag_name;
4305
4306 flag_name = secfile_lookup_str_default(file, nullptr,
4307 "%s.terrain_flag", section);
4308
4309 if (flag_name == nullptr) {
4310 td->terr_flag = terrain_flag_id_invalid();
4311 } else {
4313
4314 if (!terrain_flag_id_is_valid(td->terr_flag)) {
4315 ruleset_error(nullptr, LOG_ERROR,
4316 "%s: Invalid terrain flag %s.",
4318 ok = FALSE;
4319 break;
4320 }
4321 }
4322
4323 slist = secfile_lookup_str_vec(file, &nval, "%s.extras", section);
4324 for (ej = 0; ej < nval; ej++) {
4325 const char *sval = slist[ej];
4326 struct extra_type *pextra = extra_type_by_rule_name(sval);
4327
4328 if (pextra != nullptr) {
4330 if (pextra == old_extra) {
4331 ruleset_error(nullptr, LOG_ERROR,
4332 "%s: Duplicate extra %s.",
4333 section, extra_rule_name(pextra));
4334 ok = FALSE;
4335 break;
4336 }
4338
4339 if (ok) {
4340 extra_type_list_append(td->extras, pextra);
4341 }
4342 } else {
4343 ruleset_error(nullptr, LOG_ERROR,
4344 "%s: Unknown extra name \"%s\".",
4345 section, sval);
4346 ok = FALSE;
4347 }
4348
4349 if (ok) {
4350 td->known = secfile_lookup_bool_default(file, FALSE,
4351 "%s.known", section);
4352 td->owned = secfile_lookup_bool_default(file, FALSE,
4353 "%s.owned", section);
4354 }
4355
4356 if (!ok) {
4357 break;
4358 }
4359 }
4361 }
4362
4363 if (ok) {
4365 }
4366
4367 return ok;
4368}
4369
4370/**********************************************************************/
4374static bool load_government_names(struct section_file *file,
4375 struct rscompat_info *compat)
4376{
4377 int nval = 0;
4378 struct section_list *sec;
4379 const char *filename = secfile_name(file);
4380 bool ok = TRUE;
4381 const char *flag;
4382 int i;
4383
4384 if (!rscompat_check_cap_and_version(file, filename, compat)) {
4385 return FALSE;
4386 }
4387
4388 secfile_entry_ignore_by_path(file, "datafile.description"); /* Unused */
4389 secfile_entry_ignore_by_path(file, "datafile.ruledit"); /* Unused */
4390
4392 if (sec == nullptr || 0 == (nval = section_list_size(sec))) {
4393 ruleset_error(nullptr, LOG_ERROR, "\"%s\": No governments?!?", filename);
4394 ok = FALSE;
4395 } else if (nval > G_LAST) {
4396 ruleset_error(nullptr, LOG_ERROR,
4397 "\"%s\": Too many governments (%d, max %d)",
4398 filename, nval, G_LAST);
4399 ok = FALSE;
4400 }
4401
4402 if (ok) {
4404
4405 /* Government names are needed early so that get_government_by_name will
4406 * work. */
4407 governments_iterate(gov) {
4408 const char *sec_name =
4410
4411 if (!ruleset_load_names(&gov->name, nullptr, file, sec_name)) {
4412 ok = FALSE;
4413 break;
4414 }
4416 }
4417
4419
4420 if (ok) {
4422 nval = (sec != nullptr ? section_list_size(sec) : 0);
4423
4424 if (nval > MAX_NUM_MULTIPLIERS) {
4425 ruleset_error(nullptr, LOG_ERROR,
4426 "\"%s\": Too many multipliers (%d, max %d)",
4427 filename, nval, MAX_NUM_MULTIPLIERS);
4428
4429 ok = FALSE;
4430 } else {
4432 }
4433
4434 if (ok) {
4435 multipliers_iterate(pmul) {
4436 const char *sec_name
4438
4439 if (!ruleset_load_names(&pmul->name, nullptr, file, sec_name)) {
4440 ruleset_error(nullptr, LOG_ERROR,
4441 "\"%s\": Cannot load multiplier names",
4442 filename);
4443 ok = FALSE;
4444 break;
4445 }
4447 }
4448 }
4449
4450 /* User government flag names */
4451 for (i = 0;
4452 (flag = secfile_lookup_str_default(file, nullptr,
4453 "control.flags%d.name",
4454 i));
4455 i++) {
4456 const char *helptxt = secfile_lookup_str_default(file, nullptr,
4457 "control.flags%d.helptxt", i);
4458
4460 != gov_flag_id_invalid()) {
4461 ruleset_error(nullptr, LOG_ERROR,
4462 "\"%s\": Duplicate government flag name '%s'",
4463 filename, flag);
4464 ok = FALSE;
4465 break;
4466 }
4468 ruleset_error(nullptr, LOG_ERROR,
4469 "\"%s\": Too many user government flags!",
4470 filename);
4471 ok = FALSE;
4472 break;
4473 }
4474
4475 set_user_gov_flag_name(GOVF_USER_FLAG_1 + i, flag, helptxt);
4476 }
4477
4479
4480 return ok;
4481}
4482
4483/**********************************************************************/
4487 struct rscompat_info *compat)
4488{
4489 struct section_list *sec;
4490 const char *filename = secfile_name(file);
4491 bool ok = TRUE;
4492
4494
4496 = lookup_government(file, "governments.during_revolution", filename, nullptr);
4497 if (game.government_during_revolution == nullptr) {
4498 ok = FALSE;
4499 }
4500
4501 if (ok) {
4504
4505 /* Easy ones: */
4507 const int i = government_index(g);
4508 const char *sec_name = section_name(section_list_get(sec, i));
4509 struct requirement_vector *reqs
4510 = lookup_req_list(file, sec_name, "reqs", government_rule_name(g));
4511 const char **slist;
4512 int j;
4513 const char *sval;
4514 size_t nval;
4515
4516 if (reqs == nullptr) {
4517 ok = FALSE;
4518 break;
4519 }
4520
4521 if (secfile_entry_lookup(file, "%s.ai_better", sec_name) != nullptr) {
4522 char entry[100];
4523
4524 fc_snprintf(entry, sizeof(entry), "%s.ai_better", sec_name);
4525 g->ai.better = lookup_government(file, entry, filename, nullptr);
4526 if (g->ai.better == nullptr) {
4527 ok = FALSE;
4528 break;
4529 }
4530 } else {
4531 g->ai.better = nullptr;
4532 }
4533 requirement_vector_copy(&g->reqs, reqs);
4534
4535 sz_strlcpy(g->graphic_str,
4536 secfile_lookup_str(file, "%s.graphic", sec_name));
4537 sz_strlcpy(g->graphic_alt,
4538 secfile_lookup_str(file, "%s.graphic_alt", sec_name));
4539 sz_strlcpy(g->sound_str,
4540 secfile_lookup_str_default(file, "-", "%s.sound", sec_name));
4541 sz_strlcpy(g->sound_alt,
4542 secfile_lookup_str_default(file, "-", "%s.sound_alt", sec_name));
4543 sz_strlcpy(g->sound_alt2,
4544 secfile_lookup_str_default(file, "-", "%s.sound_alt2", sec_name));
4545
4546 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name);
4547 BV_CLR_ALL(g->flags);
4548 for (j = 0; j < nval; j++) {
4549 enum gov_flag_id flag;
4550
4551 sval = slist[j];
4553 if (!gov_flag_id_is_valid(flag)) {
4554 ruleset_error(nullptr, LOG_ERROR,
4555 "\"%s\" government \"%s\": unknown flag \"%s\".",
4556 filename, government_rule_name(g), sval);
4557 ok = FALSE;
4558 break;
4559 } else {
4560 BV_SET(g->flags, flag);
4561 }
4562 }
4563 free(slist);
4564
4565 g->helptext = lookup_strvec(file, sec_name, "helptext");
4567 }
4568
4569
4570 if (ok) {
4571 /* Titles */
4573 const char *sec_name
4575 const char *male, *female;
4576
4577 if (!(male = secfile_lookup_str(file, "%s.ruler_male_title", sec_name))
4578 || !(female = secfile_lookup_str(file, "%s.ruler_female_title",
4579 sec_name))) {
4580 ruleset_error(nullptr, LOG_ERROR,
4581 "Lack of default ruler titles for "
4582 "government \"%s\" (nb %d): %s",
4584 secfile_error());
4585 ok = FALSE;
4586 break;
4587 } else if (government_ruler_title_new(g, nullptr, male, female) == nullptr) {
4588 ruleset_error(nullptr, LOG_ERROR,
4589 "Lack of default ruler titles for "
4590 "government \"%s\" (nb %d).",
4592 ok = FALSE;
4593 break;
4594 }
4596 }
4597
4599
4600 if (ok) {
4602 multipliers_iterate(pmul) {
4603 int id = multiplier_index(pmul);
4604 const char *sec_name = section_name(section_list_get(sec, id));
4605 struct requirement_vector *reqs;
4606
4607 if (!secfile_lookup_int(file, &pmul->start, "%s.start", sec_name)) {
4608 ruleset_error(nullptr, LOG_ERROR, "Error: %s", secfile_error());
4609 ok = FALSE;
4610 break;
4611 }
4612 if (!secfile_lookup_int(file, &pmul->stop, "%s.stop", sec_name)) {
4613 ruleset_error(nullptr, LOG_ERROR, "Error: %s", secfile_error());
4614 ok = FALSE;
4615 break;
4616 }
4617 if (pmul->stop <= pmul->start) {
4618 ruleset_error(nullptr, LOG_ERROR,
4619 "Multiplier \"%s\" stop (%d) must be greater "
4620 "than start (%d)", multiplier_rule_name(pmul),
4621 pmul->stop, pmul->start);
4622 ok = FALSE;
4623 break;
4624 }
4625 if (!secfile_lookup_int(file, &pmul->step, "%s.step", sec_name)) {
4626 ruleset_error(nullptr, LOG_ERROR, "Error: %s", secfile_error());
4627 ok = FALSE;
4628 break;
4629 }
4630 if (((pmul->stop - pmul->start) % pmul->step) != 0) {
4631 ruleset_error(nullptr, LOG_ERROR,
4632 "Multiplier \"%s\" step (%d) does not fit "
4633 "exactly into interval start-stop (%d to %d)",
4634 multiplier_rule_name(pmul), pmul->step,
4635 pmul->start, pmul->stop);
4636 ok = FALSE;
4637 break;
4638 }
4639 if (!secfile_lookup_int(file, &pmul->def, "%s.default", sec_name)) {
4640 ruleset_error(nullptr, LOG_ERROR, "Error: %s", secfile_error());
4641 ok = FALSE;
4642 break;
4643 }
4644 if (pmul->def < pmul->start || pmul->def > pmul->stop) {
4645 ruleset_error(nullptr, LOG_ERROR,
4646 "Multiplier \"%s\" default (%d) not within "
4647 "legal range (%d to %d)", multiplier_rule_name(pmul),
4648 pmul->def, pmul->start, pmul->stop);
4649 ok = FALSE;
4650 break;
4651 }
4652 if (((pmul->def - pmul->start) % pmul->step) != 0) {
4653 ruleset_error(nullptr, LOG_ERROR,
4654 "Multiplier \"%s\" default (%d) not legal "
4655 "with respect to step size %d",
4656 multiplier_rule_name(pmul), pmul->def, pmul->step);
4657 ok = FALSE;
4658 break;
4659 }
4660 pmul->offset = secfile_lookup_int_default(file, 0,
4661 "%s.offset", sec_name);
4662 pmul->factor = secfile_lookup_int_default(file, 100,
4663 "%s.factor", sec_name);
4664 if (pmul->factor == 0) {
4665 ruleset_error(nullptr, LOG_ERROR,
4666 "Multiplier \"%s\" scaling factor must "
4667 "not be zero", multiplier_rule_name(pmul));
4668 ok = FALSE;
4669 break;
4670 }
4671
4672 pmul->minimum_turns = secfile_lookup_int_default(file, 0,
4673 "%s.minimum_turns",
4674 sec_name);
4675
4676 reqs = lookup_req_list(file, sec_name, "reqs",
4677 multiplier_rule_name(pmul));
4678 if (reqs == nullptr) {
4679 ok = FALSE;
4680 break;
4681 }
4682 requirement_vector_copy(&pmul->reqs, reqs);
4683
4684 pmul->helptext = lookup_strvec(file, sec_name, "helptext");
4687 }
4688
4689 if (ok) {
4691 }
4692
4693 return ok;
4694}
4695
4696/**********************************************************************/
4707static void send_ruleset_control(struct conn_list *dest)
4708{
4710 int idx = 0;
4711
4713
4714 if (game.ruleset_summary != nullptr) {
4715 struct packet_ruleset_summary summary;
4716
4718
4719 lsend_packet_ruleset_summary(dest, &summary);
4720 }
4721
4722 while (desc_left > 0) {
4724 int this_len = desc_left;
4725
4726 if (this_len > MAX_LEN_CONTENT - 21) {
4728 }
4729
4730 part.text[this_len] = '\0';
4731
4733 idx += this_len;
4735
4737 }
4738}
4739
4740/**********************************************************************/
4745static const char *check_leader_names(struct nation_type *pnation)
4746{
4748 const char *name = nation_leader_name(pleader);
4749
4751 if (prev_leader == pleader) {
4752 break;
4753 } else if (0 == fc_strcasecmp(name, nation_leader_name(prev_leader))) {
4754 return name;
4755 }
4758
4759 return nullptr;
4760}
4761
4762/**********************************************************************/
4766static bool load_nation_names(struct section_file *file,
4767 struct rscompat_info *compat)
4768{
4769 struct section_list *sec;
4770 int j;
4771 bool ok = TRUE;
4772 const char *filename = secfile_name(file);
4773
4774 if (!rscompat_check_cap_and_version(file, filename, compat)) {
4775 return FALSE;
4776 }
4777
4778 secfile_entry_ignore_by_path(file, "datafile.description"); /* Unused */
4779 secfile_entry_ignore_by_path(file, "datafile.ruledit"); /* Unused */
4780
4782 if (sec == nullptr) {
4783 ruleset_error(nullptr, LOG_ERROR,
4784 "No available nations in this ruleset!");
4785 ok = FALSE;
4786 } else if (section_list_size(sec) > MAX_NUM_NATIONS) {
4787 ruleset_error(nullptr, LOG_ERROR,
4788 "Too many nations (max %d, we have %d)!",
4790 ok = FALSE;
4791 } else {
4794
4796 const int i = nation_index(pl);
4797 const char *sec_name = section_name(section_list_get(sec, i));
4798 const char *domain = secfile_lookup_str_default(file, nullptr,
4799 "%s.translation_domain", sec_name);
4800 const char *noun_plural = secfile_lookup_str(file,
4801 "%s.plural", sec_name);
4802
4803
4804 if (domain == nullptr) {
4805 domain = "freeciv-nations";
4806 }
4807
4808 if (!strcmp("freeciv-core", domain)) {
4809 pl->translation_domain = nullptr;
4810 } else if (!strcmp("freeciv-nations", domain)) {
4811 pl->translation_domain = fc_strdup(domain);
4812 } else {
4813 ruleset_error(nullptr, LOG_ERROR,
4814 "Unsupported translation domain \"%s\" for %s",
4815 domain, sec_name);
4816 ok = FALSE;
4817 break;
4818 }
4819
4820 if (!ruleset_load_names(&pl->adjective, pl->translation_domain, file, sec_name)) {
4821 ok = FALSE;
4822 break;
4823 }
4824 name_set(&pl->noun_plural, pl->translation_domain, noun_plural);
4825
4826 /* Check if nation name is already defined. */
4827 for (j = 0; j < i && ok; j++) {
4828 struct nation_type *n2 = nation_by_number(j);
4829
4830 /* Compare strings after stripping off qualifiers -- we don't want
4831 * two nations to end up with identical adjectives displayed to users.
4832 * (This check only catches English, not localisations, of course.) */
4833 if (0 == strcmp(Qn_(untranslated_name(&n2->adjective)),
4834 Qn_(untranslated_name(&pl->adjective)))) {
4835 ruleset_error(nullptr, LOG_ERROR,
4836 "Two nations defined with the same adjective \"%s\": "
4837 "in section \'%s\' and section \'%s\'",
4838 Qn_(untranslated_name(&pl->adjective)),
4840 ok = FALSE;
4841 } else if (!strcmp(rule_name_get(&n2->adjective),
4842 rule_name_get(&pl->adjective))) {
4843 /* We cannot have the same rule name, as the game needs them to be
4844 * distinct. */
4845 ruleset_error(nullptr, LOG_ERROR,
4846 "Two nations defined with the same rule_name \"%s\": "
4847 "in section \'%s\' and section \'%s\'",
4848 rule_name_get(&pl->adjective),
4850 ok = FALSE;
4851 } else if (0 == strcmp(Qn_(untranslated_name(&n2->noun_plural)),
4852 Qn_(untranslated_name(&pl->noun_plural)))) {
4853 /* We don't want identical English plural names either. */
4854 ruleset_error(nullptr, LOG_ERROR,
4855 "Two nations defined with the same plural name \"%s\": "
4856 "in section \'%s\' and section \'%s\'",
4857 Qn_(untranslated_name(&pl->noun_plural)),
4859 ok = FALSE;
4860 }
4861 }
4862 if (!ok) {
4863 break;
4864 }
4866 }
4867
4869
4870 if (ok) {
4872 if (sec != nullptr) {
4874
4875 section_list_iterate(sec, psection) {
4876 struct nation_group *pgroup;
4877 const char *name;
4878
4879 name = secfile_lookup_str(file, "%s.name", section_name(psection));
4880 if (name == nullptr) {
4881 ruleset_error(nullptr, LOG_ERROR, "Error: %s", secfile_error());
4882 ok = FALSE;
4883 break;
4884 }
4886 if (pgroup == nullptr) {
4887 ok = FALSE;
4888 break;
4889 }
4892 sec = nullptr;
4893 }
4894 }
4895
4896 return ok;
4897}
4898
4899/**********************************************************************/
4902static bool is_on_allowed_list(const char *name, const char **list, size_t len)
4903{
4904 int i;
4905
4906 for (i = 0; i < len; i++) {
4907 if (!fc_strcasecmp(name, list[i])) {
4908 return TRUE;
4909 }
4910 }
4911 return FALSE;
4912}
4913
4914/**********************************************************************/
4918static bool load_city_name_list(struct section_file *file,
4919 struct nation_type *pnation,
4920 const char *secfile_str1,
4921 const char *secfile_str2,
4922 const char **allowed_terrains,
4923 size_t atcount)
4924{
4925 size_t dim, j;
4926 bool ok = TRUE;
4927 const char **cities = secfile_lookup_str_vec(file, &dim, "%s.%s",
4929
4930 /* Each string will be of the form "<cityname> (<label>, <label>, ...)".
4931 * The cityname is just the name for this city, while each "label" matches
4932 * a terrain type for the city (or "river"), with a preceding ! to negate
4933 * it. The parentheses are optional (but necessary to have the settings,
4934 * of course). Our job is now to parse it. */
4935 for (j = 0; j < dim; j++) {
4936 size_t len = strlen(cities[j]);
4937 char city_name[len + 1], *p, *next, *end;
4938 struct nation_city *pncity;
4939
4941
4942 /* Now we wish to determine values for all of the city labels. A value
4943 * of NCP_NONE means no preference (which is necessary so that the use
4944 * of this is optional); NCP_DISLIKE means the label is negated and
4945 * NCP_LIKE means it's labelled. Mostly the parsing just involves
4946 * a lot of ugly string handling... */
4947 if ((p = strchr(city_name, '('))) {
4948 *p++ = '\0';
4949
4950 if (!(end = strchr(p, ')'))) {
4951 ruleset_error(nullptr, LOG_ERROR,
4952 "\"%s\" [%s] %s: city name \"%s\" "
4953 "unmatched parenthesis.", secfile_name(file),
4955 ok = FALSE;
4956 } else {
4957 for (*end++ = '\0'; '\0' != *end; end++) {
4958 if (!fc_isspace(*end)) {
4959 ruleset_error(nullptr, LOG_ERROR,
4960 "\"%s\" [%s] %s: city name \"%s\" "
4961 "contains characters after last parenthesis.",
4963 cities[j]);
4964 ok = FALSE;
4965 break;
4966 }
4967 }
4968 }
4969 }
4970
4971 /* Build the nation_city. */
4974 /* The ruleset contains a name that is too long. This shouldn't
4975 * happen - if it does, the author should get immediate feedback. */
4976 ruleset_error(nullptr, LOG_ERROR,
4977 "\"%s\" [%s] %s: city name \"%s\" is too long.",
4978 secfile_name(file),
4980 ok = FALSE;
4981 city_name[MAX_LEN_CITYNAME - 1] = '\0';
4982 }
4983 pncity = nation_city_new(pnation, city_name);
4984
4985 if (p != nullptr) {
4986 /* Handle the labels one at a time. */
4987 do {
4988 enum nation_city_preference prefer;
4989
4990 if ((next = strchr(p, ','))) {
4991 *next = '\0';
4992 }
4994
4995 /* The ! is used to mark a negative, which is recorded with
4996 * NCP_DISLIKE. Otherwise we use a NCP_LIKE.
4997 */
4998 if (*p == '!') {
4999 p++;
5000 prefer = NCP_DISLIKE;
5001 } else {
5002 prefer = NCP_LIKE;
5003 }
5004
5005 if (0 == fc_strcasecmp(p, "river")) {
5006 if (game.server.ruledit.allowed_terrains != nullptr
5007 && !is_on_allowed_list(p,
5009 ruleset_error(nullptr, LOG_ERROR,
5010 "\"%s\" [%s] %s: city \"%s\" "
5011 "has terrain hint \"%s\" not in allowed_terrains.",
5013 city_name, p);
5014 ok = FALSE;
5015 } else {
5017 }
5018 } else {
5019 const struct terrain *pterrain = terrain_by_rule_name(p);
5020
5021 if (pterrain == nullptr) {
5022 /* Try with removing frequent trailing 's'. */
5023 size_t l = strlen(p);
5024
5025 if (0 < l && 's' == fc_tolower(p[l - 1])) {
5026 char saved = p[l - 1];
5027
5028 p[l - 1] = '\0';
5029 pterrain = terrain_by_rule_name(p);
5030 if (pterrain == nullptr) {
5031 /* Didn't help, restore for later allowed_terrains check */
5032 p[l - 1] = saved;
5033 }
5034 }
5035 }
5036
5037 /* Nationset may have been devised with a specific set of terrains
5038 * in mind which don't quite match this ruleset, in which case we
5039 * (a) quietly ignore any hints mentioned that don't happen to be in
5040 * the current ruleset, (b) enforce that terrains mentioned by nations
5041 * must be on the list */
5042 if (pterrain != nullptr
5043 && game.server.ruledit.allowed_terrains != nullptr) {
5044 if (!is_on_allowed_list(p,
5046 /* Terrain exists, but not intended for these nations */
5047 ruleset_error(nullptr, LOG_ERROR,
5048 "\"%s\" [%s] %s: city \"%s\" "
5049 "has terrain hint \"%s\" not in allowed_terrains.",
5051 city_name, p);
5052 ok = FALSE;
5053 break;
5054 }
5055 } else if (!pterrain) {
5056 /* Terrain doesn't exist; only complain if it's not on any list */
5057 if (game.server.ruledit.allowed_terrains == nullptr
5058 || !is_on_allowed_list(p,
5060 ruleset_error(nullptr, LOG_ERROR,
5061 "\"%s\" [%s] %s: city \"%s\" "
5062 "has unknown terrain hint \"%s\".",
5064 city_name, p);
5065 ok = FALSE;
5066 break;
5067 }
5068 }
5069 if (pterrain != nullptr) {
5070 nation_city_set_terrain_preference(pncity, pterrain, prefer);
5071 }
5072 }
5073
5074 p = next ? next + 1 : nullptr;
5075 } while (p != nullptr && '\0' != *p);
5076 }
5077 }
5078
5079 if (cities != nullptr) {
5080 free(cities);
5081 }
5082
5083 return ok;
5084}
5085
5086/**********************************************************************/
5089static bool load_ruleset_nations(struct section_file *file,
5090 struct rscompat_info *compat)
5091{
5092 struct government *gov;
5093 int j;
5094 size_t dim;
5095 char temp_name[MAX_LEN_NAME];
5096 const char **vec;
5097 const char *name, *bad_leader;
5098 const char *sval;
5099 int default_set;
5100 const char *filename = secfile_name(file);
5101 struct section_list *sec = nullptr;
5102 enum trait tr;
5103 bool ok = TRUE;
5104
5105 name = secfile_lookup_str_default(file, nullptr, "ruledit.nationlist");
5106 if (name != nullptr) {
5108 }
5110 "ruledit.embedded_nations");
5111
5112 if (vec != nullptr) {
5113 /* Copy to persistent vector */
5116
5117 for (j = 0; j < game.server.ruledit.embedded_nations_count; j++) {
5119 }
5120
5121 free(vec);
5122 }
5123
5124 game.default_government = nullptr;
5125
5126 ruleset_load_traits(game.server.default_traits, file, "default_traits", "");
5127 for (tr = trait_begin(); tr != trait_end(); tr = trait_next(tr)) {
5128 if (game.server.default_traits[tr].min < 0) {
5130 }
5131 if (game.server.default_traits[tr].max < 0) {
5133 }
5134 if (game.server.default_traits[tr].fixed < 0) {
5136
5137 /* TODO: Should sometimes round the a / 2 = x.5 results up */
5139 }
5141 ruleset_error(nullptr, LOG_ERROR,
5142 "Default values for trait %s not sane.",
5143 trait_name(tr));
5144 ok = FALSE;
5145 break;
5146 }
5147 }
5148
5149 if (ok) {
5151 "compatibility.allowed_govs");
5152 if (vec != nullptr) {
5153 /* Copy to persistent vector */
5155 = fc_malloc(game.server.ruledit.ag_count * sizeof(char *));
5157 (const char **)game.server.ruledit.nc_agovs;
5158
5159 for (j = 0; j < game.server.ruledit.ag_count; j++) {
5161 }
5162
5163 free(vec);
5164 }
5165
5167 "compatibility.allowed_terrains");
5168 if (vec != nullptr) {
5169 /* Copy to persistent vector */
5171 = fc_malloc(game.server.ruledit.at_count * sizeof(char *));
5173 (const char **)game.server.ruledit.nc_aterrs;
5174
5175 for (j = 0; j < game.server.ruledit.at_count; j++) {
5177 }
5178
5179 free(vec);
5180 }
5181
5183 "compatibility.allowed_styles");
5184 if (vec != nullptr) {
5185 /* Copy to persistent vector */
5187 = fc_malloc(game.server.ruledit.as_count * sizeof(char *));
5189 (const char **)game.server.ruledit.nc_astyles;
5190
5191 for (j = 0; j < game.server.ruledit.as_count; j++) {
5193 }
5194
5195 free(vec);
5196 }
5197
5198 sval = secfile_lookup_str_default(file, nullptr,
5199 "compatibility.default_government");
5200 /* We deliberately don't check this against allowed_govs. It's only
5201 * specified once so not vulnerable to typos, and may usefully be set in
5202 * a specific ruleset to a gov not explicitly known by the nation set. */
5203 if (sval != nullptr) {
5205 if (game.default_government == nullptr) {
5206 ruleset_error(nullptr, LOG_ERROR,
5207 "Tried to set unknown government type \"%s\" as default_government!",
5208 sval);
5209 ok = FALSE;
5210 } else {
5213 }
5214 }
5215 }
5216
5217 if (ok) {
5219 if (sec != nullptr) {
5221
5222 section_list_iterate(sec, psection) {
5223 const char *set_name, *set_rule_name, *set_description;
5224
5225 set_name = secfile_lookup_str(file, "%s.name", section_name(psection));
5227 secfile_lookup_str(file, "%s.rule_name", section_name(psection));
5228 set_description = secfile_lookup_str_default(file, "", "%s.description",
5229 section_name(psection));
5230 if (set_name == nullptr || set_rule_name == nullptr) {
5231 ruleset_error(nullptr, LOG_ERROR, "Error: %s", secfile_error());
5232 ok = FALSE;
5233 break;
5234 }
5236 ok = FALSE;
5237 break;
5238 }
5241 sec = nullptr;
5242 } else {
5243 ruleset_error(nullptr, LOG_ERROR,
5244 "At least one nation set [" NATION_SET_SECTION_PREFIX "_*] "
5245 "must be defined.");
5246 ok = FALSE;
5247 }
5248 }
5249
5250 if (ok) {
5251 /* Default set that every nation is a member of. */
5252 sval = secfile_lookup_str_default(file, nullptr,
5253 "compatibility.default_nationset");
5254 if (sval != nullptr) {
5256
5257 if (pset != nullptr) {
5259 } else {
5260 ruleset_error(nullptr, LOG_ERROR,
5261 "Unknown default_nationset \"%s\".", sval);
5262 ok = FALSE;
5263 }
5264 } else if (nation_set_count() == 1) {
5265 /* If there's only one set defined, every nation is implicitly a
5266 * member of that set. */
5267 default_set = 0;
5268 } else {
5269 /* No default nation set; every nation must explicitly specify at
5270 * least one set to be a member of. */
5271 default_set = -1;
5272 }
5273 }
5274
5275 if (ok) {
5277 if (sec) {
5278 section_list_iterate(sec, psection) {
5279 struct nation_group *pgroup;
5280 bool hidden;
5281
5282 name = secfile_lookup_str(file, "%s.name", section_name(psection));
5284 if (pgroup == nullptr) {
5285 ok = FALSE;
5286 break;
5287 }
5288
5289 hidden = secfile_lookup_bool_default(file, FALSE, "%s.hidden",
5290 section_name(psection));
5292
5293 if (!secfile_lookup_int(file, &j, "%s.match", section_name(psection))) {
5294 ruleset_error(nullptr, LOG_ERROR, "Error: %s", secfile_error());
5295 ok = FALSE;
5296 break;
5297 }
5301 sec = nullptr;
5302 }
5303 }
5304
5305 if (ok) {
5307 nations_iterate(pnation) {
5308 struct nation_type *pconflict;
5309 const int i = nation_index(pnation);
5310 char tmp[200] = "\0";
5311 const char *barb_type;
5312 const char *sec_name = section_name(section_list_get(sec, i));
5313 const char *legend;
5314
5315 /* Nation sets and groups. */
5316 if (default_set >= 0) {
5317 nation_set_list_append(pnation->sets,
5319 }
5320 vec = secfile_lookup_str_vec(file, &dim, "%s.groups", sec_name);
5321 for (j = 0; j < dim; j++) {
5322 struct nation_set *pset = nation_set_by_rule_name(vec[j]);
5324
5325 fc_assert(pset == nullptr || pgroup == nullptr);
5326
5327 if (pset != nullptr) {
5328 nation_set_list_append(pnation->sets, pset);
5329 } else if (pgroup != nullptr) {
5330 nation_group_list_append(pnation->groups, pgroup);
5331 } else {
5332 /* For nation authors, this would probably be considered an error.
5333 * But it can happen normally. The civ1 compatibility ruleset only
5334 * uses the nations that were in civ1, so not all of the links will
5335 * exist. */
5336 log_verbose("Nation %s: Unknown set/group \"%s\".",
5337 nation_rule_name(pnation), vec[j]);
5338 }
5339 }
5340 if (vec != nullptr) {
5341 free(vec);
5342 }
5343 if (nation_set_list_size(pnation->sets) < 1) {
5344 ruleset_error(nullptr, LOG_ERROR,
5345 "Nation %s is not a member of any nation set",
5346 nation_rule_name(pnation));
5347 ok = FALSE;
5348 break;
5349 }
5350
5351 /* Nation conflicts. */
5352 vec = secfile_lookup_str_vec(file, &dim, "%s.conflicts_with", sec_name);
5353 for (j = 0; j < dim; j++) {
5355
5356 if (pnation == pconflict) {
5357 ruleset_error(nullptr, LOG_ERROR,
5358 "Nation %s conflicts with itself",
5359 nation_rule_name(pnation));
5360 ok = FALSE;
5361 break;
5362 } else if (pconflict != nullptr) {
5363 nation_list_append(pnation->server.conflicts_with, pconflict);
5364 } else {
5365 /* For nation authors, this would probably be considered an error.
5366 * But it can happen normally. The civ1 compatibility ruleset only
5367 * uses the nations that were in civ1, so not all of the links will
5368 * exist. */
5369 log_verbose("Nation %s: conflicts_with nation \"%s\" is unknown.",
5370 nation_rule_name(pnation), vec[j]);
5371 }
5372 }
5373 if (vec != nullptr) {
5374 free(vec);
5375 }
5376 if (!ok) {
5377 break;
5378 }
5379
5380 /* Nation leaders. */
5381 for (j = 0; j < MAX_NUM_LEADERS; j++) {
5382 const char *sexstr;
5383 sex_t sex;
5384 bool is_male = FALSE;
5385
5386 name = secfile_lookup_str(file, "%s.leaders%d.name", sec_name, j);
5387 if (name == nullptr) {
5388 /* No more to read. */
5389 break;
5390 }
5391
5392 if (check_name(name)) {
5393 /* The ruleset contains a name that is too long. This shouldn't
5394 * happen - if it does, the author should get immediate feedback */
5396 ruleset_error(nullptr, LOG_ERROR,
5397 "Nation %s: leader name \"%s\" is too long.",
5398 nation_rule_name(pnation), name);
5399 ok = FALSE;
5400 break;
5401 }
5402
5403 sexstr = secfile_lookup_str(file, "%s.leaders%d.sex", sec_name, j);
5404 if (sexstr == nullptr) {
5405 ruleset_error(nullptr, LOG_ERROR,
5406 "Nation %s: leader \"%s\": %s.",
5407 nation_rule_name(pnation), name, secfile_error());
5408 ok = FALSE;
5409 break;
5410 }
5411
5413
5414 switch (sex) {
5415 case SEX_MALE:
5416 is_male = TRUE;
5417 break;
5418 case SEX_FEMALE:
5419 is_male = FALSE;
5420 break;
5421 case SEX_UNKNOWN:
5422 ruleset_error(nullptr, LOG_ERROR,
5423 "Nation %s: leader \"%s\" has unsupported "
5424 "sex variant \"%s\".",
5425 nation_rule_name(pnation), name, sexstr);
5426 ok = FALSE;
5427 break;
5428 }
5429
5430 if (ok) {
5431 (void) nation_leader_new(pnation, name, is_male);
5432 }
5433 }
5434 if (!ok) {
5435 break;
5436 }
5437
5438 /* Check the number of leaders. */
5439 if (j == MAX_NUM_LEADERS) {
5440 /* Too much leaders, get the real number defined in the ruleset. */
5441 while (secfile_entry_lookup(file, "%s.leaders%d.name",
5442 sec_name, j) != nullptr) {
5443 j++;
5444 }
5445 ruleset_error(nullptr, LOG_ERROR,
5446 "Nation %s: Too many leaders; max is %d",
5448 ok = FALSE;
5449 break;
5450 } else if (j == 0) {
5451 ruleset_error(nullptr, LOG_ERROR,
5452 "Nation %s: no leaders; at least one is required.",
5453 nation_rule_name(pnation));
5454 ok = FALSE;
5455 break;
5456 }
5457
5458 /* Check if leader name is not already defined in this nation. */
5459 if ((bad_leader = check_leader_names(pnation))) {
5460 ruleset_error(nullptr, LOG_ERROR,
5461 "Nation %s: leader \"%s\" defined more than once.",
5462 nation_rule_name(pnation), bad_leader);
5463 ok = FALSE;
5464 break;
5465 }
5466
5467 /* Nation player color preference, if any */
5468 fc_assert_ret_val(pnation->server.rgb == nullptr, FALSE);
5469 (void) rgbcolor_load(file, &pnation->server.rgb, "%s.color", sec_name);
5470
5471 /* Load nation traits */
5472 ruleset_load_traits(pnation->server.traits, file, sec_name, "trait_");
5473 for (tr = trait_begin(); tr != trait_end(); tr = trait_next(tr)) {
5474 bool server_traits_used = TRUE;
5475
5476 if (pnation->server.traits[tr].min < 0) {
5477 pnation->server.traits[tr].min = game.server.default_traits[tr].min;
5478 } else {
5480 }
5481 if (pnation->server.traits[tr].max < 0) {
5482 pnation->server.traits[tr].max = game.server.default_traits[tr].max;
5483 } else {
5485 }
5486 if (pnation->server.traits[tr].fixed < 0) {
5487 if (server_traits_used) {
5488 pnation->server.traits[tr].fixed = game.server.default_traits[tr].fixed;
5489 } else {
5490 int diff = pnation->server.traits[tr].max - pnation->server.traits[tr].min;
5491
5492 /* TODO: Should sometimes round the a / 2 = x.5 results up */
5493 pnation->server.traits[tr].fixed = diff / 2 + pnation->server.traits[tr].min;
5494 }
5495 }
5496 if (pnation->server.traits[tr].max < pnation->server.traits[tr].min) {
5497 ruleset_error(nullptr, LOG_ERROR,
5498 "%s values for trait %s not sane.",
5499 nation_rule_name(pnation), trait_name(tr));
5500 ok = FALSE;
5501 break;
5502 }
5503 }
5504
5505 if (!ok) {
5506 break;
5507 }
5508
5509 pnation->is_playable =
5510 secfile_lookup_bool_default(file, TRUE, "%s.is_playable", sec_name);
5511
5512 /* Check barbarian type. Default is "None" meaning not a barbarian */
5513 barb_type = secfile_lookup_str_default(file, "None",
5514 "%s.barbarian_type", sec_name);
5515 pnation->barb_type = barbarian_type_by_name(barb_type, fc_strcasecmp);
5516 if (!barbarian_type_is_valid(pnation->barb_type)) {
5517 ruleset_error(nullptr, LOG_ERROR,
5518 "Nation %s, barbarian_type is invalid (\"%s\")",
5519 nation_rule_name(pnation), barb_type);
5520 ok = FALSE;
5521 break;
5522 }
5523
5524 if (pnation->barb_type != NOT_A_BARBARIAN
5525 && pnation->is_playable) {
5526 /* We can't allow players to use barbarian nations, barbarians
5527 * may run out of nations */
5528 ruleset_error(nullptr, LOG_ERROR,
5529 "Nation %s marked both barbarian and playable.",
5530 nation_rule_name(pnation));
5531 ok = FALSE;
5532 break;
5533 }
5534
5535 /* Flags */
5536 sz_strlcpy(pnation->flag_graphic_str,
5537 secfile_lookup_str_default(file, "-", "%s.flag", sec_name));
5538 sz_strlcpy(pnation->flag_graphic_alt,
5540 "%s.flag_alt", sec_name));
5541
5542 /* Ruler titles */
5543 for (j = 0;; j++) {
5544 const char *male, *female;
5545
5546 name = secfile_lookup_str_default(file, nullptr,
5547 "%s.ruler_titles%d.government",
5548 sec_name, j);
5549 if (name == nullptr) {
5550 /* End of the list of ruler titles. */
5551 break;
5552 }
5553
5554 /* NB: Even if the government doesn't exist, we load the entries for
5555 * the ruler titles to avoid warnings about unused entries. */
5556 male = secfile_lookup_str(file, "%s.ruler_titles%d.male_title",
5557 sec_name, j);
5558 female = secfile_lookup_str(file, "%s.ruler_titles%d.female_title",
5559 sec_name, j);
5561
5562 /* Nationset may have been devised with a specific set of govs in
5563 * mind which don't quite match this ruleset, in which case we
5564 * (a) quietly ignore any govs mentioned that don't happen to be in
5565 * the current ruleset, (b) enforce that govs mentioned by nations
5566 * must be on the list */
5567 if (gov != nullptr && game.server.ruledit.allowed_govs != nullptr) {
5571 /* Gov exists, but not intended for these nations */
5572 gov = nullptr;
5573 ruleset_error(nullptr, LOG_ERROR,
5574 "Nation %s: government \"%s\" not in allowed_govs.",
5575 nation_rule_name(pnation), name);
5576 ok = FALSE;
5577 break;
5578 }
5579 } else if (!gov) {
5580 /* Gov doesn't exist; only complain if it's not on any list */
5581 if (game.server.ruledit.allowed_govs == nullptr
5585 ruleset_error(nullptr, LOG_ERROR,
5586 "Nation %s: government \"%s\" not found.",
5587 nation_rule_name(pnation), name);
5588 ok = FALSE;
5589 break;
5590 }
5591 }
5592 if (male != nullptr && female != nullptr) {
5593 if (gov) {
5594 (void) government_ruler_title_new(gov, pnation, male, female);
5595 }
5596 } else {
5597 ruleset_error(nullptr, LOG_ERROR, "%s", secfile_error());
5598 ok = FALSE;
5599 break;
5600 }
5601 }
5602 if (!ok) {
5603 break;
5604 }
5605
5606 /* City styles */
5607 name = secfile_lookup_str(file, "%s.style", sec_name);
5608 if (!name) {
5609 ruleset_error(nullptr, LOG_ERROR, "%s", secfile_error());
5610 ok = FALSE;
5611 break;
5612 }
5613 pnation->style = style_by_rule_name(name);
5614 if (pnation->style == nullptr) {
5615 if (game.server.ruledit.allowed_styles == nullptr
5619 ruleset_error(nullptr, LOG_ERROR,
5620 "Nation %s: Illegal style \"%s\"",
5621 nation_rule_name(pnation), name);
5622 ok = FALSE;
5623 break;
5624 } else {
5625 log_verbose("Nation %s: style \"%s\" not supported in this "
5626 "ruleset; using default.",
5627 nation_rule_name(pnation), name);
5628 pnation->style = style_by_number(0);
5629 }
5630 }
5631
5632 /* Civilwar nations */
5633 vec = secfile_lookup_str_vec(file, &dim,
5634 "%s.civilwar_nations", sec_name);
5635 for (j = 0; j < dim; j++) {
5637
5638 /* No test for duplicate nations is performed. If there is a duplicate
5639 * entry it will just cause that nation to have an increased
5640 * probability of being chosen. */
5641 if (pconflict == pnation) {
5642 ruleset_error(nullptr, LOG_ERROR,
5643 "Nation %s is its own civil war nation",
5644 nation_rule_name(pnation));
5645 ok = FALSE;
5646 break;
5647 } else if (pconflict != nullptr) {
5648 nation_list_append(pnation->server.civilwar_nations, pconflict);
5649 nation_list_append(pconflict->server.parent_nations, pnation);
5650 } else {
5651 /* For nation authors, this would probably be considered an error.
5652 * But it can happen normally. The civ1 compatibility ruleset only
5653 * uses the nations that were in civ1, so not all of the links will
5654 * exist. */
5655 log_verbose("Nation %s: civil war nation \"%s\" is unknown.",
5656 nation_rule_name(pnation), vec[j]);
5657 }
5658 }
5659 if (vec != nullptr) {
5660 free(vec);
5661 }
5662 if (!ok) {
5663 break;
5664 }
5665
5666 /* Load nation specific initial items */
5667 if (!lookup_tech_list(file, sec_name, "init_techs",
5668 pnation->init_techs, filename)) {
5669 ok = FALSE;
5670 break;
5671 }
5672 if (!lookup_building_list(file, sec_name, "init_buildings",
5673 pnation->init_buildings, filename)) {
5674 ok = FALSE;
5675 break;
5676 }
5677 if (!lookup_unit_list(file, sec_name, "init_units",
5678 pnation->init_units, filename)) {
5679 ok = FALSE;
5680 break;
5681 }
5682 fc_strlcat(tmp, sec_name, 200);
5683 fc_strlcat(tmp, ".init_government", 200);
5684 if (secfile_entry_by_path(file, tmp)) {
5685 pnation->init_government = lookup_government(file, tmp, filename,
5686 nullptr);
5687 /* If specified, init_government has to be in this specific ruleset,
5688 * not just allowed_govs */
5689 if (pnation->init_government == nullptr) {
5690 ok = FALSE;
5691 break;
5692 }
5693 /* ...but if a list of govs has been specified, enforce that this
5694 * nation's init_government is on the list. */
5695 if (game.server.ruledit.allowed_govs != nullptr
5696 && !is_on_allowed_list(government_rule_name(pnation->init_government),
5699 ruleset_error(nullptr, LOG_ERROR,
5700 "Nation %s: init_government \"%s\" not allowed.",
5701 nation_rule_name(pnation),
5702 government_rule_name(pnation->init_government));
5703 ok = FALSE;
5704 break;
5705 }
5706 }
5707
5708 /* Read default city names. */
5709 if (!load_city_name_list(file, pnation, sec_name, "cities",
5712 ok = FALSE;
5713 break;
5714 }
5715
5716 legend = secfile_lookup_str_default(file, "", "%s.legend", sec_name);
5717 pnation->legend = fc_strdup(legend);
5718 if (check_strlen(pnation->legend, MAX_LEN_MSG, nullptr)) {
5719 ruleset_error(nullptr, LOG_ERROR,
5720 "Nation %s: legend \"%s\" is too long.",
5721 nation_rule_name(pnation),
5722 pnation->legend);
5723 ok = FALSE;
5724 break;
5725 }
5726
5727 pnation->player = nullptr;
5730 sec = nullptr;
5731 }
5732
5733 /* Clean up on aborted load */
5734 if (sec != nullptr) {
5735 fc_assert(!ok);
5737 }
5738
5739 if (ok) {
5741 }
5742
5743 if (ok) {
5744 /* Update cached number of playable nations in the current set */
5746
5747 /* Sanity checks on all sets */
5750
5751 nations_iterate(pnation) {
5752 if (nation_is_in_set(pnation, pset)) {
5753 switch (nation_barbarian_type(pnation)) {
5754 case NOT_A_BARBARIAN:
5755 if (is_nation_playable(pnation)) {
5756 num_playable++;
5757 }
5758 break;
5759 case LAND_BARBARIAN:
5761 break;
5762 case SEA_BARBARIAN:
5764 break;
5765 case ANIMAL_BARBARIAN:
5766 /* Animals are optional */
5767 break;
5770 break;
5771 default:
5773 }
5774 }
5776 if (num_playable < 1) {
5777 ruleset_error(nullptr, LOG_ERROR,
5778 "Nation set \"%s\" has no playable nations. "
5779 "At least one required!", nation_set_rule_name(pset));
5780 ok = FALSE;
5781 break;
5782 }
5783 if (barb_land_count == 0 && barb_both_count == 0) {
5784 ruleset_error(nullptr, LOG_ERROR,
5785 "No land barbarian nation defined in set \"%s\". "
5786 "At least one required!", nation_set_rule_name(pset));
5787 ok = FALSE;
5788 break;
5789 }
5790 if (barb_sea_count == 0 && barb_both_count == 0) {
5791 ruleset_error(nullptr, LOG_ERROR,
5792 "No sea barbarian nation defined in set \"%s\". "
5793 "At least one required!", nation_set_rule_name(pset));
5794 ok = FALSE;
5795 break;
5796 }
5798 }
5799
5800 return ok;
5801}
5802
5803/**********************************************************************/
5807static bool load_style_names(struct section_file *file,
5808 struct rscompat_info *compat)
5809{
5810 bool ok = TRUE;
5811 struct section_list *sec;
5812 const char *filename = secfile_name(file);
5813
5814 if (!rscompat_check_cap_and_version(file, filename, compat)) {
5815 return FALSE;
5816 }
5817
5818 secfile_entry_ignore_by_path(file, "datafile.description"); /* Unused */
5819 secfile_entry_ignore_by_path(file, "datafile.ruledit"); /* Unused */
5820
5822 if (sec == nullptr) {
5823 ruleset_error(nullptr, LOG_ERROR,
5824 "No available nation styles in this ruleset!");
5825 ok = FALSE;
5826 } else {
5828
5830
5832 const int i = style_index(ps);
5833 const char *sec_name = section_name(section_list_get(sec, i));
5834
5835 ruleset_load_names(&ps->name, nullptr, file, sec_name);
5837 }
5838
5840
5841 if (ok) {
5842 /* The citystyle sections: */
5843 int i = 0;
5844
5846 if (sec != nullptr) {
5848 section_list_iterate(sec, style) {
5849 if (!ruleset_load_names(&city_styles[i].name, nullptr, file,
5850 section_name(style))) {
5851 ok = FALSE;
5852 break;
5853 }
5854 i++;
5856
5858 } else {
5860 }
5861 }
5862
5863 return ok;
5864}
5865
5866/**********************************************************************/
5869static bool load_ruleset_styles(struct section_file *file,
5870 struct rscompat_info *compat)
5871{
5872 struct section_list *sec;
5873 int i;
5874 bool ok = TRUE;
5875
5876 /* City Styles ... */
5877
5879
5880 /* Get rest: */
5881 for (i = 0; i < game.control.num_city_styles; i++) {
5882 struct requirement_vector *reqs;
5883 const char *sec_name = section_name(section_list_get(sec, i));
5884
5885 sz_strlcpy(city_styles[i].graphic,
5886 secfile_lookup_str(file, "%s.graphic", sec_name));
5887 sz_strlcpy(city_styles[i].graphic_alt,
5888 secfile_lookup_str(file, "%s.graphic_alt", sec_name));
5889 sz_strlcpy(city_styles[i].citizens_graphic,
5891 "%s.citizens_graphic", sec_name));
5892
5894 if (reqs == nullptr) {
5895 ok = FALSE;
5896 break;
5897 }
5899 }
5900
5902
5903 if (ok) {
5905
5906 if (sec != nullptr) {
5907 int musi;
5908
5911 musi = 0;
5912
5913 section_list_iterate(sec, psection) {
5914 struct requirement_vector *reqs;
5916 const char *sec_name = section_name(psection);
5917
5918 sz_strlcpy(pmus->music_peaceful,
5920 "%s.music_peaceful", sec_name));
5921 sz_strlcpy(pmus->music_combat,
5923 "%s.music_combat", sec_name));
5924
5925 reqs = lookup_req_list(file, sec_name, "reqs", "Music Style");
5926 if (reqs == nullptr) {
5927 ok = FALSE;
5928 break;
5929 }
5931
5932 musi++;
5934 }
5935
5937 }
5938
5939 return ok;
5940}
5941
5942/**********************************************************************/
5949 const char *uflags_path,
5950 const char *filename)
5951{
5952 /* Add each listed protected unit type flag as a !present
5953 * requirement. */
5954 if (secfile_entry_lookup(file, "%s", uflags_path)) {
5956 size_t psize;
5957 int i;
5958
5961 "%s", uflags_path);
5962
5963 if (!protecor_flag) {
5964 /* Entity exists but couldn't read it. */
5965 ruleset_error(nullptr, LOG_ERROR,
5966 "\"%s\": %s: bad unit type flag list.",
5967 filename, uflags_path);
5968
5969 return FALSE;
5970 }
5971
5972 for (i = 0; i < psize; i++) {
5976 FALSE, FALSE, TRUE,
5977 protecor_flag[i]));
5978 }
5979
5981 }
5982
5983 return TRUE;
5984}
5985
5986/**********************************************************************/
5992 const char *actions_path,
5993 const char *filename)
5994{
5995 /* Read the alternative actions. */
5996 if (secfile_entry_lookup(file, "%s", actions_path)) {
5997 enum gen_action *unit_acts;
5998 size_t asize;
5999 int i;
6000
6002 "%s", actions_path);
6003
6004 if (!unit_acts) {
6005 /* Entity exists but couldn't read it. */
6006 ruleset_error(nullptr, LOG_ERROR,
6007 "\"%s\": %s: bad action list",
6008 filename, actions_path);
6009
6010 return FALSE;
6011 }
6012
6013 for (i = 0; i < asize; i++) {
6014 auto_perf->alternatives[i] = unit_acts[i];
6015 }
6016
6017 free(unit_acts);
6018 }
6019
6020 return TRUE;
6021}
6022
6023/**********************************************************************/
6028 const char *item,
6029 const char *filename)
6030{
6031 char uflags_path[100];
6032 char action_path[100];
6033
6035 "missing_unit_upkeep.%s_protected", item);
6037 "missing_unit_upkeep.%s_unit_act", item);
6038
6040 filename)
6042 filename));
6043}
6044
6045/**********************************************************************/
6049static bool load_specialist(const struct section *psection,
6050 struct specialist *s,
6051 struct section_file *file)
6052{
6053 struct requirement_vector *reqs;
6054 const char *sec_name = section_name(psection);
6055 const char *item, *tag;
6056
6057 if (!ruleset_load_names(&s->name, nullptr, file, sec_name)) {
6058 return FALSE;
6059 }
6060
6062 "%s.short_name", sec_name);
6063 name_set(&s->abbreviation, nullptr, item);
6064
6065 tag = secfile_lookup_str(file, "%s.graphic", sec_name);
6066 if (nullptr == tag) {
6067 ruleset_error(nullptr, LOG_ERROR,
6068 "\"%s\": No graphic tag for specialist at %s.",
6069 secfile_name(file), sec_name);
6070 return FALSE;
6071 }
6072 sz_strlcpy(s->graphic_str, tag);
6075 "%s.graphic_alt", sec_name));
6076
6078 if (nullptr == reqs) {
6079 return FALSE;
6080 }
6082
6083 s->helptext = lookup_strvec(file, sec_name, "helptext");
6084
6085 return TRUE;
6086}
6087
6088/**********************************************************************/
6091static bool load_ruleset_cities(struct section_file *file,
6092 struct rscompat_info *compat)
6093{
6094 const char *filename = secfile_name(file);
6095 struct section_list *sec, *ssec = nullptr;
6096 int specs_count;
6097 bool ok = TRUE;
6098 int i = 0;
6099
6100 if (!rscompat_check_cap_and_version(file, filename, compat)) {
6101 return FALSE;
6102 }
6103
6104 secfile_entry_ignore_by_path(file, "datafile.description"); /* Unused */
6105 secfile_entry_ignore_by_path(file, "datafile.ruledit"); /* Unused */
6106
6107 /* Specialist options */
6109
6110 if (!sec) {
6111 ruleset_error(nullptr, LOG_ERROR, "\"%s\": No normal specialists.", filename);
6112
6113 ok = FALSE;
6114 } else {
6117 /* Superspecialists are optional */
6118 if (ssec) {
6120 }
6121 if (specs_count >= SP_MAX) {
6122 ruleset_error(nullptr, LOG_ERROR,
6123 "\"%s\": Too many specialists (%d, max %d).",
6124 filename, specs_count, SP_MAX);
6125 ok = FALSE;
6126 }
6127 }
6128
6129
6130 if (ok) {
6132
6133 section_list_iterate(sec, psection) {
6134 struct specialist *s = specialist_by_number(i);
6135
6136 ok = load_specialist(psection, s, file);
6137
6138 if (!ok) {
6139 break;
6140 }
6141
6142 if (requirement_vector_size(&s->reqs) == 0 && DEFAULT_SPECIALIST == -1) {
6144 }
6145 i++;
6147 }
6148
6149 if (ok){
6150 if (DEFAULT_SPECIALIST == -1) {
6151 ruleset_error(nullptr, LOG_ERROR,
6152 "\"%s\": must have zero reqs for at least one "
6153 "specialist type.", filename);
6154 ok = FALSE;
6155 } else {
6157 }
6158 }
6160 sec = nullptr;
6161
6162 if (ssec) {
6163 if (ok) {
6164 section_list_iterate(ssec, psection) {
6165 struct specialist *s = specialist_by_number(i);
6166
6167 ok = load_specialist(psection, s, file);
6168
6169 if (!ok) {
6170 break;
6171 }
6172
6173 i++;
6175 }
6176
6178 ssec = nullptr;
6179 }
6180
6181 if (ok) {
6182 /* City Parameters */
6183
6186 "parameters.celebrate_size_limit");
6188 secfile_lookup_int_default(file, GAME_DEFAULT_ADDTOSIZE, "parameters.add_to_size_limit");
6191 "parameters.angry_citizens");
6192
6194 secfile_lookup_bool_default(file, GAME_DEFAULT_CHANGABLE_TAX, "parameters.changable_tax");
6196 secfile_lookup_int_default(file, 0, "parameters.forced_science");
6198 secfile_lookup_int_default(file, 100, "parameters.forced_luxury");
6200 secfile_lookup_int_default(file, 0, "parameters.forced_gold");
6202 + game.info.forced_gold != 100) {
6203 ruleset_error(nullptr, LOG_ERROR,
6204 "\"%s\": Forced taxes do not add up in ruleset!",
6205 filename);
6206 ok = FALSE;
6207 }
6208 }
6209
6210 if (ok) {
6211 /* civ1 & 2 didn't reveal tiles */
6214 "parameters.vision_reveal_tiles");
6215
6217 secfile_lookup_int_default(file, 1, "parameters.pop_report_zeroes");
6218
6219 /* Citizens configuration. */
6222 "citizen.nationality");
6225 "citizen.ubuilder_nationality");
6228 "citizen.convert_speed");
6230 secfile_lookup_int_default(file, 0, "citizen.partisans_pct");
6232 secfile_lookup_int_default(file, 0, "citizen.conquest_convert_pct");
6233 }
6234
6235 if (ok) {
6236 /* Missing unit upkeep. */
6238
6239 /* Can't pay food upkeep! */
6241 auto_perf->cause = AAPC_UNIT_UPKEEP;
6242
6243 /* This is about food upkeep. */
6245 req_from_str("OutputType", "Local",
6246 FALSE, TRUE, TRUE,
6247 "Food"));
6248
6249 /* Internally represented as an action auto performer rule. */
6250 if (!load_muuk_as_action_auto(file, auto_perf, "food", filename)) {
6251 ok = FALSE;
6252 }
6253
6256 "missing_unit_upkeep.food_wipe");
6257
6258 /* Can't pay gold upkeep! */
6260 auto_perf->cause = AAPC_UNIT_UPKEEP;
6261
6262 /* This is about gold upkeep. */
6264 req_from_str("OutputType", "Local",
6265 FALSE, TRUE, TRUE,
6266 "Gold"));
6267
6268 /* Internally represented as an action auto performer rule. */
6269 if (!load_muuk_as_action_auto(file, auto_perf, "gold", filename)) {
6270 ok = FALSE;
6271 }
6272
6275 "missing_unit_upkeep.gold_wipe");
6276
6277 /* Can't pay shield upkeep! */
6279 auto_perf->cause = AAPC_UNIT_UPKEEP;
6280
6281 /* This is about shield upkeep. */
6283 req_from_str("OutputType", "Local",
6284 FALSE, TRUE, TRUE,
6285 "Shield"));
6286
6287 /* Internally represented as an action auto performer rule. */
6288 if (!load_muuk_as_action_auto(file, auto_perf, "shield", filename)) {
6289 ok = FALSE;
6290 }
6291
6294 "missing_unit_upkeep.shield_wipe");
6295 }
6296
6297 if (ok) {
6299 }
6300
6301 return ok;
6302}
6303
6304/**********************************************************************/
6307static bool load_ruleset_effects(struct section_file *file,
6308 struct rscompat_info *compat)
6309{
6310 struct section_list *sec;
6311 const char *filename;
6312 bool ok = TRUE;
6313
6314 filename = secfile_name(file);
6315
6316 if (!rscompat_check_cap_and_version(file, filename, compat)) {
6317 return FALSE;
6318 }
6319
6320 secfile_entry_ignore_by_path(file, "datafile.description"); /* Unused */
6321 secfile_entry_ignore_by_path(file, "datafile.ruledit"); /* Unused */
6322
6324
6325 if (sec != nullptr) {
6326 section_list_iterate(sec, psection) {
6327 const char *sec_name = section_name(psection);
6328 enum effect_type main_type;
6329 enum effect_type ai_valued_as;
6330 const char *type;
6331
6332 type = secfile_lookup_str(file, "%s.type", sec_name);
6333 if (type == nullptr) {
6334 ruleset_error(nullptr, LOG_ERROR,
6335 "\"%s\" [%s] missing effect type.",
6336 filename, sec_name);
6337 ok = FALSE;
6338 break;
6339 }
6342 ruleset_error(nullptr, LOG_ERROR,
6343 "\"%s\" [%s] lists unknown effect type \"%s\".",
6344 filename, sec_name, type);
6345 ok = FALSE;
6346 break;
6347 }
6348 if (!is_user_effect(main_type)) {
6349 ruleset_error(nullptr, LOG_ERROR,
6350 "\"%s\" [%s] type \"%s\" is not an user effect.",
6351 filename, sec_name, type);
6352 ok = FALSE;
6353 break;
6354 }
6355
6356 type = secfile_lookup_str(file, "%s.ai_valued_as", sec_name);
6357 if (type == nullptr) {
6358 ruleset_error(nullptr, LOG_ERROR,
6359 "\"%s\" [%s] missing ai_valued_as.",
6360 filename, sec_name);
6361 ok = FALSE;
6362 break;
6363 }
6366 ruleset_error(nullptr, LOG_ERROR,
6367 "\"%s\" [%s] lists unknown ai_valued_as \"%s\".",
6368 filename, sec_name, type);
6369 ok = FALSE;
6370 break;
6371 }
6373 ruleset_error(nullptr, LOG_ERROR,
6374 "\"%s\" [%s] ai_valued_as \"%s\" is an user effect.",
6375 filename, sec_name, type);
6376 ok = FALSE;
6377 break;
6378 }
6379
6381 /* It has been set already! */
6382 ruleset_error(nullptr, LOG_ERROR,
6383 "\"%s\" [%s] Duplicate \"%s\" entry.",
6384 filename, sec_name, type);
6385 ok = FALSE;
6386 break;
6387 }
6388
6391
6393 }
6394
6395 /* Parse effects and add them to the effects ruleset cache. */
6397 section_list_iterate(sec, psection) {
6398 enum effect_type eff;
6399 int value;
6400 struct multiplier *pmul;
6401 struct effect *peffect;
6402 const char *sec_name = section_name(psection);
6403 struct requirement_vector *reqs;
6404 const char *type;
6405 const char *comment;
6406
6407 type = secfile_lookup_str(file, "%s.type", sec_name);
6408
6409 if (type == nullptr) {
6410 ruleset_error(nullptr, LOG_ERROR,
6411 "\"%s\" [%s] missing effect type.",
6412 filename, sec_name);
6413 ok = FALSE;
6414 break;
6415 }
6416
6417 if (compat->compat_mode && compat->version < RSFORMAT_3_4) {
6419 }
6420
6422 if (!effect_type_is_valid(eff)) {
6423 ruleset_error(nullptr, LOG_ERROR,
6424 "\"%s\" [%s] lists unknown effect type \"%s\".",
6425 filename, sec_name, type);
6426 ok = FALSE;
6427 break;
6428 }
6429
6430 value = secfile_lookup_int_default(file, 1, "%s.value", sec_name);
6431
6432 {
6433 const char *multiplier_name
6434 = secfile_lookup_str(file, "%s.multiplier", sec_name);
6435
6436 if (multiplier_name) {
6438 if (!pmul) {
6439 ruleset_error(nullptr, LOG_ERROR,
6440 "\"%s\" [%s] has unknown multiplier \"%s\".",
6441 filename, sec_name, multiplier_name);
6442 ok = FALSE;
6443 break;
6444 }
6445 } else {
6446 pmul = nullptr;
6447 }
6448 }
6449
6450 peffect = effect_new(eff, value, pmul);
6451
6452 reqs = lookup_req_list(file, sec_name, "reqs", type);
6453 if (reqs == nullptr) {
6454 ok = FALSE;
6455 break;
6456 }
6457
6461
6462 comment = secfile_lookup_str_default(file, nullptr, "%s.comment", sec_name);
6463
6464 if (comment != nullptr) {
6465 peffect->rulesave.comment = fc_strdup(comment);
6466 }
6467
6470
6471 if (ok) {
6473 }
6474
6475 return ok;
6476}
6477
6478/**********************************************************************/
6482 int def, int min, int max,
6483 const char *path, ...)
6484{
6485 char fullpath[256];
6486 int ival;
6487 va_list args;
6488
6489 va_start(args, path);
6490 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
6491 va_end(args);
6492
6493 if (!secfile_lookup_int(file, &ival, "%s", fullpath)) {
6494 ival = def;
6495 }
6496
6497 if (ival < min) {
6498 ruleset_error(nullptr, LOG_ERROR,
6499 "\"%s\" should be in the interval [%d, %d] "
6500 "but is %d; using the minimal value.",
6501 fullpath, min, max, ival);
6502 ival = min;
6503 }
6504
6505 if (ival > max) {
6506 ruleset_error(nullptr, LOG_ERROR,
6507 "\"%s\" should be in the interval [%d, %d] "
6508 "but is %d; using the maximal value.",
6509 fullpath, min, max, ival);
6510 ival = max;
6511 }
6512
6513 return ival;
6514}
6515
6516/**********************************************************************/
6519static bool load_action_range_max(struct section_file *file, action_id act)
6520{
6521 struct action *paction = action_by_number(act);
6522 const char *vname = action_max_range_ruleset_var_name(act);
6523
6524 if (vname != nullptr) {
6525 struct entry *pentry;
6526 int max_range;
6527
6528 pentry = secfile_entry_lookup(file, "actions.%s", vname);
6529
6530 if (pentry == nullptr) {
6532 } else {
6533 const char *custom;
6534
6537 /* max_range already assigned */
6538 } else if (entry_type_get(pentry) == ENTRY_STR
6542 } else {
6543 ruleset_error(nullptr, LOG_ERROR, "Bad actions.%s",
6546
6547 return FALSE;
6548 }
6549 }
6550
6552 }
6553
6554 return TRUE;
6555}
6556
6557/**********************************************************************/
6560static bool load_action_range(struct section_file *file, action_id act)
6561{
6562 struct action *paction = action_by_number(act);
6563 const char *vname;
6564
6565 if (!load_action_range_max(file, act)) {
6566 return FALSE;
6567 }
6568
6570 if (vname != nullptr) {
6571 /* Min range can be loaded from the ruleset. */
6575 "actions.%s",
6576 vname);
6577 }
6578
6579 return TRUE;
6580}
6581
6582/**********************************************************************/
6585static bool load_action_kind(struct section_file *file, action_id act)
6586{
6587 struct action *paction = action_by_number(act);
6589
6590 if (var_name != nullptr) {
6594 paction->result),
6596 "actions.%s", var_name);
6597 } else {
6600 }
6601
6602 return TRUE;
6603}
6604
6605/**********************************************************************/
6609 action_id act)
6610{
6612 /* Actor consumption can be loaded from the ruleset. */
6615 file, RS_DEFAULT_ACTION_ACTOR_CONSUMING_ALWAYS, "actions.%s",
6617 }
6618
6619 return TRUE;
6620}
6621
6622/**********************************************************************/
6626 const char *filename,
6627 struct action *paction,
6628 struct rscompat_info *compat)
6629{
6631
6632 if (var_name != nullptr) {
6633 /* Action blocking can be loaded from the ruleset. */
6634 char fullpath[1024];
6635
6636 fc_snprintf(fullpath, sizeof(fullpath), "actions.%s", var_name);
6637
6638 if (secfile_entry_by_path(file, fullpath)) {
6640 size_t asize;
6641 int j;
6642
6645
6646 if (!blocking_actions) {
6647 /* Entity exists but couldn't read it. */
6648 ruleset_error(nullptr, LOG_ERROR,
6649 "\"%s\": %s: bad action list",
6650 filename, fullpath);
6651
6652 return FALSE;
6653 }
6654
6655 for (j = 0; j < asize; j++) {
6656 BV_SET(paction->blocked_by, blocking_actions[j]);
6657 }
6658
6660 }
6661 }
6662
6663 return TRUE;
6664}
6665
6666/**********************************************************************/
6671 const char *filename,
6672 int performer_slot,
6673 struct action *paction)
6674{
6676 char action_list_path[100];
6677
6679 /* Not relevant. */
6680 return TRUE;
6681 }
6682
6684 auto_perf->cause = AAPC_POST_ACTION;
6685
6686 /* Limit auto performer to this action. */
6689 FALSE, TRUE, TRUE,
6690 paction->id));
6691
6692 /* Load the list of actions. */
6694 "actions.%s",
6697 action_list_path, filename)) {
6698 return FALSE;
6699 }
6700
6701 return TRUE;
6702}
6703
6704/**********************************************************************/
6707static bool lookup_bv_actions(struct section_file *file,
6708 const char *filename,
6709 bv_actions *target,
6710 const char *path)
6711{
6712 if (secfile_entry_by_path(file, path)) {
6714 size_t asize;
6715 int j;
6716
6718 "%s", path);
6719
6720 if (!listed_actions) {
6721 /* Entity exists but couldn't read it. */
6722 ruleset_error(nullptr, LOG_ERROR, "\"%s\": %s: bad action list",
6723 filename, path);
6724
6725 return FALSE;
6726 }
6727
6728 for (j = 0; j < asize; j++) {
6729 BV_SET(*target, listed_actions[j]);
6730 }
6731
6733 }
6734
6735 return TRUE;
6736}
6737
6738/**********************************************************************/
6741static bool load_ruleset_game(struct section_file *file, bool act,
6742 struct rscompat_info *compat)
6743{
6744 const char *sval, **svec;
6745 const char *filename;
6746 int *food_ini;
6747 int i;
6748 size_t teams;
6749 const char *pref_text;
6750 size_t gni_tmp;
6751 struct section_list *sec;
6752 size_t nval;
6753 const char *name;
6754 bool ok = TRUE;
6755
6756 if (file == nullptr) {
6757 return FALSE;
6758 }
6759 filename = secfile_name(file);
6760
6761 name = secfile_lookup_str_default(file, nullptr, "ruledit.description_file");
6762 if (name != nullptr) {
6764 }
6766 = secfile_lookup_bool_default(file, FALSE, "ruledit.std_tileset_compat");
6767
6768 /* Section: tileset */
6769 pref_text = secfile_lookup_str_default(file, "", "tileset.preferred");
6770 if (pref_text[0] != '\0') {
6771 /* There was tileset suggestion */
6773 } else {
6774 /* No tileset suggestions */
6775 game.control.preferred_tileset[0] = '\0';
6776 }
6777
6778 /* Section: soundset */
6779 pref_text = secfile_lookup_str_default(file, "", "soundset.preferred");
6780 if (pref_text[0] != '\0') {
6781 /* There was soundset suggestion */
6783 } else {
6784 /* No soundset suggestions */
6786 }
6787
6788 /* Section: musicset */
6789 pref_text = secfile_lookup_str_default(file, "", "musicset.preferred");
6790 if (pref_text[0] != '\0') {
6791 /* There was musicset suggestion */
6793 } else {
6794 /* No musicset suggestions */
6796 }
6797
6798 /* Section: about */
6799 pref_text = secfile_lookup_str(file, "about.name");
6800 /* Ruleset/modpack name found */
6802
6803 pref_text = secfile_lookup_str_default(file, "", "about.version");
6804 if (pref_text[0] != '\0') {
6805 /* Ruleset/modpack version found */
6807 } else {
6808 /* No version information */
6809 game.control.version[0] = '\0';
6810 }
6811
6812 pref_text = secfile_lookup_str_default(file, "", "about.alt_dir");
6813 if (pref_text[0] != '\0') {
6814 /* Alt directory definition found. */
6816 } else {
6817 /* No alt directory information */
6818 game.control.alt_dir[0] = '\0';
6819 }
6820
6821 pref_text = secfile_lookup_str_default(file, "", "about.summary");
6822 if (pref_text[0] != '\0') {
6823 int len;
6824
6825 /* Ruleset/modpack summary found */
6826 len = strlen(pref_text);
6829 } else {
6830 /* No summary */
6831 if (game.ruleset_summary != nullptr) {
6833 game.ruleset_summary = nullptr;
6834 }
6835 }
6836
6837 pref_text = secfile_lookup_str_default(file, "", "about.description");
6838 if (pref_text[0] != '\0') {
6839 int len;
6840
6841 /* Ruleset/modpack description found */
6842 len = strlen(pref_text);
6846 } else {
6847 /* No description */
6848 if (game.ruleset_description != nullptr) {
6850 game.ruleset_description = nullptr;
6851 }
6853 }
6854
6855 pref_text = secfile_lookup_str_default(file, "", "about.capabilities");
6856 if (pref_text[0] != '\0') {
6857 int len = strlen(pref_text);
6858
6861 } else {
6863 game.ruleset_capabilities[0] = '\0';
6864 }
6865
6866 /* Section: options */
6867 if (!lookup_tech_list(file, "options", "global_init_techs",
6868 game.rgame.global_init_techs, filename)) {
6869 ok = FALSE;
6870 }
6871
6872 if (ok) {
6873 if (!lookup_building_list(file, "options", "global_init_buildings",
6874 game.rgame.global_init_buildings, filename)) {
6875 ok = FALSE;
6876 }
6877 }
6878
6879 if (ok) {
6880 const char **slist;
6881 int j;
6882
6884 "options.popup_tech_help");
6885
6886 /* section: civstyle */
6889 "civstyle.base_pollution");
6890
6892
6893 slist = secfile_lookup_str_vec(file, &nval, "civstyle.gameloss_style");
6894 for (j = 0; j < nval; j++) {
6895 enum gameloss_style style;
6896
6897 sval = slist[j];
6898 if (strcmp(sval, "") == 0) {
6899 continue;
6900 }
6902 if (!gameloss_style_is_valid(style)) {
6903 ruleset_error(nullptr, LOG_ERROR,
6904 "\"%s\": bad value \"%s\" for gameloss_style.",
6905 filename, sval);
6906 ok = FALSE;
6907 break;
6908 } else {
6909 game.info.gameloss_style |= style;
6910 }
6911 }
6912 free(slist);
6913 }
6914
6915 if (ok) {
6921 "civstyle.happy_cost");
6927 "civstyle.food_cost");
6933 "civstyle.base_bribe_cost");
6939 "civstyle.ransom_gold");
6942 "civstyle.pillage_select");
6943
6946 "civstyle.tech_steal_allow_holes");
6949 "civstyle.tech_trade_allow_holes");
6952 "civstyle.tech_trade_loss_allow_holes");
6955 "civstyle.tech_parasite_allow_holes");
6958 "civstyle.tech_loss_allow_holes");
6959
6965 "civstyle.upgrade_veteran_loss");
6971 "civstyle.autoupgrade_veteran_loss");
6972
6978 "research.base_tech_cost");
6979
6985 "research.min_tech_cost");
6986
6988 "civstyle.granary_food_ini");
6990
6992 ruleset_error(nullptr, LOG_ERROR,
6993 "Too many granary_food_ini entries (%d, max %d)",
6995 ok = FALSE;
6996 } else if (game.info.granary_num_inis == 0) {
6997 log_error("No values for granary_food_ini. Using default "
6998 "value %d.", RS_DEFAULT_GRANARY_FOOD_INI);
7001 } else {
7002 int gi;
7003
7004 /* check for <= 0 entries */
7005 for (gi = 0; gi < game.info.granary_num_inis; gi++) {
7006 if (food_ini[gi] <= 0) {
7007 if (gi == 0) {
7009 } else {
7010 food_ini[gi] = food_ini[gi - 1];
7011 }
7012 log_error("Bad value for granary_food_ini[%i]. Using %i.",
7013 gi, food_ini[gi]);
7014 }
7016 }
7017 }
7018 free(food_ini);
7019 }
7020
7021 if (ok) {
7027 "civstyle.granary_food_inc");
7028
7035 "civstyle.min_city_center_%s",
7038 }
7039
7040 if (ok) {
7041 const char *tus_text;
7042
7048 "civstyle.init_vis_radius_sq");
7049
7055 "civstyle.init_city_radius_sq");
7056
7058 "civstyle.gold_upkeep_style");
7062 ruleset_error(nullptr, LOG_ERROR,
7063 "Unknown gold upkeep style \"%s\"",
7064 tus_text);
7065 ok = FALSE;
7066 }
7067
7068 if (compat->compat_mode
7069 && compat->version < RSFORMAT_3_4) {
7071 = secfile_lookup_bool_default(file, FALSE, "civstyle.homeless_gold_upkeep");
7072
7075 ruleset_error(nullptr, LOG_ERROR,
7076 "Cannot have homeless_gold_upkeep while gold_upkeep_style \"City\".");
7077 ok = FALSE;
7078 }
7079 } else {
7081 }
7082
7084 "civstyle.output_granularity");
7085
7087 = secfile_lookup_bool_default(file, FALSE, "civstyle.airlift_from_always_enabled");
7088
7090 = secfile_lookup_bool_default(file, TRUE, "civstyle.airlift_to_always_enabled");
7091
7092 /* Section: wonder_visibility */
7093 if (ok) {
7094 const char *text;
7095
7096 text = secfile_lookup_str_default(file,
7098 "wonder_visibility.small_wonders");
7099
7103 ruleset_error(nullptr, LOG_ERROR,
7104 "Unknown wonder visibility type \"%s\"",
7105 text);
7106 ok = FALSE;
7107 }
7108 }
7109
7110 /* section: illness */
7113 "illness.illness_on");
7119 "illness.illness_base_factor");
7125 "illness.illness_min_size");
7131 "illness.illness_trade_infection");
7137 "illness.illness_pollution_factor");
7138
7139 /* section: incite_cost */
7145 "incite_cost.base_incite_cost");
7151 "incite_cost.improvement_factor");
7157 "incite_cost.unit_factor");
7163 "incite_cost.total_factor");
7164 }
7165
7166 if (ok) {
7167 const char *tus_text;
7168
7169 /* Section: combat_rules */
7172 "combat_rules.tired_attack");
7173
7176 "combat_rules.only_killing_makes_veteran");
7177
7180 "combat_rules.only_real_fight_makes_veteran");
7181
7184 "combat_rules.combat_odds_scaled_veterancy");
7185
7188 "combat_rules.damage_reduces_bombard_rate");
7189
7192 "combat_rules.low_firepower_badwallattacker");
7195 "combat_rules.low_firepower_pearl_harbor");
7196
7199 "combat_rules.low_firepower_combat_bonus");
7202 "combat_rules.low_firepower_nonnat_bombard");
7203
7208 "combat_rules.nuke_pop_loss_pct");
7209
7214 "combat_rules.nuke_defender_survival_chance_pct");
7215
7216 /* section: borders */
7222 "borders.radius_sq_city");
7228 "borders.size_effect");
7229
7235 "borders.radius_sq_city_permanent");
7236
7237 /* Section: research */
7239 "research.tech_cost_style");
7243 ruleset_error(nullptr, LOG_ERROR,
7244 "Unknown tech cost style \"%s\"",
7245 tus_text);
7246 ok = FALSE;
7247 }
7248
7250 "research.tech_leakage");
7254 ruleset_error(nullptr, LOG_ERROR,
7255 "Unknown tech leakage \"%s\"",
7256 tus_text);
7257 ok = FALSE;
7258 }
7261 log_error("Only tech_leakage \"%s\" supported with "
7262 "tech_cost_style \"%s\". ",
7265 log_error("Switching to tech_leakage \"%s\".",
7268 }
7274 "research.base_tech_cost");
7275
7277 "research.tech_upkeep_style");
7278
7280
7282 ruleset_error(nullptr, LOG_ERROR,
7283 "Unknown tech upkeep style \"%s\"",
7284 tus_text);
7285 ok = FALSE;
7286 }
7287 }
7288
7289 if (ok) {
7295 "research.tech_upkeep_divider");
7296
7297 sval = secfile_lookup_str_default(file, nullptr, "research.free_tech_method");
7298 if (sval == nullptr) {
7299 ruleset_error(nullptr, LOG_ERROR,
7300 "No free_tech_method given");
7301 ok = FALSE;
7302 } else {
7305 ruleset_error(nullptr, LOG_ERROR,
7306 "Bad value %s for free_tech_method.", sval);
7307 ok = FALSE;
7308 }
7309 }
7310 }
7311
7312 if (ok) {
7313 int cf;
7314
7315 /* section: culture */
7318 "culture.victory_min_points");
7321 "culture.victory_lead_pct");
7324 "culture.migration_pml");
7327 "culture.history_interest_pml");
7328
7329 /* section: world_peace */
7332 "world_peace.victory_turns");
7333
7334 /* section: calendar */
7337 "calendar.skip_year_0");
7340 "calendar.start_year");
7342 = secfile_lookup_int_default(file, 0, "calendar.fragments");
7343
7345 ruleset_error(nullptr, LOG_ERROR,
7346 "Too many calendar fragments. Max is %d",
7348 ok = FALSE;
7350 }
7354 "calendar.positive_label"));
7358 "calendar.negative_label"));
7359
7360 for (cf = 0; cf < game.calendar.calendar_fragments; cf++) {
7361 const char *fname;
7362
7363 fname = secfile_lookup_str_default(file, nullptr,
7364 "calendar.fragment_name%d", cf);
7365 if (fname != nullptr) {
7368 }
7369 }
7370 }
7371
7372 if (ok) {
7373 /* Section playercolors */
7374 struct rgbcolor *prgbcolor = nullptr;
7375 bool color_read = TRUE;
7376
7377 /* Check if the player list is defined and empty. */
7378 if (playercolor_count() != 0) {
7379 ok = FALSE;
7380 } else {
7381 i = 0;
7382
7383 while (color_read) {
7384 prgbcolor = nullptr;
7385
7386 color_read = rgbcolor_load(file, &prgbcolor, "playercolors.colorlist%d", i);
7387 if (color_read) {
7389 }
7390
7391 i++;
7392 }
7393
7394 if (playercolor_count() == 0) {
7395 ruleset_error(nullptr, LOG_ERROR, "No player colors defined!");
7396 ok = FALSE;
7397 }
7398
7399 if (ok) {
7400 fc_assert(game.plr_bg_color == nullptr);
7401 if (!rgbcolor_load(file, &game.plr_bg_color, "playercolors.background")) {
7402 ruleset_error(nullptr, LOG_ERROR,
7403 "No background player color defined! (%s)",
7404 secfile_error());
7405 ok = FALSE;
7406 }
7407 }
7408 }
7409 }
7410
7411 if (ok) {
7412 /* section: teams */
7413 svec = secfile_lookup_str_vec(file, &teams, "teams.names");
7414 if (team_slot_count() < teams) {
7416 }
7418 for (i = 0; i < teams; i++) {
7420 }
7421 free(svec);
7422
7424 nval = (sec != nullptr ? section_list_size(sec) : 0);
7425 if (nval > MAX_DISASTER_TYPES) {
7426 int num = nval; /* No "size_t" to printf */
7427
7428 ruleset_error(nullptr, LOG_ERROR,
7429 "\"%s\": Too many disaster types (%d, max %d)",
7430 filename, num, MAX_DISASTER_TYPES);
7432 ok = FALSE;
7433 } else {
7435 }
7436 }
7437
7438 if (ok) {
7440 int id = disaster_index(pdis);
7441 int j;
7442 size_t eff_count;
7443 struct requirement_vector *reqs;
7444 const char *sec_name = section_name(section_list_get(sec, id));
7445
7446 if (!ruleset_load_names(&pdis->name, nullptr, file, sec_name)) {
7447 ruleset_error(nullptr, LOG_ERROR,
7448 "\"%s\": Cannot load disaster names",
7449 filename);
7450 ok = FALSE;
7451 break;
7452 }
7453
7455 if (reqs == nullptr) {
7456 ok = FALSE;
7457 break;
7458 }
7460
7462 "%s.frequency", sec_name);
7463
7464 svec = secfile_lookup_str_vec(file, &eff_count, "%s.effects", sec_name);
7465
7466 BV_CLR_ALL(pdis->effects);
7467 for (j = 0; j < eff_count; j++) {
7468 const char *dsval = svec[j];
7470
7472
7474 ruleset_error(nullptr, LOG_ERROR,
7475 "\"%s\" disaster \"%s\": unknown effect \"%s\".",
7476 filename, disaster_rule_name(pdis), dsval);
7477 ok = FALSE;
7478 break;
7479 } else {
7480 BV_SET(pdis->effects, effect);
7481 }
7482 }
7483
7484 free(svec);
7485
7486 if (!ok) {
7487 break;
7488 }
7491 }
7492
7493 if (ok) {
7495
7497 int id = achievement_index(pach);
7498 const char *sec_name = section_name(section_list_get(sec, id));
7499 const char *typename;
7500 const char *msg;
7501
7502 typename = secfile_lookup_str_default(file, nullptr, "%s.type", sec_name);
7503
7504 pach->type = achievement_type_by_name(typename, fc_strcasecmp);
7505 if (!achievement_type_is_valid(pach->type)) {
7506 ruleset_error(nullptr, LOG_ERROR,
7507 "Achievement has unknown type \"%s\".",
7508 typename != nullptr ? typename : "(nullptr)");
7509 ok = FALSE;
7510 }
7511
7512 if (ok) {
7514 "%s.unique", sec_name);
7515
7517 "%s.value", sec_name);
7518 pach->culture = secfile_lookup_int_default(file, 0,
7519 "%s.culture", sec_name);
7520
7521 msg = secfile_lookup_str_default(file, nullptr, "%s.first_msg", sec_name);
7522 if (msg == nullptr) {
7523 ruleset_error(nullptr, LOG_ERROR,
7524 "Achievement %s has no first msg!", sec_name);
7525 ok = FALSE;
7526 } else {
7527 pach->first_msg = fc_strdup(msg);
7528 }
7529 }
7530
7531 if (ok) {
7532 msg = secfile_lookup_str_default(file, nullptr, "%s.cons_msg", sec_name);
7533 if (msg == nullptr) {
7534 if (!pach->unique) {
7535 ruleset_error(nullptr, LOG_ERROR,
7536 "Achievement %s has no msg for consecutive gainers!",
7537 sec_name);
7538 ok = FALSE;
7539 }
7540 } else {
7541 pach->cons_msg = fc_strdup(msg);
7542 }
7543 }
7544
7545 if (!ok) {
7546 break;
7547 }
7550 }
7551
7552 if (ok) {
7553 for (i = 0; (name = secfile_lookup_str_default(file, nullptr,
7554 "trade.settings%d.type",
7555 i)); i++) {
7557
7558 if (type == TRT_LAST) {
7559 ruleset_error(nullptr, LOG_ERROR,
7560 "\"%s\" unknown trade route type \"%s\".",
7561 filename, name);
7562 ok = FALSE;
7563 } else {
7565 const char *cancelling;
7566 const char *bonus;
7567
7568 set->trade_pct = secfile_lookup_int_default(file, 100,
7569 "trade.settings%d.pct", i);
7570 cancelling = secfile_lookup_str_default(file, "Active",
7571 "trade.settings%d.cancelling", i);
7573 if (set->cancelling == TRI_LAST) {
7574 ruleset_error(nullptr, LOG_ERROR,
7575 "\"%s\" unknown trade route cancelling type \"%s\".",
7576 filename, cancelling);
7577 ok = FALSE;
7578 }
7579
7580 bonus = secfile_lookup_str_default(file, "None", "trade.settings%d.bonus", i);
7581
7583
7585 ruleset_error(nullptr, LOG_ERROR,
7586 "\"%s\" unknown trade route bonus type \"%s\".",
7587 filename, bonus);
7588 ok = FALSE;
7589 }
7590 }
7591 }
7592 }
7593
7594 if (ok) {
7595 const char *str;
7596
7598 = secfile_lookup_int_default(file, 0, "trade.min_trade_route_val");
7599
7602 "trade.reveal_trade_partner");
7603
7606 "trade.goods_selection");
7607
7609
7611 ruleset_error(nullptr, LOG_ERROR,
7612 "\"%s\" goods selection method \"%s\" unknown.",
7613 filename, str);
7614 ok = FALSE;
7615 }
7616 }
7617
7618 if (ok) {
7620
7622 int id = goods_index(pgood);
7623 const char *sec_name = section_name(section_list_get(sec, id));
7624 struct requirement_vector *reqs;
7625 const char **slist;
7626 int j;
7627
7629 if (reqs == nullptr) {
7630 ok = FALSE;
7631 break;
7632 }
7634
7635 pgood->from_pct = secfile_lookup_int_default(file, 100,
7636 "%s.from_pct", sec_name);
7637 pgood->to_pct = secfile_lookup_int_default(file, 100,
7638 "%s.to_pct", sec_name);
7639 pgood->onetime_pct = secfile_lookup_int_default(file, 100,
7640 "%s.onetime_pct", sec_name);
7641 pgood->select_priority = secfile_lookup_int_default(file, 1,
7642 "%s.select_priority", sec_name);
7643 pgood->replace_priority = secfile_lookup_int_default(file, 1,
7644 "%s.replace_priority", sec_name);
7645
7646 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name);
7647 BV_CLR_ALL(pgood->flags);
7648 for (j = 0; j < nval; j++) {
7649 enum goods_flag_id flag;
7650
7651 sval = slist[j];
7653 if (!goods_flag_id_is_valid(flag)) {
7654 ruleset_error(nullptr, LOG_ERROR,
7655 "\"%s\" good \"%s\": unknown flag \"%s\".",
7656 filename, goods_rule_name(pgood), sval);
7657 ok = FALSE;
7658 break;
7659 } else {
7660 BV_SET(pgood->flags, flag);
7661 }
7662 }
7663 free(slist);
7664
7665 pgood->helptext = lookup_strvec(file, sec_name, "helptext");
7668 }
7669
7670 if (ok) {
7671 const char *uname = secfile_lookup_str_default(file, nullptr,
7672 "aarea.access_unit");
7673 const struct unit_type *access_unit = nullptr;
7674
7675 terrain_control.access_unit = -1;
7676
7677 if (uname != nullptr && uname[0] != '\0') {
7678 access_unit = unit_type_by_rule_name(uname);
7679
7680 if (access_unit == nullptr) {
7681 ruleset_error(nullptr, LOG_ERROR, "%s: access unit %s unknown.",
7682 filename, uname);
7683 ok = FALSE;
7684 } else {
7685 terrain_control.access_unit = utype_number(access_unit);
7686 }
7687 }
7688
7689 access_info_init(access_unit);
7690 }
7691
7692 if (ok) {
7694
7695 if (sec != nullptr) {
7696 int num = section_list_size(sec);
7697
7698 for (i = 0; i < num; i++) {
7699 const char *sec_name = section_name(section_list_get(sec, i));
7700 const char *clause_name = secfile_lookup_str_default(file, nullptr,
7701 "%s.type", sec_name);
7703 struct clause_info *info;
7704 struct requirement_vector *reqs;
7705
7706 if (!clause_type_is_valid(type)) {
7707 ruleset_error(nullptr, LOG_ERROR,
7708 "\"%s\" unknown clause type \"%s\".",
7709 filename, clause_name);
7710 ok = FALSE;
7711 break;
7712 }
7713
7714 info = clause_info_get(type);
7715
7716 if (info->enabled) {
7717 ruleset_error(nullptr, LOG_ERROR,
7718 "\"%s\" duplicate clause type \"%s\" definition.",
7719 filename, clause_name);
7720 ok = FALSE;
7721 break;
7722 }
7723
7724 reqs = lookup_req_list(file, sec_name, "giver_reqs", clause_name);
7725 if (reqs == nullptr) {
7726 ok = FALSE;
7727 break;
7728 }
7730
7731 reqs = lookup_req_list(file, sec_name, "receiver_reqs", clause_name);
7732 if (reqs == nullptr) {
7733 ok = FALSE;
7734 break;
7735 }
7737
7738 reqs = lookup_req_list(file, sec_name, "either_reqs", clause_name);
7739 if (reqs == nullptr) {
7740 ok = FALSE;
7741 break;
7742 }
7744
7745 info->enabled = TRUE;
7746 }
7747 }
7749 }
7750
7751 if (ok) {
7753
7754 if (sec != nullptr) {
7755 int num = section_list_size(sec);
7756 int curr;
7757
7758 for (curr = 0; curr < num; curr++) {
7759
7760 struct counter *pcount = counter_by_id(curr);
7761 const char *sec_name = section_name(section_list_get(sec, curr));
7762 const char *counter_type = secfile_lookup_str_default(file, nullptr,
7763 "%s.type",
7764 sec_name);
7765
7768 if (!counter_behavior_is_valid(cb)) {
7769 ruleset_error(nullptr, LOG_ERROR,
7770 "\"%s\" unknown counter type \"%s\".",
7771 filename, counter_type);
7772 ok = FALSE;
7773 break;
7774 }
7775
7776 if (!ruleset_load_names(&pcount->name, nullptr, file, sec_name)) {
7777 ruleset_error(nullptr, LOG_ERROR,
7778 "\"%s\": Cannot load counter names",
7779 filename);
7780 ok = FALSE;
7781 break;
7782 }
7783
7784 pcount->helptext = lookup_strvec(file, sec_name, "helptext");
7785 pcount->type = cb;
7786 if (!secfile_lookup_int(file, &pcount->checkpoint,
7787 "%s.checkpoint", sec_name)) {
7788
7789 ruleset_error(nullptr, LOG_ERROR,
7790 "\"%s\": No checkpoint value",
7791 filename);
7792 ok = FALSE;
7793 break;
7794 }
7795
7796 pcount->target = CTGT_CITY;
7797 pcount->index = curr;
7798 pcount->def = secfile_lookup_int_default(file, 0,
7799 "%s.def",
7800 sec_name);
7802 }
7803 }
7804 }
7805
7806 /* secfile_check_unused() is not here, but only after also settings section
7807 * has been loaded. */
7808
7809 return ok;
7810}
7811
7812/**********************************************************************/
7815static bool load_ruleset_actions(struct section_file *file,
7816 struct section_file *gamefile,
7817 struct rscompat_info *compat)
7818{
7819 bool ok = TRUE;
7820 const char *filename = secfile_name(file);
7821 struct section_list *sec;
7823 struct requirement_vector *reqs;
7824
7825 /* Auto attack. */
7826
7827 /* Action auto performers aren't ready to be exposed in the ruleset
7828 * yet. The behavior when two action auto performers for the same
7829 * cause can fire isn't set in stone yet. How is one of them chosen?
7830 * What if all the actions of the chosen action auto performer turned
7831 * out to be illegal but one of the other action auto performers that
7832 * fired has legal actions? These issues can decide what other action
7833 * rules action auto performers can represent in the future. Deciding
7834 * should therefore wait until a rule needs action auto performers to
7835 * work a certain way. */
7836 /* Only one action auto performer, ACTION_AUTO_MOVED_ADJ, is caused
7837 * by AAPC_UNIT_MOVED_ADJ. It is therefore safe to expose the full
7838 * requirement vector to the ruleset. */
7839
7840 /* A unit moved next to this unit and the autoattack server setting
7841 * is enabled. */
7844
7845 reqs = lookup_req_list(file,
7846 "auto_attack", "if_attacker",
7847 "auto_attack");
7848 if (reqs == nullptr) {
7849 ok = FALSE;
7850 } else {
7852
7854 "auto_attack.attack_actions",
7855 filename)) {
7856 /* Failed to load auto attack actions */
7857 ruleset_error(nullptr, LOG_ERROR,
7858 "\"%s\": %s: failed load %s.",
7859 filename, "auto_attack", "attack_actions");
7860 ok = FALSE;
7861 }
7862 }
7863
7864 /* Section: actions */
7865 if (ok) {
7866 action_iterate(act_id) {
7867 struct action *paction = action_by_number(act_id);
7868
7869 if (!load_action_blocked_by_list(file, filename, paction, compat)) {
7870 ok = FALSE;
7871 break;
7872 }
7874
7875 if (ok) {
7876 if (!lookup_bv_actions(file, filename,
7878 "actions.diplchance_initial_odds")) {
7879 ok = FALSE;
7880 }
7881 }
7882
7883 if (ok) {
7884 /* If the "Poison City" action or the "Poison City Escape" action
7885 * should empty the granary. */
7886 /* TODO: empty granary and reduce population should become separate
7887 * action effect flags when actions are generalized. */
7891 "actions.poison_empties_food_stock");
7892
7893 /* If the "Steal Maps" action or the "Steal Maps Escape" action always
7894 * will reveal all cities when successful. */
7898 "actions.steal_maps_reveals_all_cities");
7899
7900 /* Allow setting certain properties for some actions before
7901 * generalized actions. */
7902 action_iterate(act_id) {
7903 if (!load_action_range(file, act_id)) {
7904 ok = FALSE;
7905 } else if (!load_action_kind(file, act_id)) {
7906 ok = FALSE;
7907 } else if (!load_action_actor_consuming_always(file, act_id)) {
7908 ok = FALSE;
7909 }
7910
7911 if (!ok) {
7912 break;
7913 }
7915 }
7916
7917 if (ok) {
7918 /* The quiet (don't auto generate help for) property of all actions
7919 * live in a single enum vector. This avoids generic action
7920 * expectations. */
7921 if (secfile_entry_by_path(file, "actions.quiet_actions")) {
7923 size_t asize;
7924 int j;
7925
7928 "actions.quiet_actions");
7929
7930 if (!quiet_actions) {
7931 /* Entity exists but couldn't read it. */
7932 ruleset_error(nullptr, LOG_ERROR,
7933 "\"%s\": actions.quiet_actions: bad action list",
7934 filename);
7935
7936 ok = FALSE;
7937 } else {
7938 for (j = 0; j < asize; j++) {
7939 /* Don't auto generate help text for this action. */
7941 }
7942
7944 }
7945 }
7946 }
7947
7948 if (ok) {
7949 /* Hard code action sub results for now. */
7950
7951 /* Unit Enter Hut */
7953 BV_SET(paction->sub_results, ACT_SUB_RES_HUT_ENTER);
7963
7964 /* Unit Frighten Hut */
7976
7977 /* Unit May Embark */
7978 action_iterate(act_id) {
7979 struct action *paction = action_by_number(act_id);
7980
7982 "civstyle.paradrop_to_transport")
7985 BV_SET(paction->sub_results, ACT_SUB_RES_MAY_EMBARK);
7986 }
7987
7988 /* Embark actions will always embark, not maybe embark. */
7990
7991 /* Non Lethal bombard */
7998 }
7999 }
8000
8001 if (ok) {
8002 /* Forced actions after another action was successfully performed. */
8003
8004 if (!load_action_post_success_force(file, filename,
8008 ok = FALSE;
8009 } else if (!load_action_post_success_force(file, filename,
8013 ok = FALSE;
8014 } else if (!load_action_post_success_force(file, filename,
8017 ACTION_ATTACK))) {
8018 ok = FALSE;
8019 } else if (!load_action_post_success_force(file, filename,
8022 ACTION_ATTACK2))) {
8023 ok = FALSE;
8024 } else if (!load_action_post_success_force(file, filename,
8028 ok = FALSE;
8029 } else if (!load_action_post_success_force(file, filename,
8033 ok = FALSE;
8034 }
8035
8036 /* No "Suicide Attack". Can't act when dead. */
8037 }
8038
8039 if (ok) {
8040 /* The city that made the unit's current tile native is gone.
8041 * Evaluated against an adjacent tile. */
8043 auto_perf->cause = AAPC_CITY_GONE;
8044
8045 /* I have no objections to moving this out of game's actions to
8046 * cities.ruleset, units.ruleset or an other location in game.ruleset
8047 * you find more suitable. -- Sveinung */
8049 "actions.escape_city", filename)) {
8050 ok = FALSE;
8051 }
8052 }
8053
8054 if (ok) {
8055 /* The unit's stack has been defeated and is scheduled for execution
8056 * but the unit has the CanEscape unit type flag.
8057 * Evaluated against an adjacent tile. */
8060
8061 /* I have no objections to moving this out of game's actions to
8062 * cities.ruleset, units.ruleset or an other location in game.ruleset
8063 * you find more suitable. -- Sveinung */
8065 "actions.unit_stack_death", filename)) {
8066 ok = FALSE;
8067 }
8068 }
8069
8070 if (ok) {
8072 if (sec != nullptr) {
8073 section_list_iterate(sec, psection) {
8074 const char *sec_name = section_name(psection);
8075 const char *action_text;
8076 struct action *paction;
8077 const char *ui_name;
8078
8079 action_text = secfile_lookup_str(file, "%s.action", sec_name);
8080
8081 if (action_text == nullptr) {
8082 ruleset_error(nullptr, LOG_ERROR,
8083 "\"%s\" [%s] missing action to configure.",
8084 filename, sec_name);
8085 ok = FALSE;
8086 break;
8087 }
8088
8090 if (paction == nullptr) {
8091 ruleset_error(nullptr, LOG_ERROR,
8092 "\"%s\" [%s] lists unknown action type \"%s\".",
8093 filename, sec_name, action_text);
8094 ok = FALSE;
8095 break;
8096 }
8097
8098 if (paction->configured) {
8099 ruleset_error(nullptr, LOG_ERROR,
8100 "\"%s\" [%s] duplicate configuration for action \"%s\".",
8101 filename, sec_name, action_text);
8102 ok = FALSE;
8103 break;
8104 }
8105
8106 paction->configured = TRUE;
8107
8108 ui_name = secfile_lookup_str_default(file, nullptr,
8109 "%s.ui_name", sec_name);
8110 if (ui_name == nullptr) {
8112 }
8113 sz_strlcpy(paction->ui_name, ui_name);
8115 }
8116 }
8117
8118 if (ok) {
8119 action_iterate(act) {
8120 struct action *paction = action_by_number(act);
8121
8122 if (!paction->configured) {
8124 }
8126 }
8127
8128 if (ok) {
8130
8131 if (sec != nullptr) {
8132 section_list_iterate(sec, psection) {
8133 struct action_enabler *enabler;
8134 const char *sec_name = section_name(psection);
8135 struct action *paction;
8136 struct requirement_vector *actor_reqs;
8137 struct requirement_vector *target_reqs;
8138 const char *action_text;
8139 const char *comment;
8140
8142
8143 action_text = secfile_lookup_str(file, "%s.action", sec_name);
8144
8145 if (action_text == nullptr) {
8146 ruleset_error(nullptr, LOG_ERROR,
8147 "\"%s\" [%s] missing action to enable.",
8148 filename, sec_name);
8149 ok = FALSE;
8150 break;
8151 }
8152
8154 if (paction == nullptr) {
8155 ruleset_error(nullptr, LOG_ERROR,
8156 "\"%s\" [%s] lists unknown action type \"%s\".",
8157 filename, sec_name, action_text);
8158 ok = FALSE;
8159 break;
8160 }
8161
8162 enabler->action = action_id(paction);
8163
8164 actor_reqs = lookup_req_list(file, sec_name, "actor_reqs", action_text);
8165 if (actor_reqs == nullptr) {
8166 ok = FALSE;
8167 break;
8168 }
8169
8170 requirement_vector_copy(&enabler->actor_reqs, actor_reqs);
8171
8172 target_reqs = lookup_req_list(file, sec_name, "target_reqs", action_text);
8173 if (target_reqs == nullptr) {
8174 ok = FALSE;
8175 break;
8176 }
8177
8178 requirement_vector_copy(&enabler->target_reqs, target_reqs);
8179
8180 comment = secfile_lookup_str(file, "%s.comment", sec_name);
8181 if (comment != nullptr) {
8182 enabler->rulesave.comment = fc_strdup(comment);
8183 }
8184
8187
8189 }
8190 }
8191
8192 return ok;
8193}
8194
8195/**********************************************************************/
8199static void send_ruleset_unit_classes(struct conn_list *dest)
8200{
8201 struct packet_ruleset_unit_class packet;
8203 int i;
8204
8205 for (i = 0; i < MAX_NUM_USER_UCLASS_FLAGS; i++) {
8206 const char *flagname;
8207 const char *helptxt;
8208
8210
8212 if (flagname == nullptr) {
8213 fpacket.name[0] = '\0';
8214 } else {
8216 }
8217
8219 if (helptxt == nullptr) {
8220 fpacket.helptxt[0] = '\0';
8221 } else {
8222 sz_strlcpy(fpacket.helptxt, helptxt);
8223 }
8224
8226 }
8227
8229 packet.id = uclass_number(c);
8230 sz_strlcpy(packet.name, untranslated_name(&c->name));
8231 sz_strlcpy(packet.rule_name, rule_name_get(&c->name));
8232 packet.min_speed = c->min_speed;
8233 packet.hp_loss_pct = c->hp_loss_pct;
8234 packet.non_native_def_pct = c->non_native_def_pct;
8235 packet.flags = c->flags;
8236
8237 PACKET_STRVEC_INSERT(packet.helptext, c->helptext);
8238
8239 lsend_packet_ruleset_unit_class(dest, &packet);
8241}
8242
8243/**********************************************************************/
8247static void send_ruleset_units(struct conn_list *dest)
8248{
8249 struct packet_ruleset_unit packet;
8250#ifdef FREECIV_WEB
8252#endif /* FREECIV_WEB */
8254 int i;
8255
8256 for (i = 0; i < MAX_NUM_USER_UNIT_FLAGS; i++) {
8257 const char *flagname;
8258 const char *helptxt;
8259
8261
8263 if (flagname == nullptr) {
8264 fpacket.name[0] = '\0';
8265 } else {
8267 }
8268
8270 if (helptxt == nullptr) {
8271 fpacket.helptxt[0] = '\0';
8272 } else {
8273 sz_strlcpy(fpacket.helptxt, helptxt);
8274 }
8275
8277 }
8278
8280 packet.id = utype_number(u);
8281 sz_strlcpy(packet.name, untranslated_name(&u->name));
8282 sz_strlcpy(packet.rule_name, rule_name_get(&u->name));
8283 sz_strlcpy(packet.sound_move, u->sound_move);
8284 sz_strlcpy(packet.sound_move_alt, u->sound_move_alt);
8285 sz_strlcpy(packet.sound_fight, u->sound_fight);
8286 sz_strlcpy(packet.sound_fight_alt, u->sound_fight_alt);
8287 sz_strlcpy(packet.graphic_str, u->graphic_str);
8288 sz_strlcpy(packet.graphic_alt, u->graphic_alt);
8289 sz_strlcpy(packet.graphic_alt2, u->graphic_alt2);
8291 packet.build_cost = u->build_cost;
8292 packet.pop_cost = u->pop_cost;
8293 packet.spectype_id = u->spec_type ? specialist_index(u->spec_type) : -1;
8294 packet.attack_strength = u->attack_strength;
8295 packet.defense_strength = u->defense_strength;
8296 packet.move_rate = u->move_rate;
8297
8298 /* Shallow-copy (borrow) requirement vector */
8299 packet.build_reqs = u->build_reqs;
8300
8301 packet.vision_radius_sq = u->vision_radius_sq;
8302 packet.transport_capacity = u->transport_capacity;
8303 packet.hp = u->hp;
8304 packet.firepower = u->firepower;
8305 packet.obsoleted_by = u->obsoleted_by
8306 ? utype_number(u->obsoleted_by)
8307 : utype_count();
8308 packet.converted_to = u->converted_to
8309 ? utype_number(u->converted_to)
8310 : utype_count();
8311 packet.convert_time = u->convert_time;
8312 packet.fuel = u->fuel;
8313 packet.flags = u->flags;
8314 packet.roles = u->roles;
8315 packet.happy_cost = u->happy_cost;
8317 packet.upkeep[o] = u->upkeep[o];
8319 packet.paratroopers_range = u->paratroopers_range;
8320 packet.bombard_rate = u->bombard_rate;
8321 packet.city_size = u->city_size;
8322 packet.city_slots = u->city_slots;
8323 packet.tp_defense = u->tp_defense;
8324 packet.cargo = u->cargo;
8325 packet.targets = u->targets;
8326 packet.embarks = u->embarks;
8327 packet.disembarks = u->disembarks;
8328 packet.vlayer = u->vlayer;
8329
8330 if (u->veteran == nullptr) {
8331 /* Use the default veteran system. */
8332 packet.veteran_levels = 0;
8333 } else {
8334 /* Per unit veteran system definition. */
8336
8337 for (i = 0; i < packet.veteran_levels; i++) {
8338 const struct veteran_level *vlevel = utype_veteran_level(u, i);
8339
8341 packet.power_fact[i] = vlevel->power_fact;
8342 packet.move_bonus[i] = vlevel->move_bonus;
8343 packet.base_raise_chance[i] = vlevel->base_raise_chance;
8344 packet.work_raise_chance[i] = vlevel->work_raise_chance;
8345 }
8346 }
8347 PACKET_STRVEC_INSERT(packet.helptext, u->helptext);
8348
8349 packet.worker = u->adv.worker;
8350
8351#ifdef FREECIV_WEB
8352 web_packet.id = utype_number(u);
8353
8354 BV_CLR_ALL(web_packet.utype_actions);
8355
8356 action_iterate(act) {
8357 if (utype_can_do_action(u, act)) {
8358 BV_SET(web_packet.utype_actions, act);
8359 }
8361#endif /* FREECIV_WEB */
8362
8363 lsend_packet_ruleset_unit(dest, &packet);
8365
8366 combat_bonus_list_iterate(u->bonuses, pbonus) {
8368
8369 bonuspacket.unit = packet.id;
8370 bonuspacket.flag = pbonus->flag;
8371 bonuspacket.type = pbonus->type;
8372 bonuspacket.value = pbonus->value;
8373 bonuspacket.quiet = pbonus->quiet;
8374
8378}
8379
8380/**********************************************************************/
8384static void send_ruleset_specialists(struct conn_list *dest)
8385{
8386 struct packet_ruleset_specialist packet;
8387
8390
8391 packet.id = spec_id;
8393 sz_strlcpy(packet.rule_name, rule_name_get(&s->name));
8397
8398 /* Shallow-copy (borrow) requirement vector */
8399 packet.reqs = s->reqs;
8400
8402
8403 lsend_packet_ruleset_specialist(dest, &packet);
8405}
8406/**********************************************************************/
8409static void send_ruleset_tech_classes(struct conn_list *dest)
8410{
8411 struct packet_ruleset_tech_class packet;
8412
8414 packet.id = ptclass->idx;
8415 sz_strlcpy(packet.name, untranslated_name(&ptclass->name));
8416 sz_strlcpy(packet.rule_name, rule_name_get(&ptclass->name));
8417 packet.cost_pct = ptclass->cost_pct;
8418
8419 lsend_packet_ruleset_tech_class(dest, &packet);
8421}
8422
8423/**********************************************************************/
8427static void send_ruleset_techs(struct conn_list *dest)
8428{
8429 struct packet_ruleset_tech packet;
8431 int i;
8432
8433 for (i = 0; i < MAX_NUM_USER_TECH_FLAGS; i++) {
8434 const char *flagname;
8435 const char *helptxt;
8436
8437 fpacket.id = i + TECH_USER_1;
8438
8440 if (flagname == nullptr) {
8441 fpacket.name[0] = '\0';
8442 } else {
8444 }
8445
8447 if (helptxt == nullptr) {
8448 fpacket.helptxt[0] = '\0';
8449 } else {
8450 sz_strlcpy(fpacket.helptxt, helptxt);
8451 }
8452
8454 }
8455
8456 /* Since we have to prepend the tech requirements to the requirement
8457 * vector, we need to initialize a separate vector and deep-copy the
8458 * other requirements into it. */
8460
8461 advance_iterate(a) {
8462 packet.id = advance_number(a);
8463 packet.removed = !valid_advance(a);
8464 if (a->tclass == nullptr) {
8465 packet.tclass = 0;
8466 } else {
8467 packet.tclass = a->tclass->idx;
8468 }
8469 sz_strlcpy(packet.name, untranslated_name(&a->name));
8470 sz_strlcpy(packet.rule_name, rule_name_get(&a->name));
8471 sz_strlcpy(packet.graphic_str, a->graphic_str);
8472 sz_strlcpy(packet.graphic_alt, a->graphic_alt);
8473
8474 /* Reset requirement vector. */
8476
8477 /* The requirements req1 and req2 are needed to research a tech. Send
8478 * them in the research_reqs requirement vector. Range is set to player
8479 * since pooled research is configurable. */
8480
8481 if ((a->require[AR_ONE] != A_NEVER)
8482 && advance_number(a->require[AR_ONE]) > A_NONE) {
8483 struct requirement req
8485 FALSE, TRUE, FALSE,
8486 advance_number(a->require[AR_ONE]));
8488 }
8489
8490 if ((a->require[AR_TWO] != A_NEVER)
8491 && advance_number(a->require[AR_TWO]) > A_NONE) {
8492 struct requirement req
8494 FALSE, TRUE, FALSE,
8495 advance_number(a->require[AR_TWO]));
8497 }
8498
8499 /* The requirements of the tech's research_reqs also goes in the
8500 * packet's research_reqs requirement vector. */
8501 requirement_vector_iterate(&a->research_reqs, req) {
8504
8505 packet.root_req = a->require[AR_ROOT]
8506 ? advance_number(a->require[AR_ROOT])
8507 : advance_count();
8508
8509 packet.flags = a->flags;
8510 packet.cost = a->cost;
8511 packet.num_reqs = a->num_reqs;
8512 PACKET_STRVEC_INSERT(packet.helptext, a->helptext);
8513
8514 lsend_packet_ruleset_tech(dest, &packet);
8516
8518}
8519
8520/**********************************************************************/
8523static void send_ruleset_counters(struct conn_list *dest)
8524{
8526 struct packet_ruleset_counter packet;
8527
8528 sz_strlcpy(packet.name, untranslated_name(&pcount->name));
8529 sz_strlcpy(packet.rule_name, rule_name_get(&pcount->name));
8530 packet.checkpoint = pcount->checkpoint;
8531 packet.behavior = pcount->type;
8532 packet.type = pcount->target;
8533 packet.def = pcount->def;
8534
8535 PACKET_STRVEC_INSERT(packet.helptext, pcount->helptext);
8536 lsend_packet_ruleset_counter(dest, &packet);
8538}
8539
8540/**********************************************************************/
8544static void send_ruleset_buildings(struct conn_list *dest)
8545{
8546 int i;
8547
8548 for (i = 0; i < MAX_NUM_USER_BUILDING_FLAGS; i++) {
8550 const char *flagname;
8551 const char *helptxt;
8552
8554
8556 if (flagname == nullptr) {
8557 fpacket.name[0] = '\0';
8558 } else {
8560 }
8561
8563 if (helptxt == nullptr) {
8564 fpacket.helptxt[0] = '\0';
8565 } else {
8566 sz_strlcpy(fpacket.helptxt, helptxt);
8567 }
8568
8570 }
8571
8573 struct packet_ruleset_building packet;
8574
8575 packet.id = improvement_number(b);
8576 packet.genus = b->genus;
8577 sz_strlcpy(packet.name, untranslated_name(&b->name));
8578 sz_strlcpy(packet.rule_name, rule_name_get(&b->name));
8579 sz_strlcpy(packet.graphic_str, b->graphic_str);
8580 sz_strlcpy(packet.graphic_alt, b->graphic_alt);
8581 sz_strlcpy(packet.graphic_alt2, b->graphic_alt2);
8582
8583 /* Shallow-copy (borrow) requirement vectors */
8584 packet.reqs = b->reqs;
8585 packet.obs_reqs = b->obsolete_by;
8586
8587 packet.build_cost = b->build_cost;
8588 packet.upkeep = b->upkeep;
8589 packet.sabotage = b->sabotage;
8590 packet.flags = b->flags;
8591 sz_strlcpy(packet.soundtag, b->soundtag);
8592 sz_strlcpy(packet.soundtag_alt, b->soundtag_alt);
8593 sz_strlcpy(packet.soundtag_alt2, b->soundtag_alt2);
8594 PACKET_STRVEC_INSERT(packet.helptext, b->helptext);
8595
8596 lsend_packet_ruleset_building(dest, &packet);
8598}
8599
8600/**********************************************************************/
8604static void send_ruleset_terrain(struct conn_list *dest)
8605{
8606 struct packet_ruleset_terrain packet;
8608 int i;
8609
8611
8612 for (i = 0; i < MAX_NUM_USER_TER_FLAGS; i++) {
8613 const char *flagname;
8614 const char *helptxt;
8615
8616 fpacket.id = i + TER_USER_1;
8617
8619 if (flagname == nullptr) {
8620 fpacket.name[0] = '\0';
8621 } else {
8623 }
8624
8626 if (helptxt == nullptr) {
8627 fpacket.helptxt[0] = '\0';
8628 } else {
8629 sz_strlcpy(fpacket.helptxt, helptxt);
8630 }
8631
8633 }
8634
8635 terrain_type_iterate(pterrain) {
8636 packet.id = terrain_number(pterrain);
8637 packet.tclass = pterrain->tclass;
8638 packet.native_to = pterrain->native_to;
8639
8640 sz_strlcpy(packet.name, untranslated_name(&pterrain->name));
8641 sz_strlcpy(packet.rule_name, rule_name_get(&pterrain->name));
8642 sz_strlcpy(packet.graphic_str, pterrain->graphic_str);
8643 sz_strlcpy(packet.graphic_alt, pterrain->graphic_alt);
8644 sz_strlcpy(packet.graphic_alt2, pterrain->graphic_alt2);
8645
8646 packet.movement_cost = pterrain->movement_cost;
8647 packet.defense_bonus = pterrain->defense_bonus;
8648
8650 packet.output[o] = pterrain->output[o];
8652
8653 packet.num_resources = 0;
8654 terrain_resources_iterate(pterrain, res, freq) {
8655 packet.resources[packet.num_resources] = extra_number(res);
8656 packet.resource_freq[packet.num_resources] = freq;
8657 packet.num_resources++;
8659
8661 packet.road_output_incr_pct[o] = pterrain->road_output_incr_pct[o];
8663
8664 packet.base_time = pterrain->base_time;
8665 packet.road_time = pterrain->road_time;
8666
8667 packet.cultivate_result = (pterrain->cultivate_result
8668 ? terrain_number(pterrain->cultivate_result)
8669 : terrain_count());
8670 packet.cultivate_time = pterrain->cultivate_time;
8671
8672 packet.plant_result = (pterrain->plant_result
8673 ? terrain_number(pterrain->plant_result)
8674 : terrain_count());
8675 packet.plant_time = pterrain->plant_time;
8676
8677 packet.irrigation_food_incr = pterrain->irrigation_food_incr;
8678 packet.irrigation_time = pterrain->irrigation_time;
8679
8680 packet.mining_shield_incr = pterrain->mining_shield_incr;
8681 packet.mining_time = pterrain->mining_time;
8682
8683 packet.num_animals = 0;
8684 terrain_animals_iterate(pterrain, panimal) {
8685 packet.animals[packet.num_animals] = utype_number(panimal);
8686 packet.num_animals++;
8688
8689 packet.transform_result = (pterrain->transform_result
8690 ? terrain_number(pterrain->transform_result)
8691 : terrain_count());
8692 packet.placing_time = pterrain->placing_time;
8693 packet.pillage_time = pterrain->pillage_time;
8694 packet.transform_time = pterrain->transform_time;
8695
8697 for (i = 0; i < game.control.num_extra_types; i++) {
8698 packet.extra_removal_times[i] = pterrain->extra_removal_times[i];
8699 }
8700
8701 packet.flags = pterrain->flags;
8702
8703 packet.color_red = pterrain->rgb->r;
8704 packet.color_green = pterrain->rgb->g;
8705 packet.color_blue = pterrain->rgb->b;
8706
8707 PACKET_STRVEC_INSERT(packet.helptext, pterrain->helptext);
8708
8709 lsend_packet_ruleset_terrain(dest, &packet);
8711}
8712
8713/**********************************************************************/
8716static void send_ruleset_resources(struct conn_list *dest)
8717{
8718 struct packet_ruleset_resource packet;
8719
8721 packet.id = extra_index(presource);
8722
8724 packet.output[o] = presource->data.resource->output[o];
8726
8727 lsend_packet_ruleset_resource(dest, &packet);
8729}
8730
8731/**********************************************************************/
8735static void send_ruleset_extras(struct conn_list *dest)
8736{
8737 int i;
8738
8739 for (i = 0; i < MAX_NUM_USER_EXTRA_FLAGS; i++) {
8741 const char *flagname;
8742 const char *helptxt;
8743
8745
8747 if (flagname == nullptr) {
8748 fpacket.name[0] = '\0';
8749 } else {
8751 }
8752
8754 if (helptxt == nullptr) {
8755 fpacket.helptxt[0] = '\0';
8756 } else {
8757 sz_strlcpy(fpacket.helptxt, helptxt);
8758 }
8759
8761 }
8762
8764 struct packet_ruleset_extra packet;
8765 int j;
8766
8767 packet.id = extra_number(e);
8768 sz_strlcpy(packet.name, untranslated_name(&e->name));
8769 sz_strlcpy(packet.rule_name, rule_name_get(&e->name));
8770
8771 packet.category = e->category;
8772
8773 BV_CLR_ALL(packet.causes);
8774 for (j = 0; j < EC_COUNT; j++) {
8775 if (is_extra_caused_by(e, j)) {
8776 BV_SET(packet.causes, j);
8777 }
8778 }
8779
8780 BV_CLR_ALL(packet.rmcauses);
8781 for (j = 0; j < ERM_COUNT; j++) {
8782 if (is_extra_removed_by(e, j)) {
8783 BV_SET(packet.rmcauses, j);
8784 }
8785 }
8786
8787 sz_strlcpy(packet.activity_gfx, e->activity_gfx);
8788 sz_strlcpy(packet.act_gfx_alt, e->act_gfx_alt);
8789 sz_strlcpy(packet.act_gfx_alt2, e->act_gfx_alt2);
8790 sz_strlcpy(packet.rmact_gfx, e->rmact_gfx);
8791 sz_strlcpy(packet.rmact_gfx_alt, e->rmact_gfx_alt);
8792 sz_strlcpy(packet.rmact_gfx_alt2, e->rmact_gfx_alt2);
8793 sz_strlcpy(packet.graphic_str, e->graphic_str);
8794 sz_strlcpy(packet.graphic_alt, e->graphic_alt);
8795
8796 /* Shallow-copy (borrow) requirement vectors */
8797 packet.reqs = e->reqs;
8798 packet.rmreqs = e->rmreqs;
8799
8800 packet.appearance_chance = e->appearance_chance;
8801 /* Shallow-copy (borrow) requirement vector */
8802 packet.appearance_reqs = e->appearance_reqs;
8803
8804 packet.disappearance_chance = e->disappearance_chance;
8805 /* Shallow-copy (borrow) requirement vector */
8806 packet.disappearance_reqs = e->disappearance_reqs;
8807
8808 packet.visibility_req = e->visibility_req;
8809 packet.buildable = e->buildable;
8810 packet.generated = e->generated;
8811 packet.build_time = e->build_time;
8812 packet.build_time_factor = e->build_time_factor;
8813 packet.removal_time = e->removal_time;
8814 packet.removal_time_factor = e->removal_time_factor;
8815 packet.infracost = e->infracost;
8816 packet.defense_bonus = e->defense_bonus;
8817 packet.eus = e->eus;
8818 packet.no_aggr_near_city = e->no_aggr_near_city;
8819
8820 packet.native_to = e->native_to;
8821
8822 packet.flags = e->flags;
8823 packet.hidden_by = e->hidden_by;
8824 packet.bridged_over = e->bridged_over;
8825 packet.conflicts = e->conflicts;
8826
8827 PACKET_STRVEC_INSERT(packet.helptext, e->helptext);
8828
8829 lsend_packet_ruleset_extra(dest, &packet);
8831}
8832
8833/**********************************************************************/
8837static void send_ruleset_bases(struct conn_list *dest)
8838{
8840 struct base_type *b = extra_base_get(pextra);
8841 struct packet_ruleset_base packet;
8842
8843 packet.id = base_number(b);
8844
8845 packet.gui_type = b->gui_type;
8846 packet.border_sq = b->border_sq;
8847 packet.vision_main_sq = b->vision_main_sq;
8848 packet.vision_invis_sq = b->vision_invis_sq;
8849 packet.vision_subs_sq = b->vision_subs_sq;
8850
8851 lsend_packet_ruleset_base(dest, &packet);
8853}
8854
8855/**********************************************************************/
8859static void send_ruleset_roads(struct conn_list *dest)
8860{
8861 struct packet_ruleset_road packet;
8862
8864 struct road_type *r = extra_road_get(pextra);
8865
8866 packet.id = road_number(r);
8867
8868 packet.gui_type = r->gui_type;
8869
8870 /* Shallow-copy (borrow) requirement vector */
8871 packet.first_reqs = r->first_reqs;
8872
8873 packet.move_cost = r->move_cost;
8874 packet.move_mode = r->move_mode;
8875
8877 packet.tile_incr_const[o] = r->tile_incr_const[o];
8878 packet.tile_incr[o] = r->tile_incr[o];
8879 packet.tile_bonus[o] = r->tile_bonus[o];
8881
8882 packet.compat = r->compat;
8883
8884 packet.integrates = r->integrates;
8885 packet.flags = r->flags;
8886
8887 lsend_packet_ruleset_road(dest, &packet);
8889}
8890
8891/**********************************************************************/
8895static void send_ruleset_tiledefs(struct conn_list *dest)
8896{
8897 struct packet_ruleset_tiledef packet;
8898
8901
8902 packet.id = tiledef_number(td);
8903 sz_strlcpy(packet.name, untranslated_name(&td->name));
8904 sz_strlcpy(packet.rule_name, rule_name_get(&td->name));
8905
8907 extra_type_list_iterate(td->extras, pextra) {
8908 BV_SET(extras, extra_index(pextra));
8910
8911 packet.extras = extras;
8912
8913 packet.known = td->known;
8914 packet.owned = td->owned;
8915
8916 lsend_packet_ruleset_tiledef(dest, &packet);
8918}
8919
8920/**********************************************************************/
8924static void send_ruleset_goods(struct conn_list *dest)
8925{
8926 struct packet_ruleset_goods packet;
8927
8929 packet.id = goods_number(g);
8930 sz_strlcpy(packet.name, untranslated_name(&g->name));
8931 sz_strlcpy(packet.rule_name, rule_name_get(&g->name));
8932
8933 /* Shallow-copy (borrow) requirement vector */
8934 packet.reqs = g->reqs;
8935
8936 packet.from_pct = g->from_pct;
8937 packet.to_pct = g->to_pct;
8938 packet.onetime_pct = g->onetime_pct;
8939 packet.select_priority = g->select_priority;
8940 packet.replace_priority = g->replace_priority;
8941 packet.flags = g->flags;
8942
8943 PACKET_STRVEC_INSERT(packet.helptext, g->helptext);
8944
8945 lsend_packet_ruleset_goods(dest, &packet);
8947}
8948
8949/**********************************************************************/
8953static void send_ruleset_disasters(struct conn_list *dest)
8954{
8955 struct packet_ruleset_disaster packet;
8956
8958 packet.id = disaster_number(d);
8959
8960 sz_strlcpy(packet.name, untranslated_name(&d->name));
8961 sz_strlcpy(packet.rule_name, rule_name_get(&d->name));
8962
8963 /* Shallow-copy (borrow) requirement vector */
8964 packet.reqs = d->reqs;
8965
8966 packet.frequency = d->frequency;
8967
8968 packet.effects = d->effects;
8969
8970 lsend_packet_ruleset_disaster(dest, &packet);
8972}
8973
8974/**********************************************************************/
8978static void send_ruleset_achievements(struct conn_list *dest)
8979{
8980 struct packet_ruleset_achievement packet;
8981
8983 packet.id = achievement_number(a);
8984
8985 sz_strlcpy(packet.name, untranslated_name(&a->name));
8986 sz_strlcpy(packet.rule_name, rule_name_get(&a->name));
8987
8988 packet.type = a->type;
8989 packet.unique = a->unique;
8990 packet.value = a->value;
8991
8992 lsend_packet_ruleset_achievement(dest, &packet);
8994}
8995
8996/**********************************************************************/
8999static void send_ruleset_actions(struct conn_list *dest)
9000{
9001 struct packet_ruleset_action packet;
9002
9003 action_iterate(act) {
9004 struct action *paction = action_by_number(act);
9005
9006 packet.id = act;
9008 packet.quiet = action_by_number(act)->quiet;
9009
9010 packet.result = paction->result;
9011 packet.sub_results = paction->sub_results;
9012 packet.actor_consuming_always = paction->actor_consuming_always;
9013
9014 packet.act_kind = action_by_number(act)->actor_kind;
9015 packet.tgt_kind = action_by_number(act)->target_kind;
9017
9020 packet.blocked_by = action_by_number(act)->blocked_by;
9021
9022 lsend_packet_ruleset_action(dest, &packet);
9024}
9025
9026/**********************************************************************/
9030{
9031 struct packet_ruleset_action_enabler packet;
9032
9035
9036 /* Shallow-copy (borrow) requirement vectors */
9037 packet.actor_reqs = enabler->actor_reqs;
9038 packet.target_reqs = enabler->target_reqs;
9039
9042}
9043
9044/**********************************************************************/
9049{
9050 int counter;
9051 int id;
9052 struct packet_ruleset_action_auto packet;
9053
9054 id = 0;
9056 packet.id = id++;
9057
9058 packet.cause = aperf->cause;
9059
9060 /* Shallow-copy (borrow) requirement vector */
9061 packet.reqs = aperf->reqs;
9062
9063 for (counter = 0;
9064 /* Can't list more actions than all actions. */
9066 /* ACTION_NONE terminates the list. */
9067 && aperf->alternatives[counter] != ACTION_NONE;
9068 counter++) {
9069 packet.alternatives[counter] = aperf->alternatives[counter];
9070 }
9071 packet.alternatives_count = counter;
9072
9073 lsend_packet_ruleset_action_auto(dest, &packet);
9075}
9076
9077/**********************************************************************/
9081static void send_ruleset_trade_routes(struct conn_list *dest)
9082{
9083 struct packet_ruleset_trade packet;
9085
9086 for (type = TRT_NATIONAL; type < TRT_LAST; type++) {
9088
9089 packet.id = type;
9090 packet.trade_pct = set->trade_pct;
9091 packet.cancelling = set->cancelling;
9092 packet.bonus_type = set->bonus_type;
9093
9094 lsend_packet_ruleset_trade(dest, &packet);
9095 }
9096}
9097
9098/**********************************************************************/
9102static void send_ruleset_governments(struct conn_list *dest)
9103{
9104 struct packet_ruleset_government gov;
9106 int i;
9107
9108 for (i = 0; i < MAX_NUM_USER_GOVERNMENT_FLAGS; i++) {
9110 const char *flagname;
9111 const char *helptxt;
9112
9114
9116 if (flagname == nullptr) {
9117 fpacket.name[0] = '\0';
9118 } else {
9120 }
9121
9123 if (helptxt == nullptr) {
9124 fpacket.helptxt[0] = '\0';
9125 } else {
9126 sz_strlcpy(fpacket.helptxt, helptxt);
9127 }
9128
9130 }
9131
9133 /* Send one packet_government */
9134 gov.id = government_number(g);
9135
9136 /* Shallow-copy (borrow) requirement vector */
9137 gov.reqs = g->reqs;
9138
9139 gov.flags = g->flags;
9140
9141 sz_strlcpy(gov.name, untranslated_name(&g->name));
9142 sz_strlcpy(gov.rule_name, rule_name_get(&g->name));
9143 sz_strlcpy(gov.graphic_str, g->graphic_str);
9144 sz_strlcpy(gov.graphic_alt, g->graphic_alt);
9145 sz_strlcpy(gov.sound_str, g->sound_str);
9146 sz_strlcpy(gov.sound_alt, g->sound_alt);
9147 sz_strlcpy(gov.sound_alt2, g->sound_alt2);
9148 PACKET_STRVEC_INSERT(gov.helptext, g->helptext);
9149
9151
9152 /* Send one packet_government_ruler_title per ruler title. */
9154 const struct nation_type *pnation = ruler_title_nation(pruler_title);
9155
9156 title.gov = government_number(g);
9157 title.nation = pnation ? nation_number(pnation) : nation_count();
9158 sz_strlcpy(title.male_title,
9160 sz_strlcpy(title.female_title,
9165}
9166
9167/**********************************************************************/
9171static void send_ruleset_nations(struct conn_list *dest)
9172{
9175 struct packet_ruleset_nation packet;
9176 int i;
9177
9179 i = 0;
9184 i++;
9187
9189 i = 0;
9191 sz_strlcpy(groups_packet.groups[i],
9193 groups_packet.hidden[i] = pgroup->hidden;
9194 i++;
9197
9199 packet.id = nation_number(n);
9200 if (n->translation_domain == nullptr) {
9201 packet.translation_domain[0] = '\0';
9202 } else {
9203 sz_strlcpy(packet.translation_domain, n->translation_domain);
9204 }
9205 sz_strlcpy(packet.adjective, untranslated_name(&n->adjective));
9206 sz_strlcpy(packet.rule_name, rule_name_get(&n->adjective));
9207 sz_strlcpy(packet.noun_plural, untranslated_name(&n->noun_plural));
9208 sz_strlcpy(packet.graphic_str, n->flag_graphic_str);
9209 sz_strlcpy(packet.graphic_alt, n->flag_graphic_alt);
9210
9211 i = 0;
9215 i++;
9217 packet.leader_count = i;
9218
9219 packet.style = style_number(n->style);
9220 packet.is_playable = n->is_playable;
9221 packet.barbarian_type = n->barb_type;
9222
9223 sz_strlcpy(packet.legend, n->legend);
9224
9225 i = 0;
9227 packet.sets[i++] = nation_set_number(pset);
9229 packet.nsets = i;
9230
9231 i = 0;
9233 packet.groups[i++] = nation_group_number(pgroup);
9235 packet.ngroups = i;
9236
9237 packet.init_government_id = n->init_government
9238 ? government_number(n->init_government) : government_count();
9239 fc_assert(ARRAY_SIZE(packet.init_techs) == ARRAY_SIZE(n->init_techs));
9240 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
9241 if (n->init_techs[i] != A_LAST) {
9242 packet.init_techs[i] = n->init_techs[i];
9243 } else {
9244 break;
9245 }
9246 }
9247 packet.init_techs_count = i;
9248 fc_assert(ARRAY_SIZE(packet.init_units) == ARRAY_SIZE(n->init_units));
9249 for (i = 0; i < MAX_NUM_UNIT_LIST; i++) {
9250 const struct unit_type *t = n->init_units[i];
9251 if (t) {
9252 packet.init_units[i] = utype_number(t);
9253 } else {
9254 break;
9255 }
9256 }
9257 packet.init_units_count = i;
9259 == ARRAY_SIZE(n->init_buildings));
9260 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
9261 if (n->init_buildings[i] != B_LAST) {
9262 /* Impr_type_id to int */
9263 packet.init_buildings[i] = n->init_buildings[i];
9264 } else {
9265 break;
9266 }
9267 }
9268 packet.init_buildings_count = i;
9269
9270 lsend_packet_ruleset_nation(dest, &packet);
9272
9273 /* Send initial values of is_pickable */
9275}
9276
9277/**********************************************************************/
9281static void send_ruleset_styles(struct conn_list *dest)
9282{
9283 struct packet_ruleset_style packet;
9284
9285 styles_iterate(s) {
9286 packet.id = style_index(s);
9287 sz_strlcpy(packet.name, untranslated_name(&s->name));
9288 sz_strlcpy(packet.rule_name, rule_name_get(&s->name));
9289
9290 lsend_packet_ruleset_style(dest, &packet);
9292}
9293
9294/**********************************************************************/
9297static void send_ruleset_clauses(struct conn_list *dest)
9298{
9299 struct packet_ruleset_clause packet;
9300 int i;
9301
9302 for (i = 0; i < CLAUSE_COUNT; i++) {
9303 struct clause_info *info = clause_info_get(i);
9304
9305 packet.type = i;
9306 packet.enabled = info->enabled;
9307
9308 /* Shallow-copy (borrow) requirement vectors */
9309 packet.giver_reqs = info->giver_reqs;
9310 packet.receiver_reqs = info->receiver_reqs;
9311 packet.either_reqs = info->either_reqs;
9312
9313 lsend_packet_ruleset_clause(dest, &packet);
9314 }
9315}
9316
9317/**********************************************************************/
9321static void send_ruleset_multipliers(struct conn_list *dest)
9322{
9323 multipliers_iterate(pmul) {
9324 struct packet_ruleset_multiplier packet;
9325
9326 packet.id = multiplier_number(pmul);
9327 packet.start = pmul->start;
9328 packet.stop = pmul->stop;
9329 packet.step = pmul->step;
9330 packet.def = pmul->def;
9331 packet.offset = pmul->offset;
9332 packet.factor = pmul->factor;
9333 packet.minimum_turns = pmul->minimum_turns;
9334
9335 sz_strlcpy(packet.name, untranslated_name(&pmul->name));
9336 sz_strlcpy(packet.rule_name, rule_name_get(&pmul->name));
9337
9338 /* Shallow-copy (borrow) requirement vector */
9339 packet.reqs = pmul->reqs;
9340
9341 PACKET_STRVEC_INSERT(packet.helptext, pmul->helptext);
9342
9343 lsend_packet_ruleset_multiplier(dest, &packet);
9345}
9346
9347/**********************************************************************/
9351static void send_ruleset_cities(struct conn_list *dest)
9352{
9354 int k;
9355
9356 for (k = 0; k < game.control.num_city_styles; k++) {
9357 city_p.style_id = k;
9358
9359 /* Shallow-copy (borrow) requirement vector */
9360 city_p.reqs = city_styles[k].reqs;
9361
9364 sz_strlcpy(city_p.graphic, city_styles[k].graphic);
9365 sz_strlcpy(city_p.graphic_alt, city_styles[k].graphic_alt);
9366 sz_strlcpy(city_p.citizens_graphic, city_styles[k].citizens_graphic);
9367
9369 }
9370}
9371
9372/**********************************************************************/
9376static void send_ruleset_musics(struct conn_list *dest)
9377{
9378 struct packet_ruleset_music packet;
9379
9381 packet.id = pmus->id;
9382
9383 sz_strlcpy(packet.music_peaceful, pmus->music_peaceful);
9384 sz_strlcpy(packet.music_combat, pmus->music_combat);
9385
9386 /* Shallow-copy (borrow) requirement vector */
9387 packet.reqs = pmus->reqs;
9388
9389 lsend_packet_ruleset_music(dest, &packet);
9391}
9392
9393/**********************************************************************/
9397static void send_ruleset_game(struct conn_list *dest)
9398{
9400 int i;
9401
9402 fc_assert_ret(game.veteran != nullptr);
9403
9404 /* Per unit veteran system definition. */
9405 misc_p.veteran_levels = game.veteran->levels;
9406
9407 for (i = 0; i < misc_p.veteran_levels; i++) {
9408 const struct veteran_level *vlevel = game.veteran->definitions + i;
9409
9410 sz_strlcpy(misc_p.veteran_name[i], untranslated_name(&vlevel->name));
9411 misc_p.power_fact[i] = vlevel->power_fact;
9412 misc_p.move_bonus[i] = vlevel->move_bonus;
9413 misc_p.base_raise_chance[i] = vlevel->base_raise_chance;
9414 misc_p.work_raise_chance[i] = vlevel->work_raise_chance;
9415 }
9416
9417 fc_assert(sizeof(misc_p.global_init_techs)
9418 == sizeof(game.rgame.global_init_techs));
9419 fc_assert(ARRAY_SIZE(misc_p.global_init_techs)
9421 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
9423 misc_p.global_init_techs[i] = game.rgame.global_init_techs[i];
9424 } else {
9425 break;
9426 }
9427 }
9428 misc_p.global_init_techs_count = i;
9429
9430 fc_assert(ARRAY_SIZE(misc_p.global_init_buildings)
9432 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
9434 /* Impr_type_id to int */
9435 misc_p.global_init_buildings[i] =
9437 } else {
9438 break;
9439 }
9440 }
9441 misc_p.global_init_buildings_count = i;
9442
9443 misc_p.default_specialist = DEFAULT_SPECIALIST;
9444
9445 fc_assert_ret(game.plr_bg_color != nullptr);
9446
9447 misc_p.background_red = game.plr_bg_color->r;
9448 misc_p.background_green = game.plr_bg_color->g;
9449 misc_p.background_blue = game.plr_bg_color->b;
9450
9452}
9453
9454/**********************************************************************/
9458static void send_ruleset_team_names(struct conn_list *dest)
9459{
9461
9463 const char *name = team_slot_defined_name(tslot);
9464
9465 if (name == nullptr) {
9466 /* End of defined names. */
9467 break;
9468 }
9469
9471 sz_strlcpy(team_name_info_p.team_name, name);
9472
9475}
9476
9477/**********************************************************************/
9480static void notify_ruleset_fallback(const char *msg)
9481{
9482 notify_conn(nullptr, nullptr, E_LOG_FATAL, ftc_warning, "%s", msg);
9483}
9484
9485/**********************************************************************/
9488bool load_rulesets(const char *restore, const char *alt, bool compat_mode,
9489 rs_conversion_logger logger,
9490 bool act, bool buffer_script, bool load_luadata)
9491{
9492 set_ruleset_compat_mode(compat_mode);
9493
9494 if (load_rulesetdir(game.server.rulesetdir, compat_mode, logger,
9495 act, buffer_script, load_luadata)) {
9497 return TRUE;
9498 }
9499
9500 if (alt != nullptr) {
9501 if (load_rulesetdir(alt, compat_mode, logger, act, buffer_script,
9502 load_luadata)) {
9504
9506 return TRUE;
9507 }
9508 }
9509
9510 /* Fallback to previous one. */
9511 if (restore != nullptr) {
9512 if (load_rulesetdir(restore, compat_mode, logger, act, buffer_script, TRUE)) {
9514
9515 notify_ruleset_fallback(_("Ruleset couldn't be loaded. Keeping previous one."));
9516
9518
9519 /* We're in sane state as restoring previous ruleset succeeded,
9520 * but return failure to indicate that this is not what caller
9521 * wanted. */
9522 return FALSE;
9523 }
9524 }
9525
9527
9528 /* Fallback to default one, but not if that's what we tried already */
9530 && (restore == nullptr || strcmp(GAME_DEFAULT_RULESETDIR, restore))) {
9532 buffer_script, TRUE)) {
9533 /* We're in sane state as fallback ruleset loading succeeded,
9534 * but return failure to indicate that this is not what caller
9535 * wanted. */
9537
9538 notify_ruleset_fallback(_("Ruleset couldn't be loaded. Switching to default one."));
9539
9540 return FALSE;
9541 }
9542 }
9543
9544#ifdef FREECIV_WEB
9545 log_normal(_("Cannot load any ruleset. Freeciv-web ruleset is available from "
9546 "https://github.com/freeciv/freeciv-web"));
9547#endif /* FREECIV_WEB */
9548
9549 /* Cannot load even default ruleset, we're in completely unusable state */
9551
9553}
9554
9555/**********************************************************************/
9559{
9560 if (file != nullptr) {
9561 secfile_destroy(file);
9562 }
9563}
9564
9565/**********************************************************************/
9575
9576/**********************************************************************/
9580static bool load_rulesetdir(const char *rsdir, bool compat_mode,
9581 rs_conversion_logger logger,
9582 bool act, bool buffer_script, bool load_luadata)
9583{
9586 struct section_file *actionfile;
9587 bool ok = TRUE;
9589
9590 log_normal(_("Loading rulesets."));
9591
9593 compat_info.compat_mode = compat_mode;
9594 compat_info.log_cb = logger;
9595
9598 /* Reset the list of available player colors. */
9602
9603 if (script_buffer != nullptr) {
9605 script_buffer = nullptr;
9606 }
9607 if (parser_buffer != nullptr) {
9609 parser_buffer = nullptr;
9610 }
9611
9612 server.playable_nations = 0;
9613
9617 buildfile = openload_ruleset_file("buildings", rsdir);
9618 govfile = openload_ruleset_file("governments", rsdir);
9620 terrfile = openload_ruleset_file("terrain", rsdir);
9625
9626 if (load_luadata) {
9628 } else {
9629 game.server.luadata = nullptr;
9630 }
9631
9632 if (techfile == nullptr
9633 || buildfile == nullptr
9634 || govfile == nullptr
9635 || unitfile == nullptr
9636 || terrfile == nullptr
9637 || stylefile == nullptr
9638 || cityfile == nullptr
9639 || nationfile == nullptr
9640 || effectfile == nullptr
9641 || actionfile == nullptr
9642 || gamefile == nullptr) {
9643 ok = FALSE;
9644 }
9645
9646 if (ok) {
9647 /* Note: Keep load_game_names() first so that compat_info.version is
9648 * correctly initialized. */
9658 }
9659
9660 if (ok) {
9662 }
9663
9664 if (ok) {
9666 }
9667 if (ok) {
9669 }
9670 if (ok) {
9672 }
9673 if (ok) {
9675 }
9676 if (ok) {
9677 /* Terrain must precede nations and units */
9679 }
9680 if (ok) {
9682 }
9683 if (ok) {
9685 }
9686 if (ok) {
9688 }
9689 if (ok) {
9691 }
9692 if (ok) {
9694 }
9695 if (ok) {
9697 }
9698
9699 if (ok) {
9700 /* Init nations we just loaded. */
9702
9703 /* Needed by role_unit_precalcs(). */
9705
9706 /* Prepare caches we want to sanity check. */
9710
9713 }
9714
9715 if (ok) {
9716 /* Only load settings for a sane ruleset */
9717 ok = settings_ruleset(gamefile, "settings", act,
9718 compat_info.compat_mode
9719 && compat_info.version < RSFORMAT_CURRENT);
9720
9721 if (ok) {
9723 }
9724 }
9725
9737
9738 if (extra_sections) {
9740 extra_sections = nullptr;
9741 }
9742 if (base_sections) {
9744 base_sections = nullptr;
9745 }
9746 if (road_sections) {
9748 road_sections = nullptr;
9749 }
9750 if (resource_sections) {
9752 resource_sections = nullptr;
9753 }
9754 if (terrain_sections) {
9756 terrain_sections = nullptr;
9757 }
9758
9759 if (ok) {
9761 }
9762
9763 if (ok) {
9764 char **buffer = buffer_script ? &script_buffer : nullptr;
9765
9767
9769
9770 ok = (openload_script_file("script", rsdir, buffer, FALSE) == TRI_YES);
9771 }
9772
9773 if (ok) {
9774 enum fc_tristate pret;
9775 char **buffer = buffer_script ? &parser_buffer : nullptr;
9776
9777 pret = openload_script_file("parser", rsdir, buffer, compat_info.compat_mode);
9778
9779 if (pret == TRI_MAYBE && buffer_script) {
9781 "-- This file is for lua-functionality for parsing luadata.txt\n-- of this ruleset.");
9782 }
9783
9784 ok = (pret != TRI_NO);
9785 }
9786
9787 if (ok && !buffer_script) {
9788 ok = (openload_script_file("default", rsdir, nullptr, FALSE) == TRI_YES);
9789 }
9790
9791 if (ok && act) {
9792 /* Populate remaining caches. */
9799 ptype->unknown_move_cost = utype_unknown_move_cost(ptype);
9803
9804 /* Build advisors unit class cache corresponding to loaded rulesets */
9806 CALL_FUNC_EACH_AI(units_ruleset_init);
9807
9808 /* We may need to adjust the number of AI players
9809 * if the number of available nations changed. */
9811 }
9812
9813 return ok;
9814}
9815
9816/**********************************************************************/
9820{
9821 struct section_file *file;
9822 bool ok = TRUE;
9823
9825 if (file == nullptr) {
9826 ruleset_error(nullptr, LOG_ERROR,
9827 "Could not load game.ruleset:\n%s",
9828 secfile_error());
9829 ok = FALSE;
9830 }
9831 if (ok) {
9832 settings_ruleset(file, "settings", TRUE, FALSE);
9833 secfile_destroy(file);
9834 }
9835
9836 return ok;
9837}
9838
9839/**********************************************************************/
9842void send_rulesets(struct conn_list *dest)
9843{
9845
9846 /* ruleset_control also indicates to client that ruleset sending starts. */
9848
9849 /* Currently containing control-kind of data of nation sets and groups,
9850 * this too must be sent before any requirement vector may depend on
9851 * that data. */
9853
9854 send_ruleset_game(dest);
9864 send_ruleset_techs(dest);
9867 send_ruleset_units(dest);
9869 send_ruleset_extras(dest);
9870 send_ruleset_bases(dest);
9871 send_ruleset_roads(dest);
9875 send_ruleset_goods(dest);
9877 send_ruleset_styles(dest);
9879 send_ruleset_cities(dest);
9881 send_ruleset_musics(dest);
9882 send_ruleset_cache(dest);
9883
9884 /* Indicate client that all rulesets have now been sent. */
9886
9887 /* Changed game settings will be send in
9888 * connecthand.c:establish_new_connection() */
9889
9891}
void access_info_init(const struct unit_type *aunit)
Definition accessarea.c:39
void access_info_close(void)
Definition accessarea.c:55
int achievement_index(const struct achievement *pach)
int achievement_number(const struct achievement *pach)
#define achievements_iterate_end
#define achievements_iterate(_ach_)
struct action_auto_perf * action_auto_perf_slot_number(const int num)
Definition actions.c:5966
void actions_rs_pre_san_gen(void)
Definition actions.c:904
const char * action_min_range_ruleset_var_name(int act)
Definition actions.c:6420
const char * action_blocked_by_ruleset_var_name(const struct action *act)
Definition actions.c:7143
bool action_is_in_use(struct action *paction)
Definition actions.c:5920
const char * action_post_success_forced_ruleset_var_name(const struct action *act)
Definition actions.c:7340
struct action * action_by_rule_name(const char *name)
Definition actions.c:1105
const char * action_rule_name(const struct action *action)
Definition actions.c:1242
const char * action_actor_consuming_always_ruleset_var_name(action_id act)
Definition actions.c:6967
const char * action_max_range_ruleset_var_name(int act)
Definition actions.c:6601
const char * action_target_kind_ruleset_var_name(int act)
Definition actions.c:6792
void action_enabler_add(struct action_enabler *enabler)
Definition actions.c:1552
const char * action_ui_name_default(int act)
Definition actions.c:6049
struct action_enabler * action_enabler_new(void)
Definition actions.c:1501
bool action_enabler_possible_actor(const struct action_enabler *ae)
Definition actions.c:5855
struct action_enabler_list * action_enablers_for_action(action_id action)
Definition actions.c:1585
#define action_by_result_iterate(_paction_, _result_)
Definition actions.h:245
#define action_auto_perf_iterate_end
Definition actions.h:350
#define action_enablers_iterate_end
Definition actions.h:283
#define ACTION_AUTO_MOVED_ADJ
Definition actions.h:375
#define ACTION_AUTO_POST_BRIBE_UNIT
Definition actions.h:376
#define action_id_get_sub_target_kind(act_id)
Definition actions.h:421
#define ACTION_AUTO_UPKEEP_GOLD
Definition actions.h:373
#define enabler_get_action_id(_enabler_)
Definition actions.h:187
static struct action * action_by_number(action_id act_id)
Definition actions.h:400
#define NUM_ACTIONS
Definition actions.h:63
#define ACTION_AUTO_ESCAPE_STACK
Definition actions.h:382
#define action_has_result(_act_, _res_)
Definition actions.h:184
#define ACTION_AUTO_ESCAPE_CITY
Definition actions.h:381
#define action_enabler_list_iterate_end
Definition actions.h:194
#define ACTION_DISTANCE_UNLIMITED
Definition actions.h:105
#define action_by_result_iterate_end
Definition actions.h:249
#define ACTION_AUTO_POST_WIPE_UNITS
Definition actions.h:383
#define ACTION_AUTO_UPKEEP_SHIELD
Definition actions.h:374
#define action_iterate_end
Definition actions.h:218
#define ACTION_AUTO_POST_BRIBE_STACK
Definition actions.h:377
#define action_enablers_iterate(_enabler_)
Definition actions.h:277
#define ACTION_AUTO_POST_ATTACK2
Definition actions.h:379
#define action_enabler_list_iterate(action_enabler_list, aenabler)
Definition actions.h:192
#define action_id(_act_)
Definition actions.h:426
#define action_iterate(_act_)
Definition actions.h:214
#define action_auto_perf_iterate(_act_perf_)
Definition actions.h:338
#define ACTION_AUTO_UPKEEP_FOOD
Definition actions.h:372
#define ACTION_AUTO_POST_ATTACK
Definition actions.h:378
#define ACTION_AUTO_POST_COLLECT_RANSOM
Definition actions.h:380
#define ACTION_NONE
Definition actions.h:59
int actres_min_range_default(enum action_result result)
Definition actres.c:380
int actres_max_range_default(enum action_result result)
Definition actres.c:471
enum action_target_kind actres_target_kind_default(enum action_result result)
Definition actres.c:778
void adv_units_ruleset_init(void)
Definition advruleset.c:33
#define CALL_FUNC_EACH_AI(_func,...)
Definition ai.h:390
#define str
Definition astring.c:76
#define n
Definition astring.c:77
Base_type_id base_number(const struct base_type *pbase)
Definition base.c:96
void base_type_init(struct extra_type *pextra, int idx)
Definition base.c:122
bool territory_claiming_base(const struct base_type *pbase)
Definition base.c:163
#define BV_CLR_ALL(bv)
Definition bitvector.h:103
#define BV_SET(bv, bit)
Definition bitvector.h:89
#define BV_ISSET(bv, bit)
Definition bitvector.h:86
void city_styles_alloc(int num)
Definition city.c:3504
void city_production_caravan_shields_init(void)
Definition city.c:1831
const char * city_style_rule_name(const int style)
Definition city.c:1818
const char * get_output_identifier(Output_type_id output)
Definition city.c:619
static const struct city struct citystyle * city_styles
Definition city.c:84
#define output_type_iterate(output)
Definition city.h:853
#define output_type_iterate_end
Definition city.h:859
static struct fc_sockaddr_list * list
Definition clinet.c:102
char * incite_cost
Definition comments.c:77
#define MAX_LEN_CONTENT
Definition conn_types.h:32
#define MAX_LEN_MSG
Definition conn_types.h:37
void conn_list_compression_thaw(const struct conn_list *pconn_list)
Definition connection.c:734
void conn_list_compression_freeze(const struct conn_list *pconn_list)
Definition connection.c:722
struct counter * counter_by_id(int id)
Definition counters.c:82
void attach_city_counter(struct counter *counter)
Definition counters.c:94
#define city_counters_iterate_end
Definition counters.h:64
#define city_counters_iterate(pcount)
Definition counters.h:57
struct clause_info * clause_info_get(enum clause_type type)
Definition diptreaty.c:292
const char * disaster_rule_name(struct disaster_type *pdis)
Definition disaster.c:105
Disaster_type_id disaster_number(const struct disaster_type *pdis)
Definition disaster.c:56
Disaster_type_id disaster_index(const struct disaster_type *pdis)
Definition disaster.c:69
#define disaster_type_iterate(_p)
Definition disaster.h:82
#define disaster_type_iterate_end
Definition disaster.h:88
int int id
Definition editgui_g.h:28
struct @22::@23 reqs
void send_ruleset_cache(struct conn_list *dest)
Definition effects.c:609
struct effect * effect_new(enum effect_type type, int value, struct multiplier *pmul)
Definition effects.c:186
void user_effect_ai_valued_set(enum effect_type tgt, enum effect_type valued_as)
Definition effects.c:1354
struct effect_list * get_effects(enum effect_type effect_type)
Definition effects.c:143
enum effect_type user_effect_ai_valued_as(enum effect_type real)
Definition effects.c:1365
void effect_req_append(struct effect *peffect, struct requirement req)
Definition effects.c:266
bool is_user_effect(enum effect_type eff)
Definition effects.c:1345
#define effect_list_iterate_end
Definition effects.h:81
#define effect_list_iterate(effect_list, peffect)
Definition effects.h:79
struct extra_type * extra_type_by_rule_name(const char *name)
Definition extras.c:212
const char * extra_flag_helptxt(enum extra_flag_id id)
Definition extras.c:988
void set_user_extra_flag_name(enum extra_flag_id id, const char *name, const char *helptxt)
Definition extras.c:947
bool is_extra_caused_by_worker_action(const struct extra_type *pextra)
Definition extras.c:1046
struct extra_type_list * extra_type_list_of_zoccers(void)
Definition extras.c:267
int extra_number(const struct extra_type *pextra)
Definition extras.c:161
bool extra_has_flag(const struct extra_type *pextra, enum extra_flag_id flag)
Definition extras.c:875
struct extra_type_list * extra_type_list_by_cause(enum extra_cause cause)
Definition extras.c:249
void extra_to_caused_by_list(struct extra_type *pextra, enum extra_cause cause)
Definition extras.c:312
struct extra_type * extra_by_number(int id)
Definition extras.c:183
static struct extra_type extras[MAX_EXTRA_TYPES]
Definition extras.c:31
struct extra_type_list * extra_type_list_of_terr_claimers(void)
Definition extras.c:275
const char * extra_rule_name(const struct extra_type *pextra)
Definition extras.c:203
bool is_extra_removed_by(const struct extra_type *pextra, enum extra_rmcause rmcause)
Definition extras.c:353
struct extra_type_list * extra_type_list_of_unit_hiders(void)
Definition extras.c:259
#define extra_type_iterate(_p)
Definition extras.h:315
static void extra_to_removed_by_list(struct extra_type *pextra, enum extra_rmcause rmcause)
Definition extras.h:214
#define extra_type_list_iterate(extralist, pextra)
Definition extras.h:165
#define extra_type_iterate_end
Definition extras.h:321
#define is_extra_caused_by(e, c)
Definition extras.h:203
#define extra_index(_e_)
Definition extras.h:183
#define extra_type_list_iterate_end
Definition extras.h:167
#define extra_base_get(_e_)
Definition extras.h:190
#define extra_road_get(_e_)
Definition extras.h:191
#define extra_type_by_cause_iterate_end
Definition extras.h:339
#define MAX_NUM_USER_EXTRA_FLAGS
Definition extras.h:83
#define extra_type_by_cause_iterate(_cause, _extra)
Definition extras.h:333
#define MAX_NUM_USER_BUILDING_FLAGS
Definition fc_types.h:493
#define MAX_DISASTER_TYPES
Definition fc_types.h:52
#define MAX_VET_LEVELS
Definition fc_types.h:49
@ ROCO_RAILROAD
Definition fc_types.h:948
@ ROCO_NONE
Definition fc_types.h:948
@ ROCO_RIVER
Definition fc_types.h:948
@ ROCO_ROAD
Definition fc_types.h:948
#define MAX_GRANARY_INIS
Definition fc_types.h:74
#define MAX_NUM_NATIONS
Definition fc_types.h:61
#define MAX_NUM_BUILDING_LIST
Definition fc_types.h:46
#define MAX_GOODS_TYPES
Definition fc_types.h:51
#define EC_NATURAL_DEFENSIVE
Definition fc_types.h:811
#define EC_SPECIAL
Definition fc_types.h:809
int action_id
Definition fc_types.h:250
#define SP_MAX
Definition fc_types.h:269
#define EC_NONE
Definition fc_types.h:808
#define EC_NOT_AGGRESSIVE
Definition fc_types.h:812
#define EC_DEFENSIVE
Definition fc_types.h:810
#define MAX_CALENDAR_FRAGMENTS
Definition fc_types.h:63
#define MAX_TILEDEFS
Definition fc_types.h:56
#define MAX_NUM_TECH_CLASSES
Definition fc_types.h:64
#define MAX_NUM_LEADERS
Definition fc_types.h:57
#define MAX_NUM_MULTIPLIERS
Definition fc_types.h:55
#define MAX_NUM_UNIT_LIST
Definition fc_types.h:45
#define MAX_EXTRA_TYPES
Definition fc_types.h:50
@ CTGT_CITY
Definition fc_types.h:128
#define MAX_ACHIEVEMENT_TYPES
Definition fc_types.h:53
#define MAX_LEN_NAME
Definition fc_types.h:68
#define MAX_NUM_TECH_LIST
Definition fc_types.h:44
#define MAX_LEN_CITYNAME
Definition fc_types.h:69
#define MAX_COUNTERS
Definition fc_types.h:108
#define UCL_LAST
Definition fc_types.h:276
#define Q_(String)
Definition fcintl.h:70
#define _(String)
Definition fcintl.h:67
#define Qn_(String)
Definition fcintl.h:89
#define N_(String)
Definition fcintl.h:69
const struct ft_color ftc_warning
struct civ_game game
Definition game.c:62
void game_ruleset_init(void)
Definition game.c:517
void game_ruleset_free(void)
Definition game.c:568
struct world wld
Definition game.c:63
#define RS_DEFAULT_RANSOM_GOLD
Definition game.h:882
#define RS_DEFAULT_GRANARY_FOOD_INI
Definition game.h:834
#define RS_DEFAULT_NUKE_DEFENDER_SURVIVAL_CHANCE_PCT
Definition game.h:874
#define RS_MIN_BORDER_RADIUS_SQ_CITY_PERMANENT
Definition game.h:815
#define RS_MAX_TECH_UPKEEP_DIVIDER
Definition game.h:894
#define RS_MIN_ILLNESS_POLLUTION_PCT
Definition game.h:801
#define RS_DEFAULT_NUKE_POP_LOSS_PCT
Definition game.h:871
#define RS_MAX_BORDER_RADIUS_SQ_CITY
Definition game.h:808
#define RS_DEFAULT_BASE_POLLUTION
Definition game.h:857
#define RS_MIN_ILLNESS_TRADE_INFECTION_PCT
Definition game.h:797
#define RS_MAX_ILLNESS_BASE_FACTOR
Definition game.h:790
#define RS_DEFAULT_INCITE_TOTAL_FCT
Definition game.h:830
#define RS_DEFAULT_ILLNESS_BASE_FACTOR
Definition game.h:788
#define RS_DEFAULT_NEG_YEAR_LABEL
Definition game.h:784
#define RS_MIN_NUKE_POP_LOSS_PCT
Definition game.h:872
#define RS_MIN_INCITE_IMPROVEMENT_FCT
Definition game.h:823
#define RS_MIN_FOOD_COST
Definition game.h:867
#define RS_MIN_BASE_BRIBE_COST
Definition game.h:879
#define RS_MAX_NUKE_POP_LOSS_PCT
Definition game.h:873
#define RS_DEFAULT_INCITE_IMPROVEMENT_FCT
Definition game.h:822
#define RS_MAX_INCITE_IMPROVEMENT_FCT
Definition game.h:824
#define RS_MIN_RANSOM_GOLD
Definition game.h:883
#define RS_ACTION_NO_MAX_DISTANCE
Definition game.h:910
#define RS_DEFAULT_BASE_BRIBE_COST
Definition game.h:878
#define RS_MAX_INCITE_BASE_COST
Definition game.h:820
#define RS_DEFAULT_TECH_UPKEEP_DIVIDER
Definition game.h:892
#define RS_DEFAULT_HAPPY_COST
Definition game.h:862
#define RS_MIN_UPGRADE_VETERAN_LOSS
Definition game.h:889
#define RS_MIN_ILLNESS_MIN_SIZE
Definition game.h:793
#define RS_DEFAULT_POISON_EMPTIES_FOOD_STOCK
Definition game.h:900
#define RS_DEFAULT_GRANARY_FOOD_INC
Definition game.h:836
#define RS_DEFAULT_ILLNESS_ON
Definition game.h:786
#define RS_MAX_FOOD_COST
Definition game.h:868
#define RS_MAX_HAPPY_COST
Definition game.h:864
#define GAME_DEFAULT_CELEBRATESIZE
Definition game.h:507
#define RS_MIN_ILLNESS_BASE_FACTOR
Definition game.h:789
#define RS_DEFAULT_STEAL_MAP_REVEALS_CITIES
Definition game.h:901
#define RS_MIN_TECH_UPKEEP_DIVIDER
Definition game.h:893
#define RS_MAX_RANSOM_GOLD
Definition game.h:884
#define RS_MIN_HAPPY_COST
Definition game.h:863
#define RS_MIN_BORDER_RADIUS_SQ_CITY
Definition game.h:807
#define GAME_DEFAULT_RULESETDIR
Definition game.h:681
#define RS_MIN_NUKE_DEFENDER_SURVIVAL_CHANCE_PCT
Definition game.h:875
#define RS_MAX_BORDER_RADIUS_SQ_CITY_PERMANENT
Definition game.h:816
#define RS_DEFAULT_UPGRADE_VETERAN_LOSS
Definition game.h:888
#define RS_MAX_NUKE_DEFENDER_SURVIVAL_CHANCE_PCT
Definition game.h:876
#define RS_MAX_INCITE_UNIT_FCT
Definition game.h:828
#define RS_MIN_VIS_RADIUS_SQ
Definition game.h:854
#define RS_DEFAULT_CALENDAR_SKIP_0
Definition game.h:804
#define RS_MAX_ILLNESS_MIN_SIZE
Definition game.h:794
#define RS_DEFAULT_CITY_RADIUS_SQ
Definition game.h:849
#define RS_DEFAULT_HP
Definition game.h:896
#define GAME_DEFAULT_START_YEAR
Definition game.h:756
#define RS_MAX_BORDER_SIZE_EFFECT
Definition game.h:812
#define RS_DEFAULT_BORDER_SIZE_EFFECT
Definition game.h:810
#define RS_MAX_BASE_BRIBE_COST
Definition game.h:880
#define RS_MIN_INCITE_BASE_COST
Definition game.h:819
#define RS_DEFAULT_PILLAGE_SELECT
Definition game.h:886
#define RS_MIN_CITY_RADIUS_SQ
Definition game.h:850
#define RS_MIN_CITY_CENTER_OUTPUT
Definition game.h:841
#define RS_MAX_GRANARY_FOOD_INC
Definition game.h:838
#define RS_MAX_CITY_CENTER_OUTPUT
Definition game.h:842
#define RS_MAX_CITY_RADIUS_SQ
Definition game.h:851
#define RS_DEFAULT_POS_YEAR_LABEL
Definition game.h:782
#define RS_MIN_INCITE_UNIT_FCT
Definition game.h:827
#define RS_MIN_BORDER_SIZE_EFFECT
Definition game.h:811
#define RS_DEFAULT_VIS_RADIUS_SQ
Definition game.h:853
#define RS_DEFAULT_BORDER_RADIUS_SQ_CITY_PERMANENT
Definition game.h:814
#define RS_DEFAULT_TIRED_ATTACK
Definition game.h:870
#define RS_DEFAULT_ACTION_ACTOR_CONSUMING_ALWAYS
Definition game.h:902
#define RS_MAX_ILLNESS_POLLUTION_PCT
Definition game.h:802
#define RS_DEFAULT_ILLNESS_TRADE_INFECTION_PCT
Definition game.h:796
#define RS_DEFAULT_FOOD_COST
Definition game.h:866
#define RS_DEFAULT_INCITE_UNIT_FCT
Definition game.h:826
#define RS_MAX_INCITE_TOTAL_FCT
Definition game.h:832
#define RS_DEFAULT_INCITE_BASE_COST
Definition game.h:818
#define GAME_DEFAULT_ANGRYCITIZEN
Definition game.h:398
#define RS_DEFAULT_CITY_CENTER_OUTPUT
Definition game.h:840
#define RS_MIN_HP
Definition game.h:897
#define RS_MIN_INCITE_TOTAL_FCT
Definition game.h:831
#define RS_DEFAULT_ILLNESS_POLLUTION_PCT
Definition game.h:800
#define RS_MAX_UPGRADE_VETERAN_LOSS
Definition game.h:890
static void set_ruleset_compat_mode(bool active)
Definition game.h:362
#define RS_MAX_VIS_RADIUS_SQ
Definition game.h:855
#define RS_MIN_GRANARY_FOOD_INC
Definition game.h:837
#define RS_MAX_ILLNESS_TRADE_INFECTION_PCT
Definition game.h:798
#define RS_MAX_HP
Definition game.h:898
#define RS_DEFAULT_ILLNESS_MIN_SIZE
Definition game.h:792
#define RS_DEFAULT_BORDER_RADIUS_SQ_CITY
Definition game.h:806
const struct nation_type * ruler_title_nation(const struct ruler_title *pruler_title)
Definition government.c:372
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)
Definition government.c:332
const char * ruler_title_female_untranslated_name(const struct ruler_title *pruler_title)
Definition government.c:390
Government_type_id government_count(void)
Definition government.c:73
const char * ruler_title_male_untranslated_name(const struct ruler_title *pruler_title)
Definition government.c:381
const char * gov_flag_helptxt(enum gov_flag_id id)
Definition government.c:661
void governments_alloc(int num)
Definition government.c:535
Government_type_id government_number(const struct government *pgovern)
Definition government.c:92
const struct ruler_title_hash * government_ruler_titles(const struct government *pgovern)
Definition government.c:322
Government_type_id government_index(const struct government *pgovern)
Definition government.c:84
const char * government_rule_name(const struct government *pgovern)
Definition government.c:132
struct government * government_by_rule_name(const char *name)
Definition government.c:57
void set_user_gov_flag_name(enum gov_flag_id id, const char *name, const char *helptxt)
Definition government.c:624
#define governments_iterate(NAME_pgov)
Definition government.h:136
#define G_LAST
Definition government.h:50
#define ruler_titles_iterate(ARG_hash, NAME_rule_title)
Definition government.h:40
#define ruler_titles_iterate_end
Definition government.h:43
#define governments_iterate_end
Definition government.h:139
#define MAX_NUM_USER_GOVERNMENT_FLAGS
Definition government.h:29
const char * title
Definition repodlgs.c:1314
GType type
Definition repodlgs.c:1313
struct impr_type * improvement_by_number(const Impr_type_id id)
Impr_type_id improvement_number(const struct impr_type *pimprove)
const char * improvement_rule_name(const struct impr_type *pimprove)
void improvement_feature_cache_init(void)
Definition improvement.c:92
struct impr_type * improvement_by_rule_name(const char *name)
void set_user_impr_flag_name(enum impr_flag_id id, const char *name, const char *helptxt)
const char * impr_flag_helptxt(enum impr_flag_id id)
#define improvement_iterate_end
#define improvement_iterate(_p)
#define B_LAST
Definition improvement.h:42
const char * name
Definition inputfile.c:127
void vdo_log(const char *file, const char *function, int line, bool print_from_where, enum log_level level, char *buf, int buflen, const char *message, va_list args)
Definition log.c:411
#define fc_assert_ret(condition)
Definition log.h:192
#define log_verbose(message,...)
Definition log.h:110
#define fc_assert(condition)
Definition log.h:177
#define MAX_LEN_LOG_LINE
Definition log.h:27
#define fc_assert_ret_val(condition, val)
Definition log.h:195
#define log_do_output_for_level(level)
Definition log.h:90
#define log_debug(message,...)
Definition log.h:116
#define log_normal(message,...)
Definition log.h:108
log_level
Definition log.h:29
@ LOG_ERROR
Definition log.h:31
@ LOG_FATAL
Definition log.h:30
#define log_error(message,...)
Definition log.h:104
void lsend_packet_ruleset_summary(struct conn_list *dest, const struct packet_ruleset_summary *packet)
void lsend_packet_ruleset_building(struct conn_list *dest, const struct packet_ruleset_building *packet)
void lsend_packet_ruleset_unit_class_flag(struct conn_list *dest, const struct packet_ruleset_unit_class_flag *packet)
void lsend_packet_ruleset_achievement(struct conn_list *dest, const struct packet_ruleset_achievement *packet)
void lsend_packet_ruleset_nation_sets(struct conn_list *dest, const struct packet_ruleset_nation_sets *packet)
void lsend_packet_ruleset_multiplier(struct conn_list *dest, const struct packet_ruleset_multiplier *packet)
void lsend_packet_ruleset_city(struct conn_list *dest, const struct packet_ruleset_city *packet)
void lsend_packet_ruleset_unit(struct conn_list *dest, const struct packet_ruleset_unit *packet)
void lsend_packet_ruleset_clause(struct conn_list *dest, const struct packet_ruleset_clause *packet)
void lsend_packet_ruleset_unit_flag(struct conn_list *dest, const struct packet_ruleset_unit_flag *packet)
void lsend_packet_ruleset_action(struct conn_list *dest, const struct packet_ruleset_action *packet)
void lsend_packet_ruleset_extra(struct conn_list *dest, const struct packet_ruleset_extra *packet)
void lsend_packet_ruleset_nation_groups(struct conn_list *dest, const struct packet_ruleset_nation_groups *packet)
void lsend_packet_ruleset_terrain_control(struct conn_list *dest, const struct packet_ruleset_terrain_control *packet)
void lsend_packet_ruleset_government_ruler_title(struct conn_list *dest, const struct packet_ruleset_government_ruler_title *packet)
void lsend_packet_ruleset_music(struct conn_list *dest, const struct packet_ruleset_music *packet)
void lsend_packet_ruleset_control(struct conn_list *dest, const struct packet_ruleset_control *packet)
void lsend_packet_team_name_info(struct conn_list *dest, const struct packet_team_name_info *packet)
void lsend_packet_ruleset_terrain_flag(struct conn_list *dest, const struct packet_ruleset_terrain_flag *packet)
void lsend_packet_ruleset_unit_class(struct conn_list *dest, const struct packet_ruleset_unit_class *packet)
void lsend_packet_ruleset_disaster(struct conn_list *dest, const struct packet_ruleset_disaster *packet)
void lsend_packet_ruleset_tiledef(struct conn_list *dest, const struct packet_ruleset_tiledef *packet)
void lsend_packet_ruleset_description_part(struct conn_list *dest, const struct packet_ruleset_description_part *packet)
void lsend_packet_ruleset_government(struct conn_list *dest, const struct packet_ruleset_government *packet)
void lsend_packet_ruleset_unit_bonus(struct conn_list *dest, const struct packet_ruleset_unit_bonus *packet)
void lsend_packet_ruleset_base(struct conn_list *dest, const struct packet_ruleset_base *packet)
void lsend_packet_ruleset_resource(struct conn_list *dest, const struct packet_ruleset_resource *packet)
void lsend_packet_ruleset_specialist(struct conn_list *dest, const struct packet_ruleset_specialist *packet)
void lsend_packet_ruleset_tech(struct conn_list *dest, const struct packet_ruleset_tech *packet)
void lsend_packet_ruleset_trade(struct conn_list *dest, const struct packet_ruleset_trade *packet)
void lsend_packet_ruleset_action_enabler(struct conn_list *dest, const struct packet_ruleset_action_enabler *packet)
void lsend_packet_ruleset_gov_flag(struct conn_list *dest, const struct packet_ruleset_gov_flag *packet)
void lsend_packet_ruleset_style(struct conn_list *dest, const struct packet_ruleset_style *packet)
void lsend_packet_ruleset_tech_flag(struct conn_list *dest, const struct packet_ruleset_tech_flag *packet)
void lsend_packet_ruleset_tech_class(struct conn_list *dest, const struct packet_ruleset_tech_class *packet)
void lsend_packet_ruleset_goods(struct conn_list *dest, const struct packet_ruleset_goods *packet)
void lsend_packet_ruleset_game(struct conn_list *dest, const struct packet_ruleset_game *packet)
void lsend_packet_ruleset_nation(struct conn_list *dest, const struct packet_ruleset_nation *packet)
void lsend_packet_ruleset_counter(struct conn_list *dest, const struct packet_ruleset_counter *packet)
void lsend_packet_rulesets_ready(struct conn_list *dest)
void lsend_packet_ruleset_impr_flag(struct conn_list *dest, const struct packet_ruleset_impr_flag *packet)
void lsend_packet_ruleset_extra_flag(struct conn_list *dest, const struct packet_ruleset_extra_flag *packet)
void lsend_packet_ruleset_road(struct conn_list *dest, const struct packet_ruleset_road *packet)
void lsend_packet_ruleset_terrain(struct conn_list *dest, const struct packet_ruleset_terrain *packet)
void lsend_packet_ruleset_action_auto(struct conn_list *dest, const struct packet_ruleset_action_auto *packet)
struct terrain_misc terrain_control
Definition map.c:68
#define fc_calloc(n, esz)
Definition mem.h:38
#define FC_FREE(ptr)
Definition mem.h:41
#define fc_strdup(str)
Definition mem.h:43
#define fc_malloc(sz)
Definition mem.h:34
int utype_unknown_move_cost(const struct unit_type *utype)
Definition movement.c:104
void init_move_fragments(void)
Definition movement.c:978
#define SINGLE_MOVE
Definition movement.h:26
const char * multiplier_rule_name(const struct multiplier *pmul)
Multiplier_type_id multiplier_number(const struct multiplier *pmul)
Definition multipliers.c:67
struct multiplier * multiplier_by_rule_name(const char *name)
Multiplier_type_id multiplier_index(const struct multiplier *pmul)
Definition multipliers.c:80
#define multipliers_iterate(_mul_)
Definition multipliers.h:61
#define multipliers_iterate_end
Definition multipliers.h:67
static void name_set(struct name_translation *ptrans, const char *domain, const char *vernacular_name)
static const char * rule_name_get(const struct name_translation *ptrans)
static const char * untranslated_name(const struct name_translation *ptrans)
static void names_set(struct name_translation *ptrans, const char *domain, const char *vernacular_name, const char *rule_name)
void nation_group_set_match(struct nation_group *pgroup, int match)
Definition nation.c:1041
const char * nation_group_untranslated_name(const struct nation_group *pgroup)
Definition nation.c:1062
struct nation_group * nation_group_by_rule_name(const char *name)
Definition nation.c:1016
const char * nation_rule_name(const struct nation_type *pnation)
Definition nation.c:138
Nation_type_id nation_count(void)
Definition nation.c:503
Nation_type_id nation_number(const struct nation_type *pnation)
Definition nation.c:484
struct nation_group * nation_group_new(const char *name)
Definition nation.c:953
bool nation_leader_is_male(const struct nation_leader *pleader)
Definition nation.c:295
struct nation_set * nation_set_new(const char *set_name, const char *set_rule_name, const char *set_description)
Definition nation.c:714
struct nation_type * nation_by_number(const Nation_type_id nation)
Definition nation.c:472
struct nation_city * nation_city_new(struct nation_type *pnation, const char *name)
Definition nation.c:347
const struct nation_leader_list * nation_leaders(const struct nation_type *pnation)
Definition nation.c:231
const char * nation_set_untranslated_name(const struct nation_set *pset)
Definition nation.c:797
bool is_nation_playable(const struct nation_type *nation)
Definition nation.c:201
int nation_set_number(const struct nation_set *pset)
Definition nation.c:706
void nation_city_set_terrain_preference(struct nation_city *pncity, const struct terrain *pterrain, enum nation_city_preference prefer)
Definition nation.c:397
void nation_city_set_river_preference(struct nation_city *pncity, enum nation_city_preference prefer)
Definition nation.c:407
bool nation_is_in_set(const struct nation_type *pnation, const struct nation_set *pset)
Definition nation.c:832
const char * nation_set_description(const struct nation_set *pset)
Definition nation.c:824
int nation_set_count(void)
Definition nation.c:690
struct nation_set * nation_set_by_number(int id)
Definition nation.c:762
struct nation_type * nation_by_rule_name(const char *name)
Definition nation.c:121
struct nation_set * nation_set_by_rule_name(const char *name)
Definition nation.c:779
Nation_type_id nation_index(const struct nation_type *pnation)
Definition nation.c:495
const char * nation_leader_name(const struct nation_leader *pleader)
Definition nation.c:287
int nation_group_count(void)
Definition nation.c:929
const char * nation_set_rule_name(const struct nation_set *pset)
Definition nation.c:806
struct nation_leader * nation_leader_new(struct nation_type *pnation, const char *name, bool is_male)
Definition nation.c:241
void nation_group_set_hidden(struct nation_group *pgroup, bool hidden)
Definition nation.c:1032
void nations_alloc(int num)
Definition nation.c:620
enum barbarian_type nation_barbarian_type(const struct nation_type *nation)
Definition nation.c:212
int nation_group_number(const struct nation_group *pgroup)
Definition nation.c:945
#define nation_leader_list_iterate(leaderlist, pleader)
Definition nation.h:57
#define nation_sets_iterate_end
Definition nation.h:333
#define nation_set_list_iterate_end
Definition nation.h:68
#define nation_group_list_iterate(grouplist, pgroup)
Definition nation.h:75
#define nation_sets_iterate(NAME_pset)
Definition nation.h:329
#define nations_iterate_end
Definition nation.h:364
nation_city_preference
Definition nation.h:39
@ NCP_DISLIKE
Definition nation.h:40
@ NCP_LIKE
Definition nation.h:42
#define nations_iterate(NAME_pnation)
Definition nation.h:361
#define nation_leader_list_iterate_end
Definition nation.h:59
#define nation_group_list_iterate_end
Definition nation.h:77
#define nation_set_list_iterate(setlist, pset)
Definition nation.h:66
#define nation_groups_iterate(NAME_pgroup)
Definition nation.h:339
#define nation_groups_iterate_end
Definition nation.h:343
void notify_conn(struct conn_list *dest, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:238
#define web_lsend_packet(packetname,...)
Definition packets.h:57
#define PACKET_STRVEC_INSERT(dest, src)
Definition packets.h:191
struct city_list * cities
Definition packhand.c:121
int len
Definition packhand.c:129
void send_nation_availability(struct conn_list *dest, bool nationset_change)
Definition plrhand.c:2655
void playercolor_free(void)
Definition plrhand.c:3356
void playercolor_init(void)
Definition plrhand.c:3346
int playercolor_count(void)
Definition plrhand.c:3395
void playercolor_add(struct rgbcolor *prgbcolor)
Definition plrhand.c:3375
void count_playable_nations(void)
Definition plrhand.c:2612
struct section_file * secfile_load(const char *filename, bool allow_duplicates)
Definition registry.c:51
const char * secfile_error(void)
const char * section_name(const struct section *psection)
void secfile_destroy(struct section_file *secfile)
bool entry_bool_get(const struct entry *pentry, bool *value)
void secfile_check_unused(const struct section_file *secfile)
bool secfile_lookup_int(const struct section_file *secfile, int *ival, const char *path,...)
struct section_list * secfile_sections_by_name_prefix(const struct section_file *secfile, const char *prefix)
const char ** secfile_lookup_str_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
struct entry * secfile_entry_lookup(const struct section_file *secfile, const char *path,...)
bool entry_str_get(const struct entry *pentry, const char **value)
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
int * secfile_lookup_int_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
bool secfile_lookup_bool_default(const struct section_file *secfile, bool def, const char *path,...)
int secfile_lookup_int_default(const struct section_file *secfile, int def, const char *path,...)
bool entry_int_get(const struct entry *pentry, int *value)
const char * secfile_name(const struct section_file *secfile)
struct entry * secfile_entry_by_path(const struct section_file *secfile, const char *path)
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
int secfile_lookup_int_def_min_max(const struct section_file *secfile, int defval, int minval, int maxval, const char *path,...)
enum entry_type entry_type_get(const struct entry *pentry)
@ ENTRY_FILEREFERENCE
@ ENTRY_LONG_COMMENT
@ ENTRY_INT
@ ENTRY_FLOAT
@ ENTRY_STR
@ ENTRY_ILLEGAL
@ ENTRY_BOOL
#define secfile_lookup_enum_vec(secfile, dim, specenum_type, path,...)
#define secfile_lookup_enum_default(secfile, defval, specenum_type, path,...)
#define section_list_iterate(seclist, psection)
#define section_list_iterate_end
#define secfile_entry_ignore_by_path(_sfile_, _path_)
req_vec_num_in_item req_vec_vector_number(const void *parent_item, const struct requirement_vector *vec)
struct requirement_vector * req_vec_by_number(const void *parent_item, req_vec_num_in_item number)
bool req_vec_change_apply(const struct req_vec_change *modification, requirement_vector_by_number getter, const void *parent_item)
bool are_requirements_equal(const struct requirement *req1, const struct requirement *req2)
struct requirement req_from_str(const char *type, const char *range, bool survives, bool present, bool quiet, const char *value)
struct requirement req_from_values(int type, int range, bool survives, bool present, bool quiet, int value)
void req_vec_problem_free(struct req_vec_problem *issue)
struct req_vec_problem * req_vec_get_first_missing_univ(const struct requirement_vector *vec, requirement_vector_number get_num, const void *parent_item)
struct req_vec_problem * req_vec_get_first_redundant_req(const struct requirement_vector *vec, requirement_vector_number get_num, const void *parent_item)
bool req_vec_is_impossible_to_fulfill(const struct requirement_vector *reqs)
#define requirement_vector_iterate_end
#define requirement_vector_iterate(req_vec, preq)
bool rgbcolor_load(struct section_file *file, struct rgbcolor **prgbcolor, char *path,...)
Definition rgbcolor.c:86
Road_type_id road_number(const struct road_type *proad)
Definition road.c:32
void road_integrators_cache_init(void)
Definition road.c:111
void road_type_init(struct extra_type *pextra, int idx)
Definition road.c:93
bool rscompat_names(struct rscompat_info *info)
Definition rscompat.c:335
void rscompat_postprocess(struct rscompat_info *info)
Definition rscompat.c:496
const char * rscompat_effect_name_3_4(const char *old_name)
Definition rscompat.c:572
int rscompat_check_capabilities(struct section_file *file, const char *filename, const struct rscompat_info *info)
Definition rscompat.c:70
void rscompat_enablers_add_obligatory_hard_reqs(void)
Definition rscompat.c:290
void rscompat_init_info(struct rscompat_info *info)
Definition rscompat.c:61
bool rscompat_check_cap_and_version(struct section_file *file, const char *filename, const struct rscompat_info *info)
Definition rscompat.c:135
bool sanity_check_ruleset_data(struct rscompat_info *compat)
Definition rssanity.c:910
bool autoadjust_ruleset_data(void)
Definition rssanity.c:1625
#define ENABLER_SECTION_PREFIX
Definition ruleload.c:115
#define check_cityname(name)
Definition ruleload.c:121
static int ruleset_purge_redundant_reqs_enablers(void)
Definition ruleload.c:437
static void ruleset_load_traits(struct trait_limits *out, struct section_file *file, const char *secname, const char *field_prefix)
Definition ruleload.c:1280
static bool load_rulesetdir(const char *rsdir, bool compat_mode, rs_conversion_logger logger, bool act, bool buffer_script, bool load_luadata)
Definition ruleload.c:9580
#define STYLE_SECTION_PREFIX
Definition ruleload.c:100
static bool lookup_terrain(struct section_file *file, const char *entry, const char *filename, struct terrain *pthis, struct terrain **result, bool null_acceptable)
Definition ruleload.c:1181
static bool load_ruleset_veteran(struct section_file *file, const char *path, struct veteran_system **vsystem, char *err, size_t err_len)
Definition ruleload.c:1964
static bool load_terrain_names(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:2772
static bool load_style_names(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:5807
int ruleset_purge_unused_entities(void)
Definition ruleload.c:327
#define MUSICSTYLE_SECTION_PREFIX
Definition ruleload.c:93
static char * road_sections
Definition ruleload.c:132
static bool load_ruleset_governments(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:4486
#define MULTIPLIER_SECTION_PREFIX
Definition ruleload.c:117
static struct requirement_vector reqs_list
Definition ruleload.c:135
static void send_ruleset_techs(struct conn_list *dest)
Definition ruleload.c:8427
#define section_strlcpy(dst, src)
Definition ruleload.c:126
static bool load_action_range(struct section_file *file, action_id act)
Definition ruleload.c:6560
#define check_name(name)
Definition ruleload.c:120
static bool load_specialist(const struct section *psection, struct specialist *s, struct section_file *file)
Definition ruleload.c:6049
static void send_ruleset_units(struct conn_list *dest)
Definition ruleload.c:8247
static void send_ruleset_governments(struct conn_list *dest)
Definition ruleload.c:9102
static bool load_action_names(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:1451
static struct extra_type * lookup_resource(const char *filename, const char *name, const char *jsection)
Definition ruleload.c:1160
static struct section_file * openload_luadata_file(const char *rsdir)
Definition ruleload.c:641
#define TILEDEF_SECTION_PREFIX
Definition ruleload.c:106
static bool load_ruleset_techs(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:1592
static bool purge_unused_req_vec(const struct requirement_vector *reqs, const char *msg)
Definition ruleload.c:341
void rulesets_deinit(void)
Definition ruleload.c:9569
static void send_ruleset_resources(struct conn_list *dest)
Definition ruleload.c:8716
static bool load_ruleset_buildings(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:2648
static char * terrain_sections
Definition ruleload.c:129
static bool lookup_building_list(struct section_file *file, const char *prefix, const char *entry, int *output, const char *filename)
Definition ruleload.c:1010
static void nullcheck_secfile_destroy(struct section_file *file)
Definition ruleload.c:9558
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__
Definition ruleload.c:6481
static void send_ruleset_clauses(struct conn_list *dest)
Definition ruleload.c:9297
static void send_ruleset_game(struct conn_list *dest)
Definition ruleload.c:9397
char * parser_buffer
Definition ruleload.c:223
#define NATION_SECTION_PREFIX
Definition ruleload.c:99
static bool load_ruleset_effects(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:6307
static bool lookup_cbonus_list(struct combat_bonus_list *list, struct section_file *file, const char *sec, const char *sub)
Definition ruleload.c:795
static void send_ruleset_nations(struct conn_list *dest)
Definition ruleload.c:9171
static void send_ruleset_roads(struct conn_list *dest)
Definition ruleload.c:8859
static int ruleset_purge_unused_enablers(void)
Definition ruleload.c:258
#define UEFF_SECTION_PREFIX
Definition ruleload.c:94
static char * tiledef_sections
Definition ruleload.c:133
static bool is_on_allowed_list(const char *name, const char **list, size_t len)
Definition ruleload.c:4902
static void send_ruleset_tech_classes(struct conn_list *dest)
Definition ruleload.c:8409
static void send_ruleset_action_enablers(struct conn_list *dest)
Definition ruleload.c:9029
static void send_ruleset_control(struct conn_list *dest)
Definition ruleload.c:4707
bool load_rulesets(const char *restore, const char *alt, bool compat_mode, rs_conversion_logger logger, bool act, bool buffer_script, bool load_luadata)
Definition ruleload.c:9488
static void send_ruleset_tiledefs(struct conn_list *dest)
Definition ruleload.c:8895
#define GOODS_SECTION_PREFIX
Definition ruleload.c:107
void ruleset_error_real(rs_conversion_logger logger, const char *file, const char *function, int line, enum log_level level, const char *format,...)
Definition ruleload.c:229
#define TERRAIN_SECTION_PREFIX
Definition ruleload.c:110
static struct section_file * openload_ruleset_file(const char *whichset, const char *rsdir)
Definition ruleload.c:585
struct requirement_vector * lookup_req_list(struct section_file *file, const char *sec, const char *sub, const char *rfor)
Definition ruleload.c:669
static void send_ruleset_musics(struct conn_list *dest)
Definition ruleload.c:9376
int ruleset_purge_redundant_reqs(void)
Definition ruleload.c:504
static char * base_sections
Definition ruleload.c:131
#define DISASTER_SECTION_PREFIX
Definition ruleload.c:113
static void send_ruleset_goods(struct conn_list *dest)
Definition ruleload.c:8924
static const char name_too_long[]
Definition ruleload.c:124
bool reload_rulesets_settings(void)
Definition ruleload.c:9819
static struct strvec * lookup_strvec(struct section_file *file, const char *prefix, const char *suffix)
Definition ruleload.c:1139
#define CITYSTYLE_SECTION_PREFIX
Definition ruleload.c:92
static bool lookup_tech(struct section_file *file, struct advance **result, const char *prefix, const char *entry, const char *filename, const char *description)
Definition ruleload.c:854
static bool load_game_names(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:1321
static void send_ruleset_counters(struct conn_list *dest)
Definition ruleload.c:8523
static void send_ruleset_specialists(struct conn_list *dest)
Definition ruleload.c:8384
#define ADVANCE_SECTION_PREFIX
Definition ruleload.c:89
#define EFFECT_SECTION_PREFIX
Definition ruleload.c:95
static void send_ruleset_action_auto_performers(struct conn_list *dest)
Definition ruleload.c:9048
static bool load_government_names(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:4374
static int char * script_buffer
Definition ruleload.c:222
static bool load_action_blocked_by_list(struct section_file *file, const char *filename, struct action *paction, struct rscompat_info *compat)
Definition ruleload.c:6625
static void send_ruleset_team_names(struct conn_list *dest)
Definition ruleload.c:9458
static void send_ruleset_cities(struct conn_list *dest)
Definition ruleload.c:9351
static bool purge_redundant_req_vec(const struct requirement_vector *reqs, const char *msg)
Definition ruleload.c:426
static char * lookup_string(struct section_file *file, const char *prefix, const char *suffix)
Definition ruleload.c:1118
static const char * check_leader_names(struct nation_type *pnation)
Definition ruleload.c:4745
#define BASE_SECTION_PREFIX
Definition ruleload.c:103
static int ruleset_purge_redundant_reqs_effects(void)
Definition ruleload.c:475
static enum fc_tristate openload_script_file(const char *whichset, const char *rsdir, char **buffer, bool optional)
Definition ruleload.c:613
char * get_parser_buffer(void)
Definition ruleload.c:576
#define ACTION_SECTION_PREFIX
Definition ruleload.c:116
static bool load_building_names(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:2565
#define EXTRA_SECTION_PREFIX
Definition ruleload.c:102
void send_rulesets(struct conn_list *dest)
Definition ruleload.c:9842
#define CLAUSE_SECTION_PREFIX
Definition ruleload.c:101
static bool lookup_unit_list(struct section_file *file, const char *prefix, const char *entry, struct unit_type **output, const char *filename)
Definition ruleload.c:886
static char * resource_sections
Definition ruleload.c:128
#define UNIT_SECTION_PREFIX
Definition ruleload.c:112
#define ACHIEVEMENT_SECTION_PREFIX
Definition ruleload.c:114
static bool load_ruleset_cities(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:6091
static bool load_ruleset_styles(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:5869
static struct government * lookup_government(struct section_file *file, const char *entry, const char *filename, struct government *fallback)
Definition ruleload.c:1093
#define SUPER_SPECIALIST_SECTION_PREFIX
Definition ruleload.c:109
static bool load_ruleset_units(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:2085
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)
Definition ruleload.c:1231
static void send_ruleset_styles(struct conn_list *dest)
Definition ruleload.c:9281
#define NATION_GROUP_SECTION_PREFIX
Definition ruleload.c:98
static char * extra_sections
Definition ruleload.c:130
#define RULES_SUFFIX
Definition ruleload.c:86
static void send_ruleset_disasters(struct conn_list *dest)
Definition ruleload.c:8953
static bool purge_duplicate_req_vec(const struct requirement_vector *reqs, const char *msg)
Definition ruleload.c:381
static bool lookup_tech_list(struct section_file *file, const char *prefix, const char *entry, int *output, const char *filename)
Definition ruleload.c:946
#define MAX_SECTION_LABEL
Definition ruleload.c:125
#define BUILDING_SECTION_PREFIX
Definition ruleload.c:91
static bool load_ruleset_game(struct section_file *file, bool act, struct rscompat_info *compat)
Definition ruleload.c:6741
static bool load_nation_names(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:4766
static void send_ruleset_achievements(struct conn_list *dest)
Definition ruleload.c:8978
#define SCRIPT_SUFFIX
Definition ruleload.c:87
static void send_ruleset_bases(struct conn_list *dest)
Definition ruleload.c:8837
static bool load_ruleset_terrain(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:3147
static int ruleset_purge_unused_effects(void)
Definition ruleload.c:304
static bool load_action_actor_consuming_always(struct section_file *file, action_id act)
Definition ruleload.c:6608
static bool load_action_post_success_force(struct section_file *file, const char *filename, int performer_slot, struct action *paction)
Definition ruleload.c:6670
static bool load_tech_names(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:1471
#define SPECIALIST_SECTION_PREFIX
Definition ruleload.c:108
#define COUNTER_SECTION_PREFIX
Definition ruleload.c:118
static bool load_action_kind(struct section_file *file, action_id act)
Definition ruleload.c:6585
static void send_ruleset_multipliers(struct conn_list *dest)
Definition ruleload.c:9321
char * get_script_buffer(void)
Definition ruleload.c:568
static void send_ruleset_actions(struct conn_list *dest)
Definition ruleload.c:8999
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)
Definition ruleload.c:4918
static bool load_action_auto_uflag_block(struct section_file *file, struct action_auto_perf *auto_perf, const char *uflags_path, const char *filename)
Definition ruleload.c:5947
static bool load_ruleset_nations(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:5089
static bool load_action_auto_actions(struct section_file *file, struct action_auto_perf *auto_perf, const char *actions_path, const char *filename)
Definition ruleload.c:5990
static void send_ruleset_unit_classes(struct conn_list *dest)
Definition ruleload.c:8199
#define TECH_CLASS_SECTION_PREFIX
Definition ruleload.c:90
#define RESOURCE_SECTION_PREFIX
Definition ruleload.c:105
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)
Definition ruleload.c:1062
static void send_ruleset_extras(struct conn_list *dest)
Definition ruleload.c:8735
#define rs_sanity_veteran(_path, _entry, _i, _condition, _action)
static void send_ruleset_terrain(struct conn_list *dest)
Definition ruleload.c:8604
#define GOVERNMENT_SECTION_PREFIX
Definition ruleload.c:96
static bool load_unit_names(struct section_file *file, struct rscompat_info *compat)
Definition ruleload.c:1803
static void send_ruleset_trade_routes(struct conn_list *dest)
Definition ruleload.c:9081
static bool load_ruleset_actions(struct section_file *file, struct section_file *gamefile, struct rscompat_info *compat)
Definition ruleload.c:7815
static void notify_ruleset_fallback(const char *msg)
Definition ruleload.c:9480
static bool lookup_bv_actions(struct section_file *file, const char *filename, bv_actions *target, const char *path)
Definition ruleload.c:6707
static void send_ruleset_buildings(struct conn_list *dest)
Definition ruleload.c:8544
#define UNIT_CLASS_SECTION_PREFIX
Definition ruleload.c:111
static bool ruleset_load_names(struct name_translation *pname, const char *domain, struct section_file *file, const char *sec_name)
Definition ruleload.c:1257
#define ROAD_SECTION_PREFIX
Definition ruleload.c:104
static const char * valid_ruleset_filename(const char *subdir, const char *name, const char *extension, bool optional)
Definition ruleload.c:523
static bool load_action_range_max(struct section_file *file, action_id act)
Definition ruleload.c:6519
static bool load_muuk_as_action_auto(struct section_file *file, struct action_auto_perf *auto_perf, const char *item, const char *filename)
Definition ruleload.c:6026
#define NATION_SET_SECTION_PREFIX
Definition ruleload.c:97
#define RS_DEFAULT_CONVERT_SPEED
Definition ruleload.h:122
#define RS_DEFAULT_DAMAGE_REDUCES_BOMBARD_RATE
Definition ruleload.h:108
#define RS_DEFAULT_WORLD_PEACE_TURNS
Definition ruleload.h:98
#define RS_DEFAULT_TECH_TRADE_LOSS_HOLES
Definition ruleload.h:83
#define RS_DEFAULT_TECH_COST_STYLE
Definition ruleload.h:89
#define RS_DEFAULT_EXTRA_APPEARANCE
Definition ruleload.h:102
#define RS_DEFAULT_TECH_PARASITE_HOLES
Definition ruleload.h:84
#define GAME_DEFAULT_ACH_VALUE
Definition ruleload.h:77
#define RS_DEFAULT_TECH_TRADE_HOLES
Definition ruleload.h:82
#define RS_DEFAULT_CULTURE_VIC_POINTS
Definition ruleload.h:93
#define RS_DEFAULT_CULTURE_MIGRATION_PML
Definition ruleload.h:95
void(* rs_conversion_logger)(const char *msg)
Definition ruleload.h:41
#define RS_DEFAULT_SMALL_WONDER_VISIBILITY
Definition ruleload.h:110
#define ruleset_error(logger, level, format,...)
Definition ruleload.h:58
#define RS_DEFAULT_ONLY_KILLING_VETERAN
Definition ruleload.h:105
#define RS_DEFAULT_TECH_LOSS_HOLES
Definition ruleload.h:85
#define RS_DEFAULT_HISTORY_INTEREST_PML
Definition ruleload.h:96
#define RS_DEFAULT_TECH_UPKEEP_STYLE
Definition ruleload.h:91
#define RS_DEFAULT_GOODS_SELECTION
Definition ruleload.h:100
#define RS_DEFAULT_PYTHAGOREAN_DIAGONAL
Definition ruleload.h:86
#define RS_DEFAULT_TECH_STEAL_HOLES
Definition ruleload.h:81
#define RS_MIN_MIN_TECH_COST
Definition ruleload.h:117
#define GAME_DEFAULT_ACH_UNIQUE
Definition ruleload.h:76
#define RS_MAX_BASE_TECH_COST
Definition ruleload.h:114
#define RS_DEFAULT_COMBAT_ODDS_SCALED_VETERANCY
Definition ruleload.h:107
#define RS_DEFAULT_MUUK_FOOD_WIPE
Definition ruleload.h:78
#define RS_DEFAULT_MUUK_GOLD_WIPE
Definition ruleload.h:79
#define RS_DEFAULT_BASE_TECH_COST
Definition ruleload.h:112
#define RS_DEFAULT_NATIONALITY
Definition ruleload.h:120
#define GAME_DEFAULT_CHANGABLE_TAX
Definition ruleload.h:73
#define RS_DEFAULT_MUUK_SHIELD_WIPE
Definition ruleload.h:80
#define RSFORMAT_CURRENT
Definition ruleload.h:37
#define RS_DEFAULT_GOLD_UPKEEP_STYLE
Definition ruleload.h:88
#define GAME_DEFAULT_ADDTOSIZE
Definition ruleload.h:72
#define RS_DEFAULT_ONLY_REAL_FIGHT_VETERAN
Definition ruleload.h:106
#define RS_DEFAULT_EXTRA_DISAPPEARANCE
Definition ruleload.h:103
#define RS_MAX_MIN_TECH_COST
Definition ruleload.h:118
#define RS_DEFAULT_MIN_TECH_COST
Definition ruleload.h:116
#define GAME_DEFAULT_VISION_REVEAL_TILES
Definition ruleload.h:74
#define RS_DEFAULT_CULTURE_VIC_LEAD
Definition ruleload.h:94
#define RS_DEFAULT_TECH_LEAKAGE
Definition ruleload.h:90
#define GAME_DEFAULT_DISASTER_FREQ
Definition ruleload.h:75
#define RSFORMAT_3_4
Definition ruleload.h:36
#define RS_MIN_BASE_TECH_COST
Definition ruleload.h:113
static struct compatibility compat[]
Definition savecompat.c:117
bool script_server_init(void)
bool script_server_load_file(const char *filename, char **buf)
void script_server_free(void)
bool script_server_do_file(struct connection *caller, const char *filename)
struct setting_list * level[OLEVELS_NUM]
Definition settings.c:190
bool settings_ruleset(struct section_file *file, const char *section, bool act, bool compat)
Definition settings.c:4441
sex_t sex_by_name(const char *name)
Definition sex.c:27
sex_t
Definition sex.h:20
@ SEX_UNKNOWN
Definition sex.h:21
@ SEX_FEMALE
Definition sex.h:22
@ SEX_MALE
Definition sex.h:23
bool check_strlen(const char *str, size_t len, const char *errmsg)
Definition shared.c:493
const char * fileinfoname(const struct strvec *dirs, const char *filename)
Definition shared.c:1094
void remove_leading_trailing_spaces(char *s)
Definition shared.c:444
const struct strvec * get_data_dirs(void)
Definition shared.c:886
fc_tristate
Definition shared.h:46
@ TRI_YES
Definition shared.h:46
@ TRI_NO
Definition shared.h:46
@ TRI_MAYBE
Definition shared.h:46
#define DIR_SEPARATOR
Definition shared.h:127
#define ARRAY_SIZE(x)
Definition shared.h:85
struct specialist * specialist_by_rule_name(const char *name)
Definition specialist.c:123
struct specialist * specialist_by_number(const Specialist_type_id id)
Definition specialist.c:110
Specialist_type_id specialist_index(const struct specialist *sp)
Definition specialist.c:90
const char * specialist_rule_name(const struct specialist *sp)
Definition specialist.c:157
#define specialist_type_iterate_end
Definition specialist.h:85
#define specialist_type_iterate(sp)
Definition specialist.h:79
#define DEFAULT_SPECIALIST
Definition specialist.h:43
const char * aifill(int amount)
Definition srv_main.c:2556
void update_nations_with_startpos(void)
Definition srv_main.c:2361
void strvec_store(struct strvec *psv, const char *const *vec, size_t size)
struct strvec * strvec_new(void)
bool actor_consuming_always
Definition actions.h:144
int max_distance
Definition actions.h:127
bool quiet
Definition actions.h:134
char ui_name[MAX_LEN_NAME]
Definition actions.h:130
bv_action_sub_results sub_results
Definition actions.h:115
enum action_actor_kind actor_kind
Definition actions.h:117
bv_actions blocked_by
Definition actions.h:138
enum action_target_kind target_kind
Definition actions.h:118
int min_distance
Definition actions.h:127
struct advance * require[AR_SIZE]
Definition tech.h:129
int border_sq
Definition base.h:44
int vision_main_sq
Definition base.h:45
enum base_gui_type gui_type
Definition base.h:43
int vision_invis_sq
Definition base.h:46
int vision_subs_sq
Definition base.h:47
char * nationlist
Definition game.h:289
int named_teams
Definition game.h:301
size_t as_count
Definition game.h:300
struct civ_game::@32::@36::@42 ruledit
const char ** allowed_govs
Definition game.h:292
int upgrade_veteran_loss
Definition game.h:206
struct rgbcolor * plr_bg_color
Definition game.h:103
int incite_total_factor
Definition game.h:157
int init_vis_radius_sq
Definition game.h:159
bool vision_reveal_tiles
Definition game.h:207
char * description_file
Definition game.h:288
struct packet_ruleset_control control
Definition game.h:83
char * ruleset_summary
Definition game.h:84
char ** nc_agovs
Definition game.h:293
int base_incite_cost
Definition game.h:141
int global_init_techs[MAX_NUM_TECH_LIST]
Definition game.h:110
struct packet_game_info info
Definition game.h:89
int autoupgrade_veteran_loss
Definition game.h:139
char rulesetdir[MAX_LEN_NAME]
Definition game.h:246
int start_year
Definition game.h:198
int incite_improvement_factor
Definition game.h:156
struct section_file * luadata
Definition game.h:254
char ** embedded_nations
Definition game.h:290
int global_init_buildings[MAX_NUM_BUILDING_LIST]
Definition game.h:111
struct trait_limits default_traits[TRAIT_COUNT]
Definition game.h:281
char ** nc_astyles
Definition game.h:299
const char ** allowed_terrains
Definition game.h:295
char * ruleset_description
Definition game.h:85
size_t ag_count
Definition game.h:294
const char ** allowed_styles
Definition game.h:298
bool std_tileset_compat
Definition game.h:302
struct civ_game::@31 rgame
char ** nc_aterrs
Definition game.h:296
size_t embedded_nations_count
Definition game.h:291
int incite_unit_factor
Definition game.h:158
char * ruleset_capabilities
Definition game.h:86
int ransom_gold
Definition game.h:182
struct civ_game::@32::@36 server
size_t at_count
Definition game.h:297
struct veteran_system * veteran
Definition game.h:101
bool homeless_gold_upkeep
Definition game.h:131
struct packet_calendar_info calendar
Definition game.h:90
struct government * default_government
Definition game.h:93
struct civ_game::@32::@36::@37 deprecated
struct government * government_during_revolution
Definition game.h:94
struct civ_map::@44::@46 server
bool ocean_resources
Definition map_types.h:119
struct requirement_vector receiver_reqs
Definition diptreaty.h:61
struct requirement_vector giver_reqs
Definition diptreaty.h:60
struct requirement_vector either_reqs
Definition diptreaty.h:62
bool enabled
Definition diptreaty.h:59
enum unit_type_flag_id flag
Definition unittype.h:472
enum combat_bonus_type type
Definition unittype.h:473
struct name_translation name
Definition extras.h:90
int build_cost
Definition improvement.h:60
char graphic_str[MAX_LEN_NAME]
Definition improvement.h:55
char graphic_alt2[MAX_LEN_NAME]
Definition improvement.h:57
enum impr_genus_id genus
Definition improvement.h:63
char graphic_alt[MAX_LEN_NAME]
Definition improvement.h:56
struct requirement_vector obsolete_by
Definition improvement.h:59
char soundtag_alt[MAX_LEN_NAME]
Definition improvement.h:67
char soundtag_alt2[MAX_LEN_NAME]
Definition improvement.h:68
struct requirement_vector reqs
Definition improvement.h:58
struct strvec * helptext
Definition improvement.h:65
struct name_translation name
Definition improvement.h:52
bv_impr_flags flags
Definition improvement.h:64
char soundtag[MAX_LEN_NAME]
Definition improvement.h:66
Definition climisc.h:82
bool hidden
Definition nation.h:171
char * legend
Definition nation.h:107
enum barbarian_type barb_type
Definition nation.h:110
char calendar_fragment_name[MAX_CALENDAR_FRAGMENTS][MAX_LEN_NAME]
char negative_year_label[MAX_LEN_NAME]
char positive_year_label[MAX_LEN_NAME]
bool tech_steal_allow_holes
enum gameloss_style gameloss_style
int granary_food_ini[MAX_GRANARY_INIS]
enum goods_selection_method goods_selection
Government_type_id government_during_revolution_id
enum gold_upkeep_style gold_upkeep_style
int low_firepower_pearl_harbor
bool damage_reduces_bombard_rate
int nuke_defender_survival_chance_pct
enum tech_upkeep_style tech_upkeep_style
bool tech_trade_loss_allow_holes
enum free_tech_method free_tech_method
bool steal_maps_reveals_all_cities
bool only_real_fight_makes_veteran
enum tech_leakage_style tech_leakage
int min_city_center_output[O_LAST]
bool airlift_from_always_enabled
bool only_killing_makes_veteran
bool poison_empties_food_stock
bv_actions diplchance_initial_odds
bool tech_trade_allow_holes
int low_firepower_nonnat_bombard
bool tech_parasite_allow_holes
int low_firepower_combat_bonus
int border_city_permanent_radius_sq
int low_firepower_badwallattacker
bool airlift_to_always_enabled
enum wonder_visib_type small_wonder_visibility
enum tech_cost_style tech_cost_style
bool combat_odds_scaled_veterancy
bool unit_builders_nationality
Government_type_id default_government_id
char rule_name[MAX_LEN_NAME]
char name[MAX_LEN_NAME]
enum achievement_type type
action_id alternatives[MAX_NUM_ACTIONS]
struct requirement_vector reqs
enum action_auto_perf_cause cause
struct requirement_vector actor_reqs
struct requirement_vector target_reqs
char ui_name[MAX_LEN_NAME]
enum action_sub_target_kind sub_tgt_kind
enum action_actor_kind act_kind
bv_action_sub_results sub_results
enum action_target_kind tgt_kind
enum action_result result
enum base_gui_type gui_type
char graphic_alt2[MAX_LEN_NAME]
char name[MAX_LEN_NAME]
char rule_name[MAX_LEN_NAME]
char graphic_alt[MAX_LEN_NAME]
char graphic_str[MAX_LEN_NAME]
struct requirement_vector reqs
struct requirement_vector obs_reqs
char soundtag_alt2[MAX_LEN_NAME]
enum impr_genus_id genus
char soundtag[MAX_LEN_NAME]
char soundtag_alt[MAX_LEN_NAME]
struct strvec * helptext
struct requirement_vector giver_reqs
enum clause_type type
struct requirement_vector receiver_reqs
struct requirement_vector either_reqs
char alt_dir[MAX_LEN_NAME]
char version[MAX_LEN_NAME]
char preferred_musicset[MAX_LEN_NAME]
char name[MAX_LEN_NAME]
char preferred_tileset[MAX_LEN_NAME]
char preferred_soundset[MAX_LEN_NAME]
enum counter_target type
char name[MAX_LEN_NAME]
struct strvec * helptext
char rule_name[MAX_LEN_NAME]
enum counter_behavior behavior
char name[MAX_LEN_NAME]
char rule_name[MAX_LEN_NAME]
struct requirement_vector reqs
bv_disaster_effects effects
char helptxt[MAX_LEN_PACKET]
char graphic_str[MAX_LEN_NAME]
struct strvec * helptext
bv_unit_classes native_to
char graphic_alt[MAX_LEN_NAME]
char rmact_gfx[MAX_LEN_NAME]
struct requirement_vector appearance_reqs
char act_gfx_alt[MAX_LEN_NAME]
char act_gfx_alt2[MAX_LEN_NAME]
struct requirement_vector disappearance_reqs
bv_extra_flags flags
char rmact_gfx_alt[MAX_LEN_NAME]
struct requirement_vector rmreqs
enum extra_unit_seen_type eus
char activity_gfx[MAX_LEN_NAME]
char rule_name[MAX_LEN_NAME]
char name[MAX_LEN_NAME]
struct requirement_vector reqs
char rmact_gfx_alt2[MAX_LEN_NAME]
struct requirement_vector reqs
bv_goods_flags flags
char rule_name[MAX_LEN_NAME]
char name[MAX_LEN_NAME]
struct strvec * helptext
char helptxt[MAX_LEN_PACKET]
char sound_alt2[MAX_LEN_NAME]
char sound_str[MAX_LEN_NAME]
struct requirement_vector reqs
char graphic_alt[MAX_LEN_NAME]
Government_type_id id
char graphic_str[MAX_LEN_NAME]
char rule_name[MAX_LEN_NAME]
char sound_alt[MAX_LEN_NAME]
char name[MAX_LEN_NAME]
char helptxt[MAX_LEN_PACKET]
struct requirement_vector reqs
char name[MAX_LEN_NAME]
Multiplier_type_id id
char rule_name[MAX_LEN_NAME]
struct requirement_vector reqs
char music_peaceful[MAX_LEN_NAME]
char music_combat[MAX_LEN_NAME]
char graphic_alt[MAX_LEN_NAME]
char graphic_str[MAX_LEN_NAME]
bool leader_is_male[MAX_NUM_LEADERS]
int sets[MAX_NUM_NATION_SETS]
Impr_type_id init_buildings[MAX_NUM_BUILDING_LIST]
char adjective[MAX_LEN_NAME]
char translation_domain[MAX_LEN_NAME]
char leader_name[MAX_NUM_LEADERS][MAX_LEN_NAME]
int init_techs[MAX_NUM_TECH_LIST]
Unit_type_id init_units[MAX_NUM_UNIT_LIST]
char legend[MAX_LEN_MSG]
int groups[MAX_NUM_NATION_GROUPS]
Government_type_id init_government_id
enum barbarian_type barbarian_type
char noun_plural[MAX_LEN_NAME]
char rule_name[MAX_LEN_NAME]
bv_road_flags flags
enum road_gui_type gui_type
bv_max_extras integrates
int tile_incr_const[O_LAST]
enum road_compat compat
int tile_incr[O_LAST]
enum road_move_mode move_mode
int tile_bonus[O_LAST]
struct requirement_vector first_reqs
char plural_name[MAX_LEN_NAME]
struct requirement_vector reqs
Specialist_type_id id
char rule_name[MAX_LEN_NAME]
char short_name[MAX_LEN_NAME]
char graphic_alt[MAX_LEN_NAME]
char graphic_str[MAX_LEN_NAME]
char name[MAX_LEN_NAME]
char rule_name[MAX_LEN_NAME]
char text[MAX_LEN_CONTENT]
char rule_name[MAX_LEN_NAME]
char name[MAX_LEN_NAME]
char helptxt[MAX_LEN_PACKET]
struct strvec * helptext
char name[MAX_LEN_NAME]
char graphic_str[MAX_LEN_NAME]
char rule_name[MAX_LEN_NAME]
char graphic_alt[MAX_LEN_NAME]
bv_tech_flags flags
struct requirement_vector research_reqs
char helptxt[MAX_LEN_PACKET]
Terrain_type_id transform_result
char name[MAX_LEN_NAME]
int animals[MAX_NUM_ANIMALS]
int resource_freq[MAX_EXTRA_TYPES]
bv_terrain_flags flags
Resource_type_id resources[MAX_EXTRA_TYPES]
char graphic_alt[MAX_LEN_NAME]
bv_unit_classes native_to
int road_output_incr_pct[O_LAST]
char graphic_alt2[MAX_LEN_NAME]
Terrain_type_id cultivate_result
int extra_removal_times[MAX_EXTRA_TYPES]
Terrain_type_id plant_result
char rule_name[MAX_LEN_NAME]
char graphic_str[MAX_LEN_NAME]
struct strvec * helptext
char rule_name[MAX_LEN_NAME]
char name[MAX_LEN_NAME]
enum trade_route_illegal_cancelling cancelling
enum trade_route_bonus_type bonus_type
char helptxt[MAX_LEN_PACKET]
bv_unit_class_flags flags
char rule_name[MAX_LEN_NAME]
char name[MAX_LEN_NAME]
char helptxt[MAX_LEN_PACKET]
enum vision_layer vlayer
enum transp_def_type tp_defense
char rule_name[MAX_LEN_NAME]
int base_raise_chance[MAX_VET_LEVELS]
int move_bonus[MAX_VET_LEVELS]
int work_raise_chance[MAX_VET_LEVELS]
char sound_move[MAX_LEN_NAME]
bv_unit_classes disembarks
bv_unit_classes cargo
bv_unit_type_flags flags
char sound_fight_alt[MAX_LEN_NAME]
char graphic_str[MAX_LEN_NAME]
bv_unit_classes targets
struct requirement_vector build_reqs
int power_fact[MAX_VET_LEVELS]
char veteran_name[MAX_VET_LEVELS][MAX_LEN_NAME]
bv_unit_classes embarks
char sound_fight[MAX_LEN_NAME]
char sound_move_alt[MAX_LEN_NAME]
struct strvec * helptext
char graphic_alt2[MAX_LEN_NAME]
char graphic_alt[MAX_LEN_NAME]
char name[MAX_LEN_NAME]
bv_unit_type_roles roles
Definition goto.c:52
struct universal source
int g
Definition rgbcolor.h:34
int b
Definition rgbcolor.h:34
int r
Definition rgbcolor.h:34
enum road_gui_type gui_type
Definition road.h:80
struct requirement_vector first_reqs
Definition road.h:82
enum road_move_mode move_mode
Definition road.h:75
int tile_bonus[O_LAST]
Definition road.h:78
int tile_incr_const[O_LAST]
Definition road.h:76
int tile_incr[O_LAST]
Definition road.h:77
bv_road_flags flags
Definition road.h:85
int move_cost
Definition road.h:74
enum road_compat compat
Definition road.h:79
bv_max_extras integrates
Definition road.h:84
bool compat_mode
Definition rscompat.h:31
struct requirement_vector reqs
Definition specialist.h:38
char graphic_alt[MAX_LEN_NAME]
Definition specialist.h:36
struct strvec * helptext
Definition specialist.h:40
char graphic_str[MAX_LEN_NAME]
Definition specialist.h:35
struct name_translation name
Definition specialist.h:31
struct name_translation abbreviation
Definition specialist.h:32
char ** vec
enum trade_route_bonus_type bonus_type
Definition traderoutes.h:78
enum trade_route_illegal_cancelling cancelling
Definition traderoutes.h:77
int fixed
Definition traits.h:46
enum universals_n kind
Definition fc_types.h:595
struct veteran_level * definitions
Definition unittype.h:502
struct civ_map map
struct nation_style * style_by_rule_name(const char *name)
Definition style.c:113
struct nation_style * style_by_number(int id)
Definition style.c:84
void styles_alloc(int count)
Definition style.c:36
struct music_style * music_style_by_number(int id)
Definition style.c:165
int style_number(const struct nation_style *pstyle)
Definition style.c:68
void music_styles_alloc(int count)
Definition style.c:129
int style_index(const struct nation_style *pstyle)
Definition style.c:76
#define music_styles_iterate(_p)
Definition style.h:75
#define music_styles_iterate_end
Definition style.h:82
#define styles_iterate(_p)
Definition style.h:48
#define styles_iterate_end
Definition style.h:54
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:925
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:742
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:186
bool fc_isspace(char c)
Definition support.c:1205
size_t fc_strlcat(char *dest, const char *src, size_t n)
Definition support.c:787
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition support.c:851
char fc_tolower(char c)
Definition support.c:1238
#define sz_strlcpy(dest, src)
Definition support.h:195
#define RETURN_VALUE_AFTER_EXIT(_val_)
Definition support.h:146
#define fc__attribute(x)
Definition support.h:99
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
struct team_slot * team_slot_by_number(int team_id)
Definition team.c:173
const char * team_slot_defined_name(const struct team_slot *tslot)
Definition team.c:272
int team_slot_index(const struct team_slot *tslot)
Definition team.c:138
int team_slot_count(void)
Definition team.c:112
void team_slot_set_defined_name(struct team_slot *tslot, const char *team_name)
Definition team.c:282
#define team_slots_iterate_end
Definition team.h:89
#define team_slots_iterate(_tslot)
Definition team.h:84
struct advance * advance_by_number(const Tech_type_id atype)
Definition tech.c:110
const char * tech_flag_id_name_cb(enum tech_flag_id flag)
Definition tech.c:438
void set_user_tech_flag_name(enum tech_flag_id id, const char *name, const char *helptxt)
Definition tech.c:409
struct advance * valid_advance(struct advance *padvance)
Definition tech.c:157
void techs_precalc_data(void)
Definition tech.c:230
const char * advance_rule_name(const struct advance *padvance)
Definition tech.c:314
const char * tech_flag_helptxt(enum tech_flag_id id)
Definition tech.c:450
struct advance * advance_by_rule_name(const char *name)
Definition tech.c:205
struct tech_class * tech_class_by_rule_name(const char *name)
Definition tech.c:366
Tech_type_id advance_number(const struct advance *padvance)
Definition tech.c:100
#define tech_class_index(_ptclass_)
Definition tech.h:190
#define A_NEVER
Definition tech.h:51
#define tech_class_iterate_end
Definition tech.h:201
#define MAX_NUM_USER_TECH_FLAGS
Definition tech.h:105
#define advance_iterate_all_end
Definition tech.h:277
@ AR_TWO
Definition tech.h:109
@ AR_ROOT
Definition tech.h:110
@ AR_ONE
Definition tech.h:108
#define advance_iterate_all(_p)
Definition tech.h:276
static Tech_type_id advance_count(void)
Definition tech.h:167
#define A_FIRST
Definition tech.h:44
#define A_NONE
Definition tech.h:43
#define advance_iterate(_p)
Definition tech.h:273
#define tech_class_iterate(_p)
Definition tech.h:195
#define advance_iterate_end
Definition tech.h:274
#define A_LAST
Definition tech.h:45
struct terrain * terrain_by_rule_name(const char *name)
Definition terrain.c:188
Terrain_type_id terrain_count(void)
Definition terrain.c:119
const char * terrain_flag_id_name_cb(enum terrain_flag_id flag)
Definition terrain.c:820
Terrain_type_id terrain_index(const struct terrain *pterrain)
Definition terrain.c:139
struct terrain * terrain_by_number(const Terrain_type_id type)
Definition terrain.c:157
const char * terrain_flag_helptxt(enum terrain_flag_id id)
Definition terrain.c:832
struct resource_type * resource_type_init(struct extra_type *pextra)
Definition terrain.c:275
void set_user_terrain_flag_name(enum terrain_flag_id id, const char *name, const char *helptxt)
Definition terrain.c:791
Terrain_type_id terrain_number(const struct terrain *pterrain)
Definition terrain.c:148
#define RESOURCE_FREQUENCY_MAXIMUM
Definition terrain.h:102
#define terrain_type_iterate(_p)
Definition terrain.h:267
#define terrain_animals_iterate(pterrain, _animal)
Definition terrain.h:299
#define T_NONE
Definition terrain.h:61
#define TERRAIN_UNKNOWN_IDENTIFIER
Definition terrain.h:88
#define terrain_type_iterate_end
Definition terrain.h:273
#define RESOURCE_NONE_IDENTIFIER
Definition terrain.h:52
#define RESOURCE_NULL_IDENTIFIER
Definition terrain.h:51
#define RESOURCE_FREQUENCY_MINIMUM
Definition terrain.h:100
#define MAX_NUM_TERRAINS
Definition terrain.h:69
#define T_FIRST
Definition terrain.h:65
#define MAX_NUM_USER_TER_FLAGS
Definition terrain.h:32
#define terrain_resources_iterate_end
Definition terrain.h:295
#define terrain_resources_iterate(pterrain, _res, _freq)
Definition terrain.h:286
#define terrain_animals_iterate_end
Definition terrain.h:307
#define RESOURCE_FREQUENCY_DEFAULT
Definition terrain.h:101
#define ACTIVITY_FACTOR
Definition tile.h:170
int tiledef_number(const struct tiledef *td)
Definition tiledef.c:62
struct tiledef * tiledef_by_number(int id)
Definition tiledef.c:84
#define tiledef_index(_td_)
Definition tiledef.h:45
#define tiledef_iterate_end
Definition tiledef.h:58
#define tiledef_iterate(_p)
Definition tiledef.h:52
Goods_type_id goods_number(const struct goods_type *pgood)
enum trade_route_illegal_cancelling trade_route_cancelling_type_by_name(const char *name)
struct trade_route_settings * trade_route_settings_by_type(enum trade_route_type type)
const char * goods_rule_name(struct goods_type *pgood)
Goods_type_id goods_index(const struct goods_type *pgood)
enum trade_route_type trade_route_type_by_name(const char *name)
#define goods_type_iterate_end
@ TRI_LAST
Definition traderoutes.h:33
#define goods_type_iterate(_p)
trade_route_type
Definition traderoutes.h:37
@ TRT_NATIONAL
Definition traderoutes.h:38
@ TRT_LAST
Definition traderoutes.h:48
#define TRAIT_DEFAULT_VALUE
Definition traits.h:32
void set_unit_class_caches(struct unit_class *pclass)
Definition unittype.c:2793
const char * unit_class_flag_helptxt(enum unit_class_flag_id id)
Definition unittype.c:1881
struct unit_type * unit_type_by_rule_name(const char *name)
Definition unittype.c:1794
bool utype_has_role(const struct unit_type *punittype, int role)
Definition unittype.c:224
void unit_type_action_cache_init(void)
Definition unittype.c:956
void set_unit_type_caches(struct unit_type *ptype)
Definition unittype.c:2852
void role_unit_precalcs(void)
Definition unittype.c:2206
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)
Definition unittype.c:2722
Unit_type_id utype_count(void)
Definition unittype.c:82
int utype_veteran_levels(const struct unit_type *punittype)
Definition unittype.c:2662
const char * utype_rule_name(const struct unit_type *punittype)
Definition unittype.c:1604
const struct veteran_level * utype_veteran_level(const struct unit_type *punittype, int level)
Definition unittype.c:2634
const char * uclass_rule_name(const struct unit_class *pclass)
Definition unittype.c:1667
Unit_type_id utype_number(const struct unit_type *punittype)
Definition unittype.c:102
struct unit_class * unit_class_by_rule_name(const char *s)
Definition unittype.c:1811
const char * unit_type_flag_helptxt(enum unit_type_flag_id id)
Definition unittype.c:1944
Unit_type_id utype_index(const struct unit_type *punittype)
Definition unittype.c:93
void set_user_unit_class_flag_name(enum unit_class_flag_id id, const char *name, const char *helptxt)
Definition unittype.c:1839
struct veteran_system * veteran_system_new(int count)
Definition unittype.c:2691
Unit_Class_id uclass_number(const struct unit_class *pclass)
Definition unittype.c:2502
bool utype_can_do_action(const struct unit_type *putype, const action_id act_id)
Definition unittype.c:396
void set_user_unit_type_flag_name(enum unit_type_flag_id id, const char *name, const char *helptxt)
Definition unittype.c:1903
static bool uclass_has_flag(const struct unit_class *punitclass, enum unit_class_flag_id flag)
Definition unittype.h:773
#define utype_class(_t_)
Definition unittype.h:756
#define combat_bonus_list_iterate_end
Definition unittype.h:487
#define L_FIRST
Definition unittype.h:354
#define combat_bonus_list_iterate(bonuslist, pbonus)
Definition unittype.h:485
#define unit_tech_reqs_iterate_end
Definition unittype.h:891
#define unit_class_iterate(_p)
Definition unittype.h:918
#define unit_tech_reqs_iterate(_utype_, _p)
Definition unittype.h:885
#define MAX_NUM_USER_UNIT_FLAGS
Definition unittype.h:336
static bool utype_has_flag(const struct unit_type *punittype, int flag)
Definition unittype.h:624
#define UTYF_LAST_USER_FLAG
Definition unittype.h:335
#define unit_type_iterate(_p)
Definition unittype.h:865
#define U_LAST
Definition unittype.h:40
#define uclass_index(_c_)
Definition unittype.h:749
#define unit_class_iterate_end
Definition unittype.h:925
#define unit_type_iterate_end
Definition unittype.h:872
#define MAX_NUM_USER_UCLASS_FLAGS
Definition unittype.h:128