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)
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 ***********************************************************************/
15 #include <fc_config.h>
24 #include "bitvector.h"
25 #include "deprecations.h"
31 #include "string_vector.h"
35 #include "achievements.h"
39 #include "capability.h"
44 #include "featured_text.h"
46 #include "government.h"
49 #include "multipliers.h"
50 #include "name_translation.h"
54 #include "requirements.h"
57 #include "specialist.h"
60 #include "traderoutes.h"
65 #include "citytools.h"
74 #include "advruleset.h"
76 /* server/scripting */
77 #include "script_server.h"
81 /* RULESET_SUFFIX already used, no leading dot here */
82 #define RULES_SUFFIX "ruleset"
83 #define SCRIPT_SUFFIX "lua"
85 #define ADVANCE_SECTION_PREFIX "advance_"
86 #define TECH_CLASS_SECTION_PREFIX "techclass_"
87 #define BUILDING_SECTION_PREFIX "building_"
88 #define CITYSTYLE_SECTION_PREFIX "citystyle_"
89 #define MUSICSTYLE_SECTION_PREFIX "musicstyle_"
90 #define EFFECT_SECTION_PREFIX "effect_"
91 #define GOVERNMENT_SECTION_PREFIX "government_"
92 #define NATION_SET_SECTION_PREFIX "nset" /* without underscore? */
93 #define NATION_GROUP_SECTION_PREFIX "ngroup" /* without underscore? */
94 #define NATION_SECTION_PREFIX "nation" /* without underscore? */
95 #define STYLE_SECTION_PREFIX "style_"
96 #define EXTRA_SECTION_PREFIX "extra_"
97 #define BASE_SECTION_PREFIX "base_"
98 #define ROAD_SECTION_PREFIX "road_"
99 #define RESOURCE_SECTION_PREFIX "resource_"
100 #define GOODS_SECTION_PREFIX "goods_"
101 #define SPECIALIST_SECTION_PREFIX "specialist_"
102 #define TERRAIN_SECTION_PREFIX "terrain_"
103 #define UNIT_CLASS_SECTION_PREFIX "unitclass_"
104 #define UNIT_SECTION_PREFIX "unit_"
105 #define DISASTER_SECTION_PREFIX "disaster_"
106 #define ACHIEVEMENT_SECTION_PREFIX "achievement_"
107 #define ACTION_ENABLER_SECTION_PREFIX "actionenabler_"
108 #define MULTIPLIER_SECTION_PREFIX "multiplier_"
110 #define check_name(name) (check_strlen(name, MAX_LEN_NAME, NULL))
111 #define check_cityname(name) (check_strlen(name, MAX_LEN_CITYNAME, NULL))
113 /* avoid re-reading files */
114 static const char name_too_long
[] = "Name \"%s\" too long; truncating.";
115 #define MAX_SECTION_LABEL 64
116 #define section_strlcpy(dst, src) \
117 (void) loud_strlcpy(dst, src, MAX_SECTION_LABEL, name_too_long)
118 static char *resource_sections
= NULL
;
119 static char *terrain_sections
= NULL
;
120 static char *extra_sections
= NULL
;
121 static char *base_sections
= NULL
;
122 static char *road_sections
= NULL
;
124 static struct requirement_vector reqs_list
;
126 static bool load_rulesetdir(const char *rsdir
, bool compat_mode
,
127 bool act
, bool buffer_script
);
128 static struct section_file
*openload_ruleset_file(const char *whichset
,
131 static bool load_game_names(struct section_file
*file
,
132 struct rscompat_info
*compat
);
133 static bool load_tech_names(struct section_file
*file
,
134 struct rscompat_info
*compat
);
135 static bool load_unit_names(struct section_file
*file
,
136 struct rscompat_info
*compat
);
137 static bool load_building_names(struct section_file
*file
,
138 struct rscompat_info
*compat
);
139 static bool load_government_names(struct section_file
*file
,
140 struct rscompat_info
*compat
);
141 static bool load_terrain_names(struct section_file
*file
,
142 struct rscompat_info
*compat
);
143 static bool load_style_names(struct section_file
*file
,
144 struct rscompat_info
*compat
);
145 static bool load_nation_names(struct section_file
*file
,
146 struct rscompat_info
*compat
);
147 static bool load_city_name_list(struct section_file
*file
,
148 struct nation_type
*pnation
,
149 const char *secfile_str1
,
150 const char *secfile_str2
,
151 const char **allowed_terrains
,
154 static bool load_ruleset_techs(struct section_file
*file
,
155 struct rscompat_info
*compat
);
156 static bool load_ruleset_units(struct section_file
*file
,
157 struct rscompat_info
*compat
);
158 static bool load_ruleset_buildings(struct section_file
*file
,
159 struct rscompat_info
*compat
);
160 static bool load_ruleset_governments(struct section_file
*file
,
161 struct rscompat_info
*compat
);
162 static bool load_ruleset_terrain(struct section_file
*file
,
163 struct rscompat_info
*compat
);
164 static bool load_ruleset_styles(struct section_file
*file
,
165 struct rscompat_info
*compat
);
166 static bool load_ruleset_cities(struct section_file
*file
,
167 struct rscompat_info
*compat
);
168 static bool load_ruleset_effects(struct section_file
*file
,
169 struct rscompat_info
*compat
);
170 static bool load_ruleset_game(struct section_file
*file
, bool act
,
171 struct rscompat_info
*compat
);
173 static void send_ruleset_tech_classes(struct conn_list
*dest
);
174 static void send_ruleset_techs(struct conn_list
*dest
);
175 static void send_ruleset_unit_classes(struct conn_list
*dest
);
176 static void send_ruleset_units(struct conn_list
*dest
);
177 static void send_ruleset_buildings(struct conn_list
*dest
);
178 static void send_ruleset_terrain(struct conn_list
*dest
);
179 static void send_ruleset_resources(struct conn_list
*dest
);
180 static void send_ruleset_extras(struct conn_list
*dest
);
181 static void send_ruleset_bases(struct conn_list
*dest
);
182 static void send_ruleset_roads(struct conn_list
*dest
);
183 static void send_ruleset_goods(struct conn_list
*dest
);
184 static void send_ruleset_governments(struct conn_list
*dest
);
185 static void send_ruleset_styles(struct conn_list
*dest
);
186 static void send_ruleset_musics(struct conn_list
*dest
);
187 static void send_ruleset_cities(struct conn_list
*dest
);
188 static void send_ruleset_game(struct conn_list
*dest
);
189 static void send_ruleset_team_names(struct conn_list
*dest
);
191 static bool load_ruleset_veteran(struct section_file
*file
,
193 struct veteran_system
**vsystem
, char *err
,
196 char *script_buffer
= NULL
;
197 char *parser_buffer
= NULL
;
199 /**************************************************************************
200 Notifications about ruleset errors to clients. Especially important in
201 case of internal server crashing.
202 **************************************************************************/
203 void ruleset_error_real(const char *file
, const char *function
,
204 int line
, enum log_level level
,
205 const char *format
, ...)
210 va_start(args
, format
);
211 vdo_log(file
, function
, line
, FALSE
, level
, buf
, sizeof(buf
), format
, args
);
214 if (LOG_FATAL
>= level
) {
219 /**************************************************************************
220 datafilename() wrapper: tries to match in two ways.
221 Returns NULL on failure, the (statically allocated) filename on success.
222 **************************************************************************/
223 static const char *valid_ruleset_filename(const char *subdir
,
225 const char *extension
,
229 const char *dfilename
;
231 fc_assert_ret_val(subdir
&& name
&& extension
, NULL
);
233 fc_snprintf(filename
, sizeof(filename
), "%s" DIR_SEPARATOR
"%s.%s",
234 subdir
, name
, extension
);
235 log_verbose("Trying \"%s\".", filename
);
236 dfilename
= fileinfoname(get_data_dirs(), filename
);
241 fc_snprintf(filename
, sizeof(filename
), "default" DIR_SEPARATOR
"%s.%s", name
, extension
);
242 log_verbose("Trying \"%s\": default ruleset directory.", filename
);
243 dfilename
= fileinfoname(get_data_dirs(), filename
);
248 fc_snprintf(filename
, sizeof(filename
), "%s_%s.%s",
249 subdir
, name
, extension
);
250 log_verbose("Trying \"%s\": alternative ruleset filename syntax.",
252 dfilename
= fileinfoname(get_data_dirs(), filename
);
255 } else if (!optional
) {
256 ruleset_error(LOG_ERROR
,
257 /* TRANS: message about an installation error. */
258 _("Could not find a readable \"%s.%s\" ruleset file."),
265 /**************************************************************************
266 Return current script.lua buffer.
267 **************************************************************************/
268 char *get_script_buffer(void)
270 return script_buffer
;
273 /**************************************************************************
274 Return current parser.lua buffer.
275 **************************************************************************/
276 char *get_parser_buffer(void)
278 return parser_buffer
;
281 /**************************************************************************
282 Do initial section_file_load on a ruleset file.
283 "whichset" = "techs", "units", "buildings", "terrain", ...
284 **************************************************************************/
285 static struct section_file
*openload_ruleset_file(const char *whichset
,
289 const char *dfilename
= valid_ruleset_filename(rsdir
, whichset
,
290 RULES_SUFFIX
, FALSE
);
291 struct section_file
*secfile
;
293 if (dfilename
== NULL
) {
297 /* Need to save a copy of the filename for following message, since
298 section_file_load() may call datafilename() for includes. */
299 sz_strlcpy(sfilename
, dfilename
);
300 secfile
= secfile_load(sfilename
, FALSE
);
302 if (secfile
== NULL
) {
303 ruleset_error(LOG_ERROR
, "Could not load ruleset '%s':\n%s",
304 sfilename
, secfile_error());
310 /**************************************************************************
312 **************************************************************************/
313 static bool openload_script_file(const char *whichset
, const char *rsdir
,
316 const char *dfilename
= valid_ruleset_filename(rsdir
, whichset
,
317 SCRIPT_SUFFIX
, FALSE
);
319 if (dfilename
== NULL
) {
323 if (buffer
== NULL
) {
324 if (!script_server_do_file(NULL
, dfilename
)) {
325 ruleset_error(LOG_ERROR
, "\"%s\": could not load ruleset script.",
331 script_server_load_file(dfilename
, buffer
);
337 /**************************************************************************
338 Load optional luadata.txt
339 **************************************************************************/
340 static struct section_file
*openload_luadata_file(const char *rsdir
)
342 struct section_file
*secfile
;
344 const char *dfilename
= valid_ruleset_filename(rsdir
, "luadata",
347 if (dfilename
== NULL
) {
351 /* Need to save a copy of the filename for following message, since
352 section_file_load() may call datafilename() for includes. */
353 sz_strlcpy(sfilename
, dfilename
);
354 secfile
= secfile_load(sfilename
, FALSE
);
356 if (secfile
== NULL
) {
357 ruleset_error(LOG_ERROR
, "Could not load luadata '%s':\n%s",
358 sfilename
, secfile_error());
364 /**************************************************************************
365 Load a requirement list. The list is returned as a static vector
366 (callers need not worry about freeing anything).
367 **************************************************************************/
368 static struct requirement_vector
*lookup_req_list(struct section_file
*file
,
369 struct rscompat_info
*compat
,
374 const char *type
, *name
;
376 const char *filename
;
378 filename
= secfile_name(file
);
380 requirement_vector_reserve(&reqs_list
, 0);
382 for (j
= 0; (type
= secfile_lookup_str_default(file
, NULL
, "%s.%s%d.type",
383 sec
, sub
, j
)); j
++) {
384 char buf
[MAX_LEN_NAME
];
386 bool survives
, present
, quiet
;
387 struct entry
*pentry
;
388 struct requirement req
;
390 if (!(pentry
= secfile_entry_lookup(file
, "%s.%s%d.name",
392 ruleset_error(LOG_ERROR
, "%s", secfile_error());
397 switch (entry_type(pentry
)) {
402 if (entry_bool_get(pentry
, &val
)) {
403 fc_snprintf(buf
, sizeof(buf
), "%d", val
);
412 if (entry_int_get(pentry
, &val
)) {
413 fc_snprintf(buf
, sizeof(buf
), "%d", val
);
419 (void) entry_str_get(pentry
, &name
);
422 fc_assert(entry_type(pentry
) != ENTRY_FLOAT
);
423 ruleset_error(LOG_ERROR
,
424 "\"%s\": trying to have an floating point entry as a requirement name in '%s.%s%d'.",
425 filename
, sec
, sub
, j
);
427 case ENTRY_FILEREFERENCE
:
428 fc_assert(entry_type(pentry
) != ENTRY_FILEREFERENCE
);
431 ruleset_error(LOG_ERROR
,
432 "\"%s\": error in handling requirement name for '%s.%s%d'.",
433 filename
, sec
, sub
, j
);
437 if (!(range
= secfile_lookup_str(file
, "%s.%s%d.range", sec
, sub
, j
))) {
438 ruleset_error(LOG_ERROR
, "%s", secfile_error());
444 if ((pentry
= secfile_entry_lookup(file
, "%s.%s%d.survives",
446 && !entry_bool_get(pentry
, &survives
)) {
447 ruleset_error(LOG_ERROR
,
448 "\"%s\": invalid boolean value for survives for "
449 "'%s.%s%d'.", filename
, sec
, sub
, j
);
453 if ((pentry
= secfile_entry_lookup(file
, "%s.%s%d.present",
455 && !entry_bool_get(pentry
, &present
)) {
456 ruleset_error(LOG_ERROR
,
457 "\"%s\": invalid boolean value for present for "
458 "'%s.%s%d'.", filename
, sec
, sub
, j
);
461 if ((pentry
= secfile_entry_lookup(file
, "%s.%s%d.quiet",
463 && !entry_bool_get(pentry
, &quiet
)) {
464 ruleset_error(LOG_ERROR
,
465 "\"%s\": invalid boolean value for quiet for "
466 "'%s.%s%d'.", filename
, sec
, sub
, j
);
469 if (compat
->compat_mode
) {
470 if (!fc_strcasecmp(type
, universals_n_name(VUT_UTFLAG
))) {
471 name
= rscompat_utype_flag_name_3_1(compat
, name
);
475 if (compat
->compat_mode
) {
476 name
= rscompat_req_name_3_1(type
, name
);
479 req
= req_from_str(type
, range
, survives
, present
, quiet
, name
);
480 if (req
.source
.kind
== universals_n_invalid()) {
481 ruleset_error(LOG_ERROR
, "\"%s\" [%s] has invalid or unknown req: "
483 filename
, sec
, type
, name
);
488 requirement_vector_append(&reqs_list
, req
);
491 if (j
> MAX_NUM_REQS
) {
492 ruleset_error(LOG_ERROR
, "Too many (%d) requirements for %s. Max is %d",
493 j
, rfor
, MAX_NUM_REQS
);
501 /**************************************************************************
502 Load combat bonus list
503 **************************************************************************/
504 static bool lookup_cbonus_list(struct rscompat_info
*compat
,
505 struct combat_bonus_list
*list
,
506 struct section_file
*file
,
512 const char *filename
;
515 filename
= secfile_name(file
);
517 for (j
= 0; (flag
= secfile_lookup_str_default(file
, NULL
, "%s.%s%d.flag",
518 sec
, sub
, j
)); j
++) {
519 struct combat_bonus
*bonus
= fc_malloc(sizeof(*bonus
));
522 bonus
->flag
= unit_type_flag_id_by_name(rscompat_utype_flag_name_3_1(compat
, flag
),
524 if (!unit_type_flag_id_is_valid(bonus
->flag
)) {
525 log_error("\"%s\": unknown flag name \"%s\" in '%s.%s'.",
526 filename
, flag
, sec
, sub
);
531 type
= secfile_lookup_str(file
, "%s.%s%d.type", sec
, sub
, j
);
532 bonus
->type
= combat_bonus_type_by_name(type
, fc_strcasecmp
);
533 if (!combat_bonus_type_is_valid(bonus
->type
)) {
534 log_error("\"%s\": unknown bonus type \"%s\" in '%s.%s'.",
535 filename
, type
, sec
, sub
);
540 if (!secfile_lookup_int(file
, &bonus
->value
, "%s.%s%d.value",
542 log_error("\"%s\": failed to get value from '%s.%s%d'.",
543 filename
, sec
, sub
, j
);
548 bonus
->quiet
= secfile_lookup_bool_default(file
, FALSE
,
551 combat_bonus_list_append(list
, bonus
);
557 /**************************************************************************
558 Lookup a string prefix.entry in the file and return the corresponding
559 advances pointer. If (!required), return A_NEVER for match "Never" or
560 can't match. If (required), die when can't match. Note the first tech
561 should have name "None" so that will always match.
562 If description is not NULL, it is used in the warning message
563 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
564 **************************************************************************/
565 static bool lookup_tech(struct section_file
*file
,
566 struct advance
**result
,
567 const char *prefix
, const char *entry
,
568 const char *filename
,
569 const char *description
)
573 sval
= secfile_lookup_str_default(file
, NULL
, "%s.%s", prefix
, entry
);
574 if (!sval
|| !strcmp(sval
, "Never")) {
577 *result
= advance_by_rule_name(sval
);
579 if (A_NEVER
== *result
) {
580 ruleset_error(LOG_ERROR
,
581 "\"%s\" %s %s: couldn't match \"%s\".",
582 filename
, (description
? description
: prefix
), entry
, sval
);
590 /**************************************************************************
591 Lookup a string prefix.entry in the file and return the corresponding
592 improvement pointer. Return B_NEVER for match "None" or
594 If description is not NULL, it is used in the warning message
595 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
596 **************************************************************************/
597 static bool lookup_building(struct section_file
*file
,
598 const char *prefix
, const char *entry
,
599 struct impr_type
**result
,
600 const char *filename
,
601 const char *description
)
606 sval
= secfile_lookup_str_default(file
, NULL
, "%s.%s", prefix
, entry
);
607 if (!sval
|| strcmp(sval
, "None") == 0) {
610 *result
= improvement_by_rule_name(sval
);
612 if (B_NEVER
== *result
) {
613 ruleset_error(LOG_ERROR
,
614 "\"%s\" %s %s: couldn't match \"%s\".",
615 filename
, (description
? description
: prefix
), entry
, sval
);
623 /**************************************************************************
624 Lookup a prefix.entry string vector in the file and fill in the
625 array, which should hold MAX_NUM_UNIT_LIST items. The output array is
626 either NULL terminated or full (contains MAX_NUM_UNIT_LIST
627 items). If the vector is not found and the required parameter is set,
628 we report it as an error, otherwise we just punt.
629 **************************************************************************/
630 static bool lookup_unit_list(struct section_file
*file
, const char *prefix
,
632 struct unit_type
**output
,
633 const char *filename
)
640 /* pre-fill with NULL: */
641 for (i
= 0; i
< MAX_NUM_UNIT_LIST
; i
++) {
644 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.%s", prefix
, entry
);
646 /* 'No vector' is considered same as empty vector */
652 if (nval
> MAX_NUM_UNIT_LIST
) {
653 ruleset_error(LOG_ERROR
,
654 "\"%s\": string vector %s.%s too long (%d, max %d)",
655 filename
, prefix
, entry
, (int) nval
, MAX_NUM_UNIT_LIST
);
657 } else if (nval
== 1 && strcmp(slist
[0], "") == 0) {
662 for (i
= 0; i
< nval
; i
++) {
663 const char *sval
= slist
[i
];
664 struct unit_type
*punittype
= unit_type_by_rule_name(sval
);
667 ruleset_error(LOG_ERROR
,
668 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
669 filename
, prefix
, entry
, i
, sval
);
673 output
[i
] = punittype
;
674 log_debug("\"%s\" %s.%s (%d): %s (%d)", filename
, prefix
, entry
, i
, sval
,
675 utype_number(punittype
));
683 /**************************************************************************
684 Lookup a prefix.entry string vector in the file and fill in the
685 array, which should hold MAX_NUM_TECH_LIST items. The output array is
686 either A_LAST terminated or full (contains MAX_NUM_TECH_LIST
687 items). All valid entries of the output array are guaranteed to
689 **************************************************************************/
690 static bool lookup_tech_list(struct section_file
*file
, const char *prefix
,
691 const char *entry
, int *output
,
692 const char *filename
)
699 /* pre-fill with A_LAST: */
700 for (i
= 0; i
< MAX_NUM_TECH_LIST
; i
++) {
703 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.%s", prefix
, entry
);
704 if (slist
== NULL
|| nval
== 0) {
706 } else if (nval
> MAX_NUM_TECH_LIST
) {
707 ruleset_error(LOG_ERROR
,
708 "\"%s\": string vector %s.%s too long (%d, max %d)",
709 filename
, prefix
, entry
, (int) nval
, MAX_NUM_TECH_LIST
);
714 if (nval
== 1 && strcmp(slist
[0], "") == 0) {
718 for (i
= 0; i
< nval
&& ok
; i
++) {
719 const char *sval
= slist
[i
];
720 struct advance
*padvance
= advance_by_rule_name(sval
);
722 if (NULL
== padvance
) {
723 ruleset_error(LOG_ERROR
,
724 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
725 filename
, prefix
, entry
, i
, sval
);
728 if (!valid_advance(padvance
)) {
729 ruleset_error(LOG_ERROR
, "\"%s\" %s.%s (%d): \"%s\" is removed.",
730 filename
, prefix
, entry
, i
, sval
);
735 output
[i
] = advance_number(padvance
);
736 log_debug("\"%s\" %s.%s (%d): %s (%d)", filename
, prefix
, entry
, i
, sval
,
737 advance_number(padvance
));
746 /**************************************************************************
747 Lookup a prefix.entry string vector in the file and fill in the
748 array, which should hold MAX_NUM_BUILDING_LIST items. The output array is
749 either B_LAST terminated or full (contains MAX_NUM_BUILDING_LIST
750 items). [All valid entries of the output array are guaranteed to pass
751 improvement_exist()?]
752 **************************************************************************/
753 static bool lookup_building_list(struct section_file
*file
,
754 const char *prefix
, const char *entry
,
755 int *output
, const char *filename
)
762 /* pre-fill with B_LAST: */
763 for (i
= 0; i
< MAX_NUM_BUILDING_LIST
; i
++) {
766 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.%s", prefix
, entry
);
767 if (nval
> MAX_NUM_BUILDING_LIST
) {
768 ruleset_error(LOG_ERROR
,
769 "\"%s\": string vector %s.%s too long (%d, max %d)",
770 filename
, prefix
, entry
, (int) nval
, MAX_NUM_BUILDING_LIST
);
772 } else if (nval
== 0 || (nval
== 1 && strcmp(slist
[0], "") == 0)) {
779 for (i
= 0; i
< nval
; i
++) {
780 const char *sval
= slist
[i
];
781 struct impr_type
*pimprove
= improvement_by_rule_name(sval
);
783 if (NULL
== pimprove
) {
784 ruleset_error(LOG_ERROR
,
785 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
786 filename
, prefix
, entry
, i
, sval
);
790 output
[i
] = improvement_number(pimprove
);
791 log_debug("%s.%s,%d %s %d", prefix
, entry
, i
, sval
, output
[i
]);
799 /**************************************************************************
800 Lookup a string prefix.entry in the file and set result to the corresponding
802 If description is not NULL, it is used in the warning message
803 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
804 **************************************************************************/
805 static bool lookup_unit_type(struct section_file
*file
,
808 struct unit_type
**result
,
809 const char *filename
,
810 const char *description
)
814 sval
= secfile_lookup_str_default(file
, "None", "%s.%s", prefix
, entry
);
816 if (strcmp(sval
, "None") == 0) {
819 *result
= unit_type_by_rule_name(sval
);
820 if (*result
== NULL
) {
821 ruleset_error(LOG_ERROR
,
822 "\"%s\" %s %s: couldn't match \"%s\".",
823 filename
, (description
? description
: prefix
), entry
, sval
);
832 /**************************************************************************
833 Lookup entry in the file and return the corresponding government index.
834 filename is for error message.
835 **************************************************************************/
836 static struct government
*lookup_government(struct section_file
*file
,
838 const char *filename
,
839 struct government
*fallback
)
842 struct government
*gov
;
844 sval
= secfile_lookup_str_default(file
, NULL
, "%s", entry
);
848 gov
= government_by_rule_name(sval
);
851 ruleset_error(LOG_ERROR
,
852 "\"%s\" %s: couldn't match \"%s\".",
853 filename
, entry
, sval
);
858 /****************************************************************************
859 Lookup optional string, returning allocated memory or NULL.
860 ****************************************************************************/
861 static char *lookup_string(struct section_file
*file
, const char *prefix
,
864 const char *sval
= secfile_lookup_str(file
, "%s.%s", prefix
, suffix
);
867 char copy
[strlen(sval
) + 1];
870 remove_leading_trailing_spaces(copy
);
871 if (strlen(copy
) > 0) {
872 return fc_strdup(copy
);
878 /****************************************************************************
879 Lookup optional string vector, returning allocated memory or NULL.
880 ****************************************************************************/
881 static struct strvec
*lookup_strvec(struct section_file
*file
,
882 const char *prefix
, const char *suffix
)
885 const char **vec
= secfile_lookup_str_vec(file
, &dim
,
886 "%s.%s", prefix
, suffix
);
889 struct strvec
*dest
= strvec_new();
891 strvec_store(dest
, vec
, dim
);
898 /**************************************************************************
899 Look up the resource section name and return its pointer.
900 **************************************************************************/
901 static struct extra_type
*lookup_resource(const char *filename
,
903 const char *jsection
)
905 struct extra_type
*pres
;
907 pres
= extra_type_by_rule_name(name
);
910 ruleset_error(LOG_ERROR
,
911 "\"%s\" [%s] has unknown \"%s\".",
920 /**************************************************************************
921 Look up the terrain by name and return its pointer.
922 filename is for error message.
923 **************************************************************************/
924 static bool lookup_terrain(struct section_file
*file
,
926 const char *filename
,
927 struct terrain
*pthis
,
928 struct terrain
**result
)
930 const int j
= terrain_index(pthis
);
931 const char *jsection
= &terrain_sections
[j
* MAX_SECTION_LABEL
];
932 const char *name
= secfile_lookup_str(file
, "%s.%s", jsection
, entry
);
933 struct terrain
*pterr
;
937 || (0 == strcmp(name
, "none"))
938 || (0 == strcmp(name
, "no"))) {
943 if (0 == strcmp(name
, "yes")) {
949 pterr
= terrain_by_rule_name(name
);
953 ruleset_error(LOG_ERROR
, "\"%s\" [%s] has unknown \"%s\".",
954 secfile_name(file
), jsection
, name
);
961 /**************************************************************************
962 Look up a value comparable to activity_count (road_time, etc).
963 item_name describes the thing which has the time property, if non-NULL,
964 for any error message.
965 Returns FALSE if not found in secfile, but TRUE even if validation failed.
966 Sets *ok to FALSE if validation failed, leaves it alone otherwise.
967 **************************************************************************/
968 static bool lookup_time(const struct section_file
*secfile
, int *turns
,
969 const char *sec_name
, const char *property_name
,
970 const char *filename
, const char *item_name
,
973 /* Assumes that PACKET_UNIT_INFO.activity_count in packets.def is UINT16 */
974 const int max_turns
= 65535 / ACTIVITY_FACTOR
;
976 if (!secfile_lookup_int(secfile
, turns
, "%s.%s", sec_name
, property_name
)) {
980 if (*turns
> max_turns
) {
981 ruleset_error(LOG_ERROR
,
982 "\"%s\": \"%s\": \"%s\" value %d too large (max %d)",
983 filename
, item_name
? item_name
: sec_name
,
984 property_name
, *turns
, max_turns
);
988 return TRUE
; /* we found _something */
991 /**************************************************************************
992 Load "name" and (optionally) "rule_name" into a struct name_translation.
993 **************************************************************************/
994 static bool ruleset_load_names(struct name_translation
*pname
,
996 struct section_file
*file
,
997 const char *sec_name
)
999 const char *name
= secfile_lookup_str(file
, "%s.name", sec_name
);
1000 const char *rule_name
= secfile_lookup_str(file
, "%s.rule_name", sec_name
);
1003 ruleset_error(LOG_ERROR
,
1004 "\"%s\" [%s]: no \"name\" specified.",
1005 secfile_name(file
), sec_name
);
1009 names_set(pname
, domain
, name
, rule_name
);
1014 /**************************************************************************
1015 Load trait values to array.
1016 **************************************************************************/
1017 static void ruleset_load_traits(struct trait_limits
*out
,
1018 struct section_file
*file
,
1019 const char *secname
, const char *field_prefix
)
1023 /* FIXME: Use specenum trait names without duplicating them here.
1024 * Just needs to take care of case. */
1025 const char *trait_names
[] = {
1032 for (tr
= trait_begin(); tr
!= trait_end() && trait_names
[tr
] != NULL
; tr
= trait_next(tr
)) {
1033 out
[tr
].min
= secfile_lookup_int_default(file
, -1, "%s.%s%s_min",
1037 out
[tr
].max
= secfile_lookup_int_default(file
, -1, "%s.%s%s_max",
1041 out
[tr
].fixed
= secfile_lookup_int_default(file
, -1, "%s.%s%s_default",
1047 fc_assert(tr
== trait_end()); /* number of trait_names correct */
1050 /**************************************************************************
1051 Load names from game.ruleset so other rulesets can refer to objects
1053 **************************************************************************/
1054 static bool load_game_names(struct section_file
*file
,
1055 struct rscompat_info
*compat
)
1057 struct section_list
*sec
;
1059 const char *filename
= secfile_name(file
);
1062 /* section: datafile */
1063 compat
->ver_game
= rscompat_check_capabilities(file
, filename
, compat
);
1064 if (compat
->ver_game
<= 0) {
1068 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
1069 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
1071 sec
= secfile_sections_by_name_prefix(file
, ACHIEVEMENT_SECTION_PREFIX
);
1072 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
1073 if (nval
> MAX_ACHIEVEMENT_TYPES
) {
1074 int num
= nval
; /* No "size_t" to printf */
1076 ruleset_error(LOG_ERROR
, "\"%s\": Too many achievement types (%d, max %d)",
1077 filename
, num
, MAX_ACHIEVEMENT_TYPES
);
1080 game
.control
.num_achievement_types
= nval
;
1084 achievements_iterate(pach
) {
1085 const char *sec_name
= section_name(section_list_get(sec
, achievement_index(pach
)));
1087 if (!ruleset_load_names(&pach
->name
, NULL
, file
, sec_name
)) {
1088 ruleset_error(LOG_ERROR
, "\"%s\": Cannot load achievement names",
1093 } achievements_iterate_end
;
1096 section_list_destroy(sec
);
1098 if (compat
->ver_game
>= 10) {
1100 sec
= secfile_sections_by_name_prefix(file
, GOODS_SECTION_PREFIX
);
1102 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
1103 if (nval
> MAX_GOODS_TYPES
) {
1104 int num
= nval
; /* No "size_t" to printf */
1106 ruleset_error(LOG_ERROR
,
1107 "\"%s\": Too many goods types (%d, max %d)",
1108 filename
, num
, MAX_GOODS_TYPES
);
1109 section_list_destroy(sec
);
1111 } else if (nval
< 1) {
1112 ruleset_error(LOG_ERROR
, "\"%s\": At least one goods type needed",
1114 section_list_destroy(sec
);
1117 game
.control
.num_goods_types
= nval
;
1121 goods_type_iterate(pgood
) {
1122 const char *sec_name
1123 = section_name(section_list_get(sec
, goods_index(pgood
)));
1125 if (!ruleset_load_names(&pgood
->name
, NULL
, file
, sec_name
)) {
1126 ruleset_error(LOG_ERROR
, "\"%s\": Cannot load goods names",
1131 } goods_type_iterate_end
;
1133 section_list_destroy(sec
);
1141 /**************************************************************************
1142 Load names of technologies so other rulesets can refer to techs with
1144 **************************************************************************/
1145 static bool load_tech_names(struct section_file
*file
,
1146 struct rscompat_info
*compat
)
1148 struct section_list
*sec
= NULL
;
1149 /* Number of techs in the ruleset (means without A_NONE). */
1152 const char *filename
= secfile_name(file
);
1156 compat
->ver_techs
= rscompat_check_capabilities(file
, filename
, compat
);
1157 if (compat
->ver_techs
<= 0) {
1161 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
1162 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
1164 /* User tech flag names */
1165 for (i
= 0; (flag
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.name", i
)) ;
1167 const char *helptxt
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.helptxt",
1169 if (tech_flag_id_by_name(flag
, fc_strcasecmp
) != tech_flag_id_invalid()) {
1170 ruleset_error(LOG_ERROR
, "\"%s\": Duplicate tech flag name '%s'",
1175 if (i
> MAX_NUM_USER_TECH_FLAGS
) {
1176 ruleset_error(LOG_ERROR
, "\"%s\": Too many user tech flags!",
1182 set_user_tech_flag_name(TECH_USER_1
+ i
, flag
, helptxt
);
1188 for (; i
< MAX_NUM_USER_TECH_FLAGS
; i
++) {
1189 set_user_tech_flag_name(TECH_USER_1
+ i
, NULL
, NULL
);
1193 sec
= secfile_sections_by_name_prefix(file
, TECH_CLASS_SECTION_PREFIX
);
1195 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
1196 if (nval
> MAX_NUM_TECH_CLASSES
) {
1197 int num
= nval
; /* No "size_t" to printf */
1199 ruleset_error(LOG_ERROR
,
1200 "\"%s\": Too many tech classes (%d, max %d)",
1201 filename
, num
, MAX_NUM_TECH_CLASSES
);
1202 section_list_destroy(sec
);
1205 game
.control
.num_tech_classes
= nval
;
1209 tech_class_iterate(ptclass
) {
1210 const char *sec_name
1211 = section_name(section_list_get(sec
, tech_class_index(ptclass
)));
1213 if (!ruleset_load_names(&ptclass
->name
, NULL
, file
, sec_name
)) {
1214 ruleset_error(LOG_ERROR
, "\"%s\": Cannot load tech class names",
1219 } tech_class_iterate_end
;
1225 sec
= secfile_sections_by_name_prefix(file
, ADVANCE_SECTION_PREFIX
);
1226 if (NULL
== sec
|| 0 == (num_techs
= section_list_size(sec
))) {
1227 ruleset_error(LOG_ERROR
, "\"%s\": No Advances?!?", filename
);
1230 log_verbose("%d advances (including possibly unused)", num_techs
);
1231 if (num_techs
+ A_FIRST
> A_LAST
) {
1232 ruleset_error(LOG_ERROR
, "\"%s\": Too many advances (%d, max %d)",
1233 filename
, num_techs
, A_LAST
- A_FIRST
);
1240 game
.control
.num_tech_types
= num_techs
+ A_FIRST
; /* includes A_NONE */
1243 advance_iterate(A_FIRST
, a
) {
1244 if (!ruleset_load_names(&a
->name
, NULL
, file
, section_name(section_list_get(sec
, i
)))) {
1249 } advance_iterate_end
;
1251 section_list_destroy(sec
);
1256 /**************************************************************************
1257 Load technologies related ruleset data
1258 **************************************************************************/
1259 static bool load_ruleset_techs(struct section_file
*file
,
1260 struct rscompat_info
*compat
)
1262 struct section_list
*sec
;
1266 struct advance
*a_none
= advance_by_number(A_NONE
);
1267 const char *filename
= secfile_name(file
);
1270 sec
= secfile_sections_by_name_prefix(file
, TECH_CLASS_SECTION_PREFIX
);
1273 tech_class_iterate(ptclass
) {
1274 const char *sec_name
= section_name(section_list_get(sec
, i
));
1276 ptclass
->cost_pct
= secfile_lookup_int_default(file
, 100, "%s.%s",
1277 sec_name
, "cost_pct");
1280 } tech_class_iterate_end
;
1282 sec
= secfile_sections_by_name_prefix(file
, ADVANCE_SECTION_PREFIX
);
1285 advance_iterate(A_FIRST
, a
) {
1286 const char *sec_name
= section_name(section_list_get(sec
, i
));
1289 struct requirement_vector
*research_reqs
;
1291 if (!lookup_tech(file
, &a
->require
[AR_ONE
], sec_name
, "req1",
1292 filename
, rule_name_get(&a
->name
))
1293 || !lookup_tech(file
, &a
->require
[AR_TWO
], sec_name
, "req2",
1294 filename
, rule_name_get(&a
->name
))
1295 || !lookup_tech(file
, &a
->require
[AR_ROOT
], sec_name
, "root_req",
1296 filename
, rule_name_get(&a
->name
))) {
1301 if ((A_NEVER
== a
->require
[AR_ONE
] && A_NEVER
!= a
->require
[AR_TWO
])
1302 || (A_NEVER
!= a
->require
[AR_ONE
] && A_NEVER
== a
->require
[AR_TWO
])) {
1303 ruleset_error(LOG_ERROR
, "\"%s\" [%s] \"%s\": \"Never\" with non-\"Never\".",
1304 filename
, sec_name
, rule_name_get(&a
->name
));
1308 if (a_none
== a
->require
[AR_ONE
] && a_none
!= a
->require
[AR_TWO
]) {
1309 ruleset_error(LOG_ERROR
, "\"%s\" [%s] \"%s\": should have \"None\" second.",
1310 filename
, sec_name
, rule_name_get(&a
->name
));
1315 if (game
.control
.num_tech_classes
== 0) {
1318 const char *classname
;
1320 classname
= lookup_string(file
, sec_name
, "class");
1321 if (classname
!= NULL
) {
1322 classname
= Q_(classname
);
1323 a
->tclass
= tech_class_by_rule_name(classname
);
1324 if (a
->tclass
== NULL
) {
1325 ruleset_error(LOG_ERROR
, "\"%s\" [%s] \"%s\": Uknown tech class \"%s\".",
1326 filename
, sec_name
, rule_name_get(&a
->name
), classname
);
1331 a
->tclass
= NULL
; /* Default */
1335 research_reqs
= lookup_req_list(file
, compat
, sec_name
, "research_reqs",
1336 rule_name_get(&a
->name
));
1337 if (research_reqs
== NULL
) {
1342 requirement_vector_copy(&a
->research_reqs
, research_reqs
);
1344 BV_CLR_ALL(a
->flags
);
1346 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", sec_name
);
1347 for (j
= 0; j
< nval
; j
++) {
1349 if (strcmp(sval
, "") == 0) {
1352 ival
= tech_flag_id_by_name(sval
, fc_strcasecmp
);
1353 if (!tech_flag_id_is_valid(ival
)) {
1354 ruleset_error(LOG_ERROR
, "\"%s\" [%s] \"%s\": bad flag name \"%s\".",
1355 filename
, sec_name
, rule_name_get(&a
->name
), sval
);
1359 BV_SET(a
->flags
, ival
);
1368 sz_strlcpy(a
->graphic_str
,
1369 secfile_lookup_str_default(file
, "-", "%s.graphic", sec_name
));
1370 sz_strlcpy(a
->graphic_alt
,
1371 secfile_lookup_str_default(file
, "-",
1372 "%s.graphic_alt", sec_name
));
1374 a
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
1375 a
->bonus_message
= lookup_string(file
, sec_name
, "bonus_message");
1376 a
->cost
= secfile_lookup_int_default(file
, -1, "%s.%s",
1381 } advance_iterate_end
;
1383 /* Propagate a root tech up into the tech tree. Thus if a technology
1384 * X has Y has a root tech, then any technology requiring X also has
1385 * Y as a root tech. */
1389 advance_iterate(A_FIRST
, a
) {
1390 if (valid_advance(a
)
1391 && A_NEVER
!= a
->require
[AR_ROOT
]) {
1392 bool out_of_order
= FALSE
;
1394 /* Now find any tech depending on this technology and update its
1396 advance_iterate(A_FIRST
, b
) {
1397 if (valid_advance(b
)
1398 && A_NEVER
== b
->require
[AR_ROOT
]
1399 && (a
== b
->require
[AR_ONE
] || a
== b
->require
[AR_TWO
])) {
1400 b
->require
[AR_ROOT
] = a
->require
[AR_ROOT
];
1402 out_of_order
= TRUE
;
1405 } advance_iterate_end
;
1408 /* HACK: If we just changed the root_tech of a lower-numbered
1409 * technology, we need to go back so that we can propagate the
1410 * root_tech up to that technology's parents... */
1414 } advance_iterate_end
;
1416 /* Now rename A_NEVER to A_NONE for consistency */
1417 advance_iterate(A_NONE
, a
) {
1418 if (A_NEVER
== a
->require
[AR_ROOT
]) {
1419 a
->require
[AR_ROOT
] = a_none
;
1421 } advance_iterate_end
;
1423 /* Some more consistency checking:
1424 Non-removed techs depending on removed techs is too
1425 broken to fix by default, so die.
1427 advance_iterate(A_FIRST
, a
) {
1428 if (valid_advance(a
)) {
1429 /* We check for recursive tech loops later,
1430 * in build_required_techs_helper. */
1431 if (!valid_advance(a
->require
[AR_ONE
])) {
1432 ruleset_error(LOG_ERROR
,
1433 "\"%s\" tech \"%s\": req1 leads to removed tech.",
1435 advance_rule_name(a
));
1439 if (!valid_advance(a
->require
[AR_TWO
])) {
1440 ruleset_error(LOG_ERROR
,
1441 "\"%s\" tech \"%s\": req2 leads to removed tech.",
1443 advance_rule_name(a
));
1448 } advance_iterate_end
;
1451 section_list_destroy(sec
);
1453 secfile_check_unused(file
);
1459 /**************************************************************************
1460 Load names of units so other rulesets can refer to units with
1462 **************************************************************************/
1463 static bool load_unit_names(struct section_file
*file
,
1464 struct rscompat_info
*compat
)
1466 struct section_list
*sec
= NULL
;
1469 const char *filename
= secfile_name(file
);
1473 compat
->ver_units
= rscompat_check_capabilities(file
, filename
, compat
);
1474 if (compat
->ver_units
<= 0) {
1478 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
1479 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
1481 /* User unit flag names */
1482 for (i
= 0; (flag
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.name", i
)) ;
1484 const char *helptxt
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.helptxt",
1487 if (unit_type_flag_id_by_name(rscompat_utype_flag_name_3_1(compat
, flag
),
1489 != unit_type_flag_id_invalid()) {
1490 ruleset_error(LOG_ERROR
, "\"%s\": Duplicate unit flag name '%s'",
1495 if (i
> MAX_NUM_USER_UNIT_FLAGS
) {
1496 ruleset_error(LOG_ERROR
, "\"%s\": Too many user unit type flags!",
1502 set_user_unit_type_flag_name(UTYF_USER_FLAG_1
+ i
, flag
, helptxt
);
1506 /* Blank the remaining unit type user flags. */
1507 for (; i
< MAX_NUM_USER_UNIT_FLAGS
; i
++) {
1508 set_user_unit_type_flag_name(UTYF_USER_FLAG_1
+ i
, NULL
, NULL
);
1513 /* User unit class flag names */
1515 (flag
= secfile_lookup_str_default(file
, NULL
,
1516 "control.class_flags%d.name",
1519 const char *helptxt
= secfile_lookup_str_default(file
, NULL
,
1520 "control.class_flags%d.helptxt", i
);
1522 if (unit_class_flag_id_by_name(flag
, fc_strcasecmp
)
1523 != unit_class_flag_id_invalid()) {
1524 ruleset_error(LOG_ERROR
, "\"%s\": Duplicate unit class flag name "
1530 if (i
> MAX_NUM_USER_UCLASS_FLAGS
) {
1531 ruleset_error(LOG_ERROR
, "\"%s\": Too many user unit class flags!",
1537 set_user_unit_class_flag_name(UCF_USER_FLAG_1
+ i
, flag
, helptxt
);
1542 /* Blank the remaining unit class user flags. */
1543 for (; i
< MAX_NUM_USER_UCLASS_FLAGS
; i
++) {
1544 set_user_unit_class_flag_name(UCF_USER_FLAG_1
+ i
, NULL
, NULL
);
1550 sec
= secfile_sections_by_name_prefix(file
, UNIT_CLASS_SECTION_PREFIX
);
1551 if (NULL
== sec
|| 0 == (nval
= section_list_size(sec
))) {
1552 ruleset_error(LOG_ERROR
, "\"%s\": No unit classes?!?", filename
);
1555 log_verbose("%d unit classes", nval
);
1556 if (nval
> UCL_LAST
) {
1557 ruleset_error(LOG_ERROR
, "\"%s\": Too many unit classes (%d, max %d)",
1558 filename
, nval
, UCL_LAST
);
1565 game
.control
.num_unit_classes
= nval
;
1567 unit_class_iterate(punitclass
) {
1568 const int pci
= uclass_index(punitclass
);
1570 if (!ruleset_load_names(&punitclass
->name
, NULL
, file
,
1571 section_name(section_list_get(sec
, pci
)))) {
1575 } unit_class_iterate_end
;
1577 section_list_destroy(sec
);
1582 sec
= secfile_sections_by_name_prefix(file
, UNIT_SECTION_PREFIX
);
1583 if (NULL
== sec
|| 0 == (nval
= section_list_size(sec
))) {
1584 ruleset_error(LOG_ERROR
, "\"%s\": No unit types?!?", filename
);
1587 log_verbose("%d unit types (including possibly unused)", nval
);
1588 if (nval
> U_LAST
) {
1589 ruleset_error(LOG_ERROR
, "\"%s\": Too many unit types (%d, max %d)",
1590 filename
, nval
, U_LAST
);
1597 game
.control
.num_unit_types
= nval
;
1599 unit_type_iterate(punittype
) {
1600 const int utypei
= utype_index(punittype
);
1601 if (!ruleset_load_names(&punittype
->name
, NULL
, file
,
1602 section_name(section_list_get(sec
, utypei
)))) {
1606 } unit_type_iterate_end
;
1608 section_list_destroy(sec
);
1613 /**************************************************************************
1614 Load veteran levels.
1615 **************************************************************************/
1616 static bool load_ruleset_veteran(struct section_file
*file
,
1618 struct veteran_system
**vsystem
, char *err
,
1621 const char **vlist_name
;
1622 int *vlist_power
, *vlist_raise
, *vlist_wraise
, *vlist_move
;
1623 size_t count_name
, count_power
, count_raise
, count_wraise
, count_move
;
1627 /* The pointer should be uninitialised. */
1628 if (*vsystem
!= NULL
) {
1629 fc_snprintf(err
, err_len
, "Veteran system is defined?!");
1634 vlist_name
= secfile_lookup_str_vec(file
, &count_name
,
1635 "%s.veteran_names", path
);
1636 vlist_power
= secfile_lookup_int_vec(file
, &count_power
,
1637 "%s.veteran_power_fact", path
);
1638 vlist_raise
= secfile_lookup_int_vec(file
, &count_raise
,
1639 "%s.veteran_raise_chance", path
);
1640 vlist_wraise
= secfile_lookup_int_vec(file
, &count_wraise
,
1641 "%s.veteran_work_raise_chance",
1643 vlist_move
= secfile_lookup_int_vec(file
, &count_move
,
1644 "%s.veteran_move_bonus", path
);
1646 if (count_name
> MAX_VET_LEVELS
) {
1648 fc_snprintf(err
, err_len
, "\"%s\": Too many veteran levels (section "
1649 "'%s': %lu, max %d)", secfile_name(file
), path
,
1650 (long unsigned)count_name
, MAX_VET_LEVELS
);
1651 } else if (count_name
!= count_power
1652 || count_name
!= count_raise
1653 || count_name
!= count_wraise
1654 || count_name
!= count_move
) {
1656 fc_snprintf(err
, err_len
, "\"%s\": Different lengths for the veteran "
1657 "settings in section '%s'", secfile_name(file
),
1659 } else if (count_name
== 0) {
1660 /* Nothing defined. */
1663 /* Generate the veteran system. */
1664 *vsystem
= veteran_system_new((int)count_name
);
1666 #define rs_sanity_veteran(_path, _entry, _i, _condition, _action) \
1668 log_error("Invalid veteran definition '%s.%s[%d]'!", \
1669 _path, _entry, _i); \
1670 log_debug("Failed check: '%s'. Update value: '%s'.", \
1671 #_condition, #_action); \
1674 for (i
= 0; i
< count_name
; i
++) {
1675 /* Some sanity checks. */
1676 rs_sanity_veteran(path
, "veteran_power_fact", i
,
1677 (vlist_power
[i
] < 0), vlist_power
[i
] = 0);
1678 rs_sanity_veteran(path
, "veteran_raise_chance", i
,
1679 (vlist_raise
[i
] < 0), vlist_raise
[i
] = 0);
1680 rs_sanity_veteran(path
, "veteran_work_raise_chance", i
,
1681 (vlist_wraise
[i
] < 0), vlist_wraise
[i
] = 0);
1682 rs_sanity_veteran(path
, "veteran_move_bonus", i
,
1683 (vlist_move
[i
] < 0), vlist_move
[i
] = 0);
1686 rs_sanity_veteran(path
, "veteran_power_fact", i
,
1687 (vlist_power
[i
] != 100), vlist_power
[i
] = 100);
1688 } else if (i
== count_name
- 1) {
1690 rs_sanity_veteran(path
, "veteran_power_fact", i
,
1691 (vlist_power
[i
] < vlist_power
[i
- 1]),
1692 vlist_power
[i
] = vlist_power
[i
- 1]);
1693 rs_sanity_veteran(path
, "veteran_raise_chance", i
,
1694 (vlist_raise
[i
] != 0), vlist_raise
[i
] = 0);
1695 rs_sanity_veteran(path
, "veteran_work_raise_chance", i
,
1696 (vlist_wraise
[i
] != 0), vlist_wraise
[i
] = 0);
1698 /* All elements inbetween. */
1699 rs_sanity_veteran(path
, "veteran_power_fact", i
,
1700 (vlist_power
[i
] < vlist_power
[i
- 1]),
1701 vlist_power
[i
] = vlist_power
[i
- 1]);
1702 rs_sanity_veteran(path
, "veteran_raise_chance", i
,
1703 (vlist_raise
[i
] > 100), vlist_raise
[i
] = 100);
1704 rs_sanity_veteran(path
, "veteran_work_raise_chance", i
,
1705 (vlist_wraise
[i
] > 100), vlist_wraise
[i
] = 100);
1708 veteran_system_definition(*vsystem
, i
, vlist_name
[i
], vlist_power
[i
],
1709 vlist_move
[i
], vlist_raise
[i
],
1712 #undef rs_sanity_veteran
1734 /**************************************************************************
1735 Load units related ruleset data.
1736 **************************************************************************/
1737 static bool load_ruleset_units(struct section_file
*file
,
1738 struct rscompat_info
*compat
)
1742 struct section_list
*sec
, *csec
;
1743 const char *sval
, **slist
;
1744 const char *filename
= secfile_name(file
);
1745 char msg
[MAX_LEN_MSG
];
1748 if (!load_ruleset_veteran(file
, "veteran_system", &game
.veteran
, msg
,
1749 sizeof(msg
)) || game
.veteran
== NULL
) {
1750 ruleset_error(LOG_ERROR
, "Error loading the default veteran system: %s",
1755 sec
= secfile_sections_by_name_prefix(file
, UNIT_SECTION_PREFIX
);
1756 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
1758 csec
= secfile_sections_by_name_prefix(file
, UNIT_CLASS_SECTION_PREFIX
);
1759 nval
= (NULL
!= csec
? section_list_size(csec
) : 0);
1762 unit_class_iterate(uc
) {
1763 int i
= uclass_index(uc
);
1764 const char *hut_str
;
1765 const char *sec_name
= section_name(section_list_get(csec
, i
));
1767 if (secfile_lookup_int(file
, &uc
->min_speed
, "%s.min_speed", sec_name
)) {
1768 uc
->min_speed
*= SINGLE_MOVE
;
1770 ruleset_error(LOG_ERROR
, "%s", secfile_error());
1774 if (!secfile_lookup_int(file
, &uc
->hp_loss_pct
,
1775 "%s.hp_loss_pct", sec_name
)) {
1776 ruleset_error(LOG_ERROR
, "%s", secfile_error());
1781 uc
->non_native_def_pct
= secfile_lookup_int_default(file
, 100,
1782 "%s.non_native_def_pct",
1785 hut_str
= secfile_lookup_str_default(file
, "Normal", "%s.hut_behavior", sec_name
);
1786 if (fc_strcasecmp(hut_str
, "Normal") == 0) {
1787 uc
->hut_behavior
= HUT_NORMAL
;
1788 } else if (fc_strcasecmp(hut_str
, "Nothing") == 0) {
1789 uc
->hut_behavior
= HUT_NOTHING
;
1790 } else if (fc_strcasecmp(hut_str
, "Frighten") == 0) {
1791 uc
->hut_behavior
= HUT_FRIGHTEN
;
1793 ruleset_error(LOG_ERROR
,
1794 "\"%s\" unit_class \"%s\":"
1795 " Illegal hut behavior \"%s\".",
1797 uclass_rule_name(uc
),
1803 BV_CLR_ALL(uc
->flags
);
1804 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", sec_name
);
1805 for (j
= 0; j
< nval
; j
++) {
1807 if (strcmp(sval
, "") == 0) {
1810 ival
= unit_class_flag_id_by_name(sval
, fc_strcasecmp
);
1811 if (!unit_class_flag_id_is_valid(ival
)) {
1813 ival
= unit_type_flag_id_by_name(rscompat_utype_flag_name_3_1(compat
, sval
),
1815 if (unit_type_flag_id_is_valid(ival
)) {
1816 ruleset_error(LOG_ERROR
,
1817 "\"%s\" unit_class \"%s\": unit_type flag \"%s\"!",
1818 filename
, uclass_rule_name(uc
), sval
);
1820 ruleset_error(LOG_ERROR
,
1821 "\"%s\" unit_class \"%s\": bad flag name \"%s\".",
1822 filename
, uclass_rule_name(uc
), sval
);
1826 BV_SET(uc
->flags
, ival
);
1831 uc
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
1836 } unit_class_iterate_end
;
1840 /* Tech and Gov requirements; per unit veteran system */
1841 unit_type_iterate(u
) {
1842 const int i
= utype_index(u
);
1843 const struct section
*psection
= section_list_get(sec
, i
);
1844 const char *sec_name
= section_name(psection
);
1846 if (!lookup_tech(file
, &u
->require_advance
, sec_name
,
1847 "tech_req", filename
,
1848 rule_name_get(&u
->name
))) {
1852 if (NULL
!= section_entry_by_name(psection
, "gov_req")) {
1853 char tmp
[200] = "\0";
1854 fc_strlcat(tmp
, section_name(psection
), sizeof(tmp
));
1855 fc_strlcat(tmp
, ".gov_req", sizeof(tmp
));
1856 u
->need_government
= lookup_government(file
, tmp
, filename
, NULL
);
1857 if (u
->need_government
== NULL
) {
1862 u
->need_government
= NULL
; /* no requirement */
1865 if (!load_ruleset_veteran(file
, sec_name
, &u
->veteran
,
1866 msg
, sizeof(msg
))) {
1867 ruleset_error(LOG_ERROR
, "Error loading the veteran system: %s",
1873 if (!lookup_unit_type(file
, sec_name
, "obsolete_by",
1874 &u
->obsoleted_by
, filename
,
1875 rule_name_get(&u
->name
))
1876 || !lookup_unit_type(file
, sec_name
, "convert_to",
1877 &u
->converted_to
, filename
,
1878 rule_name_get(&u
->name
))) {
1882 u
->convert_time
= 1; /* default */
1883 lookup_time(file
, &u
->convert_time
, sec_name
, "convert_time",
1884 filename
, rule_name_get(&u
->name
), &ok
);
1885 } unit_type_iterate_end
;
1890 unit_type_iterate(u
) {
1891 const int i
= utype_index(u
);
1892 struct unit_class
*pclass
;
1893 const char *sec_name
= section_name(section_list_get(sec
, i
));
1896 if (!lookup_building(file
, sec_name
, "impr_req",
1897 &u
->need_improvement
, filename
,
1898 rule_name_get(&u
->name
))) {
1903 sval
= secfile_lookup_str(file
, "%s.class", sec_name
);
1904 pclass
= unit_class_by_rule_name(sval
);
1906 ruleset_error(LOG_ERROR
,
1907 "\"%s\" unit_type \"%s\":"
1908 " bad class \"%s\".",
1917 sz_strlcpy(u
->sound_move
,
1918 secfile_lookup_str_default(file
, "-", "%s.sound_move",
1920 sz_strlcpy(u
->sound_move_alt
,
1921 secfile_lookup_str_default(file
, "-", "%s.sound_move_alt",
1923 sz_strlcpy(u
->sound_fight
,
1924 secfile_lookup_str_default(file
, "-", "%s.sound_fight",
1926 sz_strlcpy(u
->sound_fight_alt
,
1927 secfile_lookup_str_default(file
, "-", "%s.sound_fight_alt",
1930 if ((string
= secfile_lookup_str(file
, "%s.graphic", sec_name
))) {
1931 sz_strlcpy(u
->graphic_str
, string
);
1933 ruleset_error(LOG_ERROR
, "%s", secfile_error());
1937 sz_strlcpy(u
->graphic_alt
,
1938 secfile_lookup_str_default(file
, "-", "%s.graphic_alt",
1941 if (!secfile_lookup_int(file
, &u
->build_cost
,
1942 "%s.build_cost", sec_name
)
1943 || !secfile_lookup_int(file
, &u
->pop_cost
,
1944 "%s.pop_cost", sec_name
)
1945 || !secfile_lookup_int(file
, &u
->attack_strength
,
1946 "%s.attack", sec_name
)
1947 || !secfile_lookup_int(file
, &u
->defense_strength
,
1948 "%s.defense", sec_name
)
1949 || !secfile_lookup_int(file
, &u
->move_rate
,
1950 "%s.move_rate", sec_name
)
1951 || !secfile_lookup_int(file
, &u
->vision_radius_sq
,
1952 "%s.vision_radius_sq", sec_name
)
1953 || !secfile_lookup_int(file
, &u
->transport_capacity
,
1954 "%s.transport_cap", sec_name
)
1955 || !secfile_lookup_int(file
, &u
->hp
,
1956 "%s.hitpoints", sec_name
)
1957 || !secfile_lookup_int(file
, &u
->firepower
,
1958 "%s.firepower", sec_name
)
1959 || !secfile_lookup_int(file
, &u
->fuel
,
1960 "%s.fuel", sec_name
)
1961 || !secfile_lookup_int(file
, &u
->happy_cost
,
1962 "%s.uk_happy", sec_name
)) {
1963 ruleset_error(LOG_ERROR
, "%s", secfile_error());
1967 u
->move_rate
*= SINGLE_MOVE
;
1969 if (u
->firepower
<= 0) {
1970 ruleset_error(LOG_ERROR
,
1971 "\"%s\" unit_type \"%s\":"
1973 " but must be at least 1. "
1974 " If you want no attack ability,"
1975 " set the unit's attack strength to 0.",
1983 lookup_cbonus_list(compat
, u
->bonuses
, file
, sec_name
, "bonuses");
1985 output_type_iterate(o
) {
1986 u
->upkeep
[o
] = secfile_lookup_int_default(file
, 0, "%s.uk_%s",
1988 get_output_identifier(o
));
1989 } output_type_iterate_end
;
1991 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.cargo", sec_name
);
1992 BV_CLR_ALL(u
->cargo
);
1993 for (j
= 0; j
< nval
; j
++) {
1994 struct unit_class
*uclass
= unit_class_by_rule_name(slist
[j
]);
1997 ruleset_error(LOG_ERROR
,
1998 "\"%s\" unit_type \"%s\":"
1999 "has unknown unit class %s as cargo.",
2007 BV_SET(u
->cargo
, uclass_index(uclass
));
2015 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.targets", sec_name
);
2016 BV_CLR_ALL(u
->targets
);
2017 for (j
= 0; j
< nval
; j
++) {
2018 struct unit_class
*uclass
= unit_class_by_rule_name(slist
[j
]);
2021 ruleset_error(LOG_ERROR
,
2022 "\"%s\" unit_type \"%s\":"
2023 "has unknown unit class %s as target.",
2031 BV_SET(u
->targets
, uclass_index(uclass
));
2039 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.embarks", sec_name
);
2040 BV_CLR_ALL(u
->embarks
);
2041 for (j
= 0; j
< nval
; j
++) {
2042 struct unit_class
*uclass
= unit_class_by_rule_name(slist
[j
]);
2045 ruleset_error(LOG_ERROR
,
2046 "\"%s\" unit_type \"%s\":"
2047 "has unknown unit class %s as embarkable.",
2055 BV_SET(u
->embarks
, uclass_index(uclass
));
2063 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.disembarks", sec_name
);
2064 BV_CLR_ALL(u
->disembarks
);
2065 for (j
= 0; j
< nval
; j
++) {
2066 struct unit_class
*uclass
= unit_class_by_rule_name(slist
[j
]);
2069 ruleset_error(LOG_ERROR
,
2070 "\"%s\" unit_type \"%s\":"
2071 "has unknown unit class %s as disembarkable.",
2079 BV_SET(u
->disembarks
, uclass_index(uclass
));
2087 /* Set also all classes that are never unreachable as targets,
2088 * embarks, and disembarks. */
2089 unit_class_iterate(preachable
) {
2090 if (!uclass_has_flag(preachable
, UCF_UNREACHABLE
)) {
2091 BV_SET(u
->targets
, uclass_index(preachable
));
2092 BV_SET(u
->embarks
, uclass_index(preachable
));
2093 BV_SET(u
->disembarks
, uclass_index(preachable
));
2095 } unit_class_iterate_end
;
2097 u
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
2099 u
->paratroopers_range
= secfile_lookup_int_default(file
,
2100 0, "%s.paratroopers_range", sec_name
);
2101 u
->paratroopers_mr_req
= SINGLE_MOVE
* secfile_lookup_int_default(file
,
2102 0, "%s.paratroopers_mr_req", sec_name
);
2103 u
->paratroopers_mr_sub
= SINGLE_MOVE
* secfile_lookup_int_default(file
,
2104 0, "%s.paratroopers_mr_sub", sec_name
);
2105 u
->bombard_rate
= secfile_lookup_int_default(file
, 0,
2106 "%s.bombard_rate", sec_name
);
2107 u
->city_slots
= secfile_lookup_int_default(file
, 0,
2108 "%s.city_slots", sec_name
);
2109 u
->city_size
= secfile_lookup_int_default(file
, 1,
2110 "%s.city_size", sec_name
);
2111 } unit_type_iterate_end
;
2116 unit_type_iterate(u
) {
2117 const int i
= utype_index(u
);
2119 BV_CLR_ALL(u
->flags
);
2120 fc_assert(!utype_has_flag(u
, UTYF_LAST_USER_FLAG
- 1));
2122 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags",
2123 section_name(section_list_get(sec
, i
)));
2124 for (j
= 0; j
< nval
; j
++) {
2126 if (0 == strcmp(sval
, "")) {
2129 ival
= unit_type_flag_id_by_name(rscompat_utype_flag_name_3_1(compat
, sval
),
2131 if (!unit_type_flag_id_is_valid(ival
)) {
2133 ival
= unit_class_flag_id_by_name(sval
, fc_strcasecmp
);
2134 if (unit_class_flag_id_is_valid(ival
)) {
2135 ruleset_error(LOG_ERROR
, "\"%s\" unit_type \"%s\": unit_class flag!",
2136 filename
, utype_rule_name(u
));
2138 ruleset_error(LOG_ERROR
,
2139 "\"%s\" unit_type \"%s\": bad flag name \"%s\".",
2140 filename
, utype_rule_name(u
), sval
);
2144 BV_SET(u
->flags
, ival
);
2146 fc_assert(utype_has_flag(u
, ival
));
2153 } unit_type_iterate_end
;
2158 unit_type_iterate(u
) {
2159 const int i
= utype_index(u
);
2161 BV_CLR_ALL(u
->roles
);
2163 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.roles",
2164 section_name(section_list_get(sec
, i
)));
2165 for (j
= 0; j
< nval
; j
++) {
2167 if (strcmp(sval
, "") == 0) {
2170 ival
= unit_role_id_by_name(sval
, fc_strcasecmp
);
2171 if (!unit_role_id_is_valid(ival
)) {
2172 ruleset_error(LOG_ERROR
, "\"%s\" unit_type \"%s\": bad role name \"%s\".",
2173 filename
, utype_rule_name(u
), sval
);
2177 BV_SET(u
->roles
, ival
- L_FIRST
);
2179 fc_assert(utype_has_role(u
, ival
));
2182 } unit_type_iterate_end
;
2186 /* Some more consistency checking: */
2187 unit_type_iterate(u
) {
2188 if (!valid_advance(u
->require_advance
)) {
2189 ruleset_error(LOG_ERROR
, "\"%s\" unit_type \"%s\": depends on removed tech \"%s\".",
2190 filename
, utype_rule_name(u
),
2191 advance_rule_name(u
->require_advance
));
2192 u
->require_advance
= A_NEVER
;
2197 if (utype_has_flag(u
, UTYF_SETTLERS
)
2198 && u
->city_size
<= 0) {
2199 ruleset_error(LOG_ERROR
, "\"%s\": Unit %s would build size %d cities",
2200 filename
, utype_rule_name(u
), u
->city_size
);
2205 } unit_type_iterate_end
;
2208 section_list_destroy(csec
);
2209 section_list_destroy(sec
);
2212 secfile_check_unused(file
);
2218 /**************************************************************************
2219 Load names of buildings so other rulesets can refer to buildings with
2221 **************************************************************************/
2222 static bool load_building_names(struct section_file
*file
,
2223 struct rscompat_info
*compat
)
2225 struct section_list
*sec
;
2227 const char *filename
= secfile_name(file
);
2230 compat
->ver_buildings
= rscompat_check_capabilities(file
, filename
,
2232 if (compat
->ver_buildings
<= 0) {
2236 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
2237 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
2240 sec
= secfile_sections_by_name_prefix(file
, BUILDING_SECTION_PREFIX
);
2241 if (NULL
== sec
|| 0 == (nval
= section_list_size(sec
))) {
2242 ruleset_error(LOG_ERROR
, "\"%s\": No improvements?!?", filename
);
2245 log_verbose("%d improvement types (including possibly unused)", nval
);
2246 if (nval
> B_LAST
) {
2247 ruleset_error(LOG_ERROR
, "\"%s\": Too many improvements (%d, max %d)",
2248 filename
, nval
, B_LAST
);
2254 game
.control
.num_impr_types
= nval
;
2256 for (i
= 0; i
< nval
; i
++) {
2257 struct impr_type
*b
= improvement_by_number(i
);
2259 if (!ruleset_load_names(&b
->name
, NULL
, file
, section_name(section_list_get(sec
, i
)))) {
2266 section_list_destroy(sec
);
2271 /**************************************************************************
2272 Load buildings related ruleset data
2273 **************************************************************************/
2274 static bool load_ruleset_buildings(struct section_file
*file
,
2275 struct rscompat_info
*compat
)
2277 struct section_list
*sec
;
2280 const char *filename
= secfile_name(file
);
2283 sec
= secfile_sections_by_name_prefix(file
, BUILDING_SECTION_PREFIX
);
2284 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
2286 for (i
= 0; i
< nval
&& ok
; i
++) {
2287 struct impr_type
*b
= improvement_by_number(i
);
2288 const char *sec_name
= section_name(section_list_get(sec
, i
));
2289 struct requirement_vector
*reqs
=
2290 lookup_req_list(file
, compat
, sec_name
, "reqs",
2291 improvement_rule_name(b
));
2297 const char *sval
, **slist
;
2301 item
= secfile_lookup_str(file
, "%s.genus", sec_name
);
2302 b
->genus
= impr_genus_id_by_name(item
, fc_strcasecmp
);
2303 if (!impr_genus_id_is_valid(b
->genus
)) {
2304 ruleset_error(LOG_ERROR
, "\"%s\" improvement \"%s\": couldn't match "
2305 "genus \"%s\".", filename
,
2306 improvement_rule_name(b
), item
);
2311 slist
= secfile_lookup_str_vec(file
, &nflags
, "%s.flags", sec_name
);
2312 BV_CLR_ALL(b
->flags
);
2314 for (j
= 0; j
< nflags
; j
++) {
2316 if (strcmp(sval
,"") == 0) {
2319 ival
= impr_flag_id_by_name(sval
, fc_strcasecmp
);
2320 if (!impr_flag_id_is_valid(ival
)) {
2321 ruleset_error(LOG_ERROR
,
2322 "\"%s\" improvement \"%s\": bad flag name \"%s\".",
2323 filename
, improvement_rule_name(b
), sval
);
2327 BV_SET(b
->flags
, ival
);
2336 requirement_vector_copy(&b
->reqs
, reqs
);
2339 struct requirement_vector
*obs_reqs
=
2340 lookup_req_list(file
, compat
, sec_name
, "obsolete_by",
2341 improvement_rule_name(b
));
2343 if (obs_reqs
== NULL
) {
2347 requirement_vector_copy(&b
->obsolete_by
, obs_reqs
);
2351 if (!secfile_lookup_int(file
, &b
->build_cost
,
2352 "%s.build_cost", sec_name
)
2353 || !secfile_lookup_int(file
, &b
->upkeep
,
2354 "%s.upkeep", sec_name
)
2355 || !secfile_lookup_int(file
, &b
->sabotage
,
2356 "%s.sabotage", sec_name
)) {
2357 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2362 sz_strlcpy(b
->graphic_str
,
2363 secfile_lookup_str_default(file
, "-",
2364 "%s.graphic", sec_name
));
2365 sz_strlcpy(b
->graphic_alt
,
2366 secfile_lookup_str_default(file
, "-",
2367 "%s.graphic_alt", sec_name
));
2369 sz_strlcpy(b
->soundtag
,
2370 secfile_lookup_str_default(file
, "-",
2371 "%s.sound", sec_name
));
2372 sz_strlcpy(b
->soundtag_alt
,
2373 secfile_lookup_str_default(file
, "-",
2374 "%s.sound_alt", sec_name
));
2375 b
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
2379 section_list_destroy(sec
);
2381 secfile_check_unused(file
);
2387 /**************************************************************************
2388 Load names of terrain types so other rulesets can refer to terrains with
2390 **************************************************************************/
2391 static bool load_terrain_names(struct section_file
*file
,
2392 struct rscompat_info
*compat
)
2395 struct section_list
*sec
= NULL
;
2398 const char *filename
= secfile_name(file
);
2401 compat
->ver_terrain
= rscompat_check_capabilities(file
, filename
,
2403 if (compat
->ver_terrain
<= 0) {
2407 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
2408 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
2410 /* User terrain flag names */
2411 for (i
= 0; (flag
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.name", i
)) ;
2413 const char *helptxt
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.helptxt",
2416 if (terrain_flag_id_by_name(flag
, fc_strcasecmp
)
2417 != terrain_flag_id_invalid()) {
2418 ruleset_error(LOG_ERROR
, "\"%s\": Duplicate terrain flag name '%s'",
2423 if (i
> MAX_NUM_USER_TER_FLAGS
) {
2424 ruleset_error(LOG_ERROR
, "\"%s\": Too many user terrain flags!",
2430 set_user_terrain_flag_name(TER_USER_1
+ i
, flag
, helptxt
);
2434 /* Blank the remaining terrain user flag slots. */
2435 for (; i
< MAX_NUM_USER_TER_FLAGS
; i
++) {
2436 set_user_terrain_flag_name(TER_USER_1
+ i
, NULL
, NULL
);
2440 /* User extra flag names */
2442 (flag
= secfile_lookup_str_default(file
, NULL
,
2443 "control.extra_flags%d.name",
2446 const char *helptxt
= secfile_lookup_str_default(file
, NULL
,
2447 "control.extra_flags%d.helptxt", i
);
2449 if (extra_flag_id_by_name(flag
, fc_strcasecmp
)
2450 != extra_flag_id_invalid()) {
2451 ruleset_error(LOG_ERROR
, "\"%s\": Duplicate extra flag name '%s'",
2456 if (i
> MAX_NUM_USER_EXTRA_FLAGS
) {
2457 ruleset_error(LOG_ERROR
, "\"%s\": Too many user extra flags!",
2463 set_user_extra_flag_name(EF_USER_FLAG_1
+ i
, flag
, helptxt
);
2467 /* Blank the remaining extra user flag slots. */
2468 for (; i
< MAX_NUM_USER_EXTRA_FLAGS
; i
++) {
2469 set_user_extra_flag_name(EF_USER_FLAG_1
+ i
, NULL
, NULL
);
2474 sec
= secfile_sections_by_name_prefix(file
, TERRAIN_SECTION_PREFIX
);
2475 if (NULL
== sec
|| 0 == (nval
= section_list_size(sec
))) {
2476 ruleset_error(LOG_ERROR
, "\"%s\": ruleset doesn't have any terrains.",
2480 if (nval
> MAX_NUM_TERRAINS
) {
2481 ruleset_error(LOG_ERROR
, "\"%s\": Too many terrains (%d, max %d)",
2482 filename
, nval
, MAX_NUM_TERRAINS
);
2489 game
.control
.terrain_count
= nval
;
2491 /* avoid re-reading files */
2492 if (terrain_sections
) {
2493 free(terrain_sections
);
2495 terrain_sections
= fc_calloc(nval
, MAX_SECTION_LABEL
);
2497 terrain_type_iterate(pterrain
) {
2498 const int terri
= terrain_index(pterrain
);
2499 const char *sec_name
= section_name(section_list_get(sec
, terri
));
2501 if (!ruleset_load_names(&pterrain
->name
, NULL
, file
, sec_name
)) {
2506 if (0 == strcmp(rule_name_get(&pterrain
->name
), "unused")) {
2507 name_set(&pterrain
->name
, NULL
, "");
2510 section_strlcpy(&terrain_sections
[terri
* MAX_SECTION_LABEL
], sec_name
);
2511 } terrain_type_iterate_end
;
2514 section_list_destroy(sec
);
2520 sec
= secfile_sections_by_name_prefix(file
, EXTRA_SECTION_PREFIX
);
2521 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
2522 if (nval
> MAX_EXTRA_TYPES
) {
2523 ruleset_error(LOG_ERROR
, "\"%s\": Too many extra types (%d, max %d)",
2524 filename
, nval
, MAX_EXTRA_TYPES
);
2532 game
.control
.num_extra_types
= nval
;
2534 if (extra_sections
) {
2535 free(extra_sections
);
2537 extra_sections
= fc_calloc(nval
, MAX_SECTION_LABEL
);
2540 for (idx
= 0; idx
< nval
; idx
++) {
2541 const char *sec_name
= section_name(section_list_get(sec
, idx
));
2542 struct extra_type
*pextra
= extra_by_number(idx
);
2544 if (!ruleset_load_names(&pextra
->name
, NULL
, file
, sec_name
)) {
2548 section_strlcpy(&extra_sections
[idx
* MAX_SECTION_LABEL
], sec_name
);
2553 section_list_destroy(sec
);
2559 sec
= secfile_sections_by_name_prefix(file
, BASE_SECTION_PREFIX
);
2560 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
2561 if (nval
> MAX_BASE_TYPES
) {
2562 ruleset_error(LOG_ERROR
, "\"%s\": Too many base types (%d, max %d)",
2563 filename
, nval
, MAX_BASE_TYPES
);
2567 game
.control
.num_base_types
= nval
;
2573 if (base_sections
) {
2574 free(base_sections
);
2576 base_sections
= fc_calloc(nval
, MAX_SECTION_LABEL
);
2578 /* Cannot use base_type_iterate() before bases are added to
2579 * EC_BASE caused_by list. Have to get them by extra_type_by_rule_name() */
2580 for (idx
= 0; idx
< nval
; idx
++) {
2581 const char *sec_name
= section_name(section_list_get(sec
, idx
));
2582 const char *base_name
= secfile_lookup_str(file
, "%s.extra", sec_name
);
2584 if (base_name
!= NULL
) {
2585 struct extra_type
*pextra
= extra_type_by_rule_name(base_name
);
2587 if (pextra
!= NULL
) {
2588 base_type_init(pextra
, idx
);
2589 section_strlcpy(&base_sections
[idx
* MAX_SECTION_LABEL
], sec_name
);
2591 ruleset_error(LOG_ERROR
,
2592 "No extra definition matching base definition \"%s\"",
2597 ruleset_error(LOG_ERROR
,
2598 "Base section \"%s\" does not associate base with any extra",
2605 section_list_destroy(sec
);
2611 sec
= secfile_sections_by_name_prefix(file
, ROAD_SECTION_PREFIX
);
2612 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
2613 if (nval
> MAX_ROAD_TYPES
) {
2614 ruleset_error(LOG_ERROR
, "\"%s\": Too many road types (%d, max %d)",
2615 filename
, nval
, MAX_ROAD_TYPES
);
2619 game
.control
.num_road_types
= nval
;
2625 if (road_sections
) {
2626 free(road_sections
);
2628 road_sections
= fc_calloc(nval
, MAX_SECTION_LABEL
);
2630 /* Cannot use extra_type_by_cause_iterate(EC_ROAD) before roads are added to
2631 * EC_ROAD caused_by list. Have to get them by extra_type_by_rule_name() */
2632 for (idx
= 0; idx
< nval
; idx
++) {
2633 const char *sec_name
= section_name(section_list_get(sec
, idx
));
2634 const char *road_name
= secfile_lookup_str(file
, "%s.extra", sec_name
);
2636 if (road_name
!= NULL
) {
2637 struct extra_type
*pextra
= extra_type_by_rule_name(road_name
);
2639 if (pextra
!= NULL
) {
2640 road_type_init(pextra
, idx
);
2641 section_strlcpy(&road_sections
[idx
* MAX_SECTION_LABEL
], sec_name
);
2643 ruleset_error(LOG_ERROR
,
2644 "No extra definition matching road definition \"%s\"",
2649 ruleset_error(LOG_ERROR
,
2650 "Road section \"%s\" does not associate road with any extra",
2657 section_list_destroy(sec
);
2660 /* resource names */
2663 sec
= secfile_sections_by_name_prefix(file
, RESOURCE_SECTION_PREFIX
);
2664 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
2665 if (nval
> MAX_RESOURCE_TYPES
) {
2666 ruleset_error(LOG_ERROR
, "\"%s\": Too many resource types (%d, max %d)",
2667 filename
, nval
, MAX_RESOURCE_TYPES
);
2671 game
.control
.num_resource_types
= nval
;
2677 if (resource_sections
) {
2678 free(resource_sections
);
2680 resource_sections
= fc_calloc(nval
, MAX_SECTION_LABEL
);
2682 /* Cannot use resource_type_iterate() before resource are added to
2683 * EC_RESOURCE caused_by list. Have to get them by extra_type_by_rule_name() */
2684 for (idx
= 0; idx
< nval
; idx
++) {
2685 const char *sec_name
= section_name(section_list_get(sec
, idx
));
2686 const char *resource_name
;
2687 struct extra_type
*pextra
= NULL
;
2689 resource_name
= secfile_lookup_str_default(file
, NULL
, "%s.extra", sec_name
);
2691 if (resource_name
!= NULL
) {
2692 pextra
= extra_type_by_rule_name(resource_name
);
2694 if (pextra
!= NULL
) {
2695 resource_type_init(pextra
);
2696 section_strlcpy(&resource_sections
[idx
* MAX_SECTION_LABEL
], sec_name
);
2698 ruleset_error(LOG_ERROR
,
2699 "No extra definition matching resource definition \"%s\"",
2704 ruleset_error(LOG_ERROR
,
2705 "Resource section %s does not list extra this resource belongs to.",
2712 section_list_destroy(sec
);
2717 /**************************************************************************
2718 Load terrain types related ruleset data
2719 **************************************************************************/
2720 static bool load_ruleset_terrain(struct section_file
*file
,
2721 struct rscompat_info
*compat
)
2725 bool compat_road
= FALSE
;
2726 bool compat_rail
= FALSE
;
2727 bool compat_river
= FALSE
;
2729 const char *filename
= secfile_name(file
);
2735 terrain_control
.ocean_reclaim_requirement_pct
2736 = secfile_lookup_int_default(file
, 101,
2737 "parameters.ocean_reclaim_requirement");
2738 terrain_control
.land_channel_requirement_pct
2739 = secfile_lookup_int_default(file
, 101,
2740 "parameters.land_channel_requirement");
2741 terrain_control
.terrain_thaw_requirement_pct
2742 = secfile_lookup_int_default(file
, 101,
2743 "parameters.thaw_requirement");
2744 terrain_control
.terrain_freeze_requirement_pct
2745 = secfile_lookup_int_default(file
, 101,
2746 "parameters.freeze_requirement");
2747 terrain_control
.lake_max_size
2748 = secfile_lookup_int_default(file
, 0,
2749 "parameters.lake_max_size");
2750 terrain_control
.min_start_native_area
2751 = secfile_lookup_int_default(file
, 0,
2752 "parameters.min_start_native_area");
2753 terrain_control
.move_fragments
2754 = secfile_lookup_int_default(file
, 3,
2755 "parameters.move_fragments");
2756 if (terrain_control
.move_fragments
< 1) {
2757 ruleset_error(LOG_ERROR
, "\"%s\": move_fragments must be at least 1",
2761 init_move_fragments();
2762 terrain_control
.igter_cost
2763 = secfile_lookup_int_default(file
, 1,
2764 "parameters.igter_cost");
2765 if (terrain_control
.igter_cost
< 1) {
2766 ruleset_error(LOG_ERROR
, "\"%s\": igter_cost must be at least 1",
2770 terrain_control
.pythagorean_diagonal
2771 = secfile_lookup_bool_default(file
, RS_DEFAULT_PYTHAGOREAN_DIAGONAL
,
2772 "parameters.pythagorean_diagonal");
2774 wld
.map
.server
.ocean_resources
2775 = secfile_lookup_bool_default(file
, FALSE
,
2776 "parameters.ocean_resources");
2778 text
= secfile_lookup_str_default(file
,
2779 N_("?gui_type:Build Type A Base"),
2780 "extraui.ui_name_base_fortress");
2781 sz_strlcpy(terrain_control
.gui_type_base0
, text
);
2783 text
= secfile_lookup_str_default(file
,
2784 N_("?gui_type:Build Type B Base"),
2785 "extraui.ui_name_base_airbase");
2786 sz_strlcpy(terrain_control
.gui_type_base1
, text
);
2789 /* terrain details */
2791 terrain_type_iterate(pterrain
) {
2793 const int i
= terrain_index(pterrain
);
2794 const char *tsection
= &terrain_sections
[i
* MAX_SECTION_LABEL
];
2797 sz_strlcpy(pterrain
->graphic_str
,
2798 secfile_lookup_str(file
,"%s.graphic", tsection
));
2799 sz_strlcpy(pterrain
->graphic_alt
,
2800 secfile_lookup_str(file
,"%s.graphic_alt", tsection
));
2802 pterrain
->identifier
2803 = secfile_lookup_str(file
, "%s.identifier", tsection
)[0];
2804 if ('\0' == pterrain
->identifier
) {
2805 ruleset_error(LOG_ERROR
, "\"%s\" [%s] identifier missing value.",
2806 filename
, tsection
);
2810 if (TERRAIN_UNKNOWN_IDENTIFIER
== pterrain
->identifier
) {
2811 ruleset_error(LOG_ERROR
,
2812 "\"%s\" [%s] cannot use '%c' as an identifier;"
2813 " it is reserved for unknown terrain.",
2814 filename
, tsection
, pterrain
->identifier
);
2818 for (j
= T_FIRST
; j
< i
; j
++) {
2819 if (pterrain
->identifier
== terrain_by_number(j
)->identifier
) {
2820 ruleset_error(LOG_ERROR
,
2821 "\"%s\" [%s] has the same identifier as [%s].",
2824 &terrain_sections
[j
* MAX_SECTION_LABEL
]);
2834 cstr
= secfile_lookup_str(file
, "%s.class", tsection
);
2835 pterrain
->tclass
= terrain_class_by_name(cstr
, fc_strcasecmp
);
2836 if (!terrain_class_is_valid(pterrain
->tclass
)) {
2837 ruleset_error(LOG_ERROR
, "\"%s\": [%s] unknown class \"%s\"",
2838 filename
, tsection
, cstr
);
2843 if (!secfile_lookup_int(file
, &pterrain
->movement_cost
,
2844 "%s.movement_cost", tsection
)
2845 || !secfile_lookup_int(file
, &pterrain
->defense_bonus
,
2846 "%s.defense_bonus", tsection
)) {
2847 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2852 output_type_iterate(o
) {
2854 = secfile_lookup_int_default(file
, 0, "%s.%s", tsection
,
2855 get_output_identifier(o
));
2856 } output_type_iterate_end
;
2858 res
= secfile_lookup_str_vec(file
, &nval
, "%s.resources", tsection
);
2859 pterrain
->resources
= fc_calloc(nval
+ 1, sizeof(*pterrain
->resources
));
2860 for (j
= 0; j
< nval
; j
++) {
2861 pterrain
->resources
[j
] = lookup_resource(filename
, res
[j
], tsection
);
2862 if (pterrain
->resources
[j
] == NULL
) {
2867 pterrain
->resources
[nval
] = NULL
;
2875 output_type_iterate(o
) {
2876 pterrain
->road_output_incr_pct
[o
]
2877 = secfile_lookup_int_default(file
, 0, "%s.road_%s_incr_pct",
2878 tsection
, get_output_identifier(o
));
2879 } output_type_iterate_end
;
2881 if (!lookup_time(file
, &pterrain
->base_time
, tsection
, "base_time",
2882 filename
, NULL
, &ok
)
2883 || !lookup_time(file
, &pterrain
->road_time
, tsection
, "road_time",
2884 filename
, NULL
, &ok
)) {
2885 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2890 if (!lookup_terrain(file
, "irrigation_result", filename
, pterrain
,
2891 &pterrain
->irrigation_result
)) {
2895 if (!secfile_lookup_int(file
, &pterrain
->irrigation_food_incr
,
2896 "%s.irrigation_food_incr", tsection
)
2897 || !lookup_time(file
, &pterrain
->irrigation_time
,
2898 tsection
, "irrigation_time", filename
, NULL
, &ok
)) {
2899 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2904 if (!lookup_terrain(file
, "mining_result", filename
, pterrain
,
2905 &pterrain
->mining_result
)) {
2909 if (!secfile_lookup_int(file
, &pterrain
->mining_shield_incr
,
2910 "%s.mining_shield_incr", tsection
)
2911 || !lookup_time(file
, &pterrain
->mining_time
,
2912 tsection
, "mining_time", filename
, NULL
, &ok
)) {
2913 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2918 if (!lookup_unit_type(file
, tsection
, "animal",
2919 &pterrain
->animal
, filename
,
2920 rule_name_get(&pterrain
->name
))) {
2925 if (!lookup_terrain(file
, "transform_result", filename
, pterrain
,
2926 &pterrain
->transform_result
)) {
2930 if (!lookup_time(file
, &pterrain
->transform_time
,
2931 tsection
, "transform_time", filename
, NULL
, &ok
)) {
2932 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2936 pterrain
->pillage_time
= 1; /* default */
2937 lookup_time(file
, &pterrain
->pillage_time
,
2938 tsection
, "pillage_time", filename
, NULL
, &ok
);
2939 pterrain
->clean_pollution_time
= 3; /* default */
2940 lookup_time(file
, &pterrain
->clean_pollution_time
,
2941 tsection
, "clean_pollution_time", filename
, NULL
, &ok
);
2942 pterrain
->clean_fallout_time
= 3; /* default */
2943 lookup_time(file
, &pterrain
->clean_fallout_time
,
2944 tsection
, "clean_fallout_time", filename
, NULL
, &ok
);
2946 if (!lookup_terrain(file
, "warmer_wetter_result", filename
, pterrain
,
2947 &pterrain
->warmer_wetter_result
)
2948 || !lookup_terrain(file
, "warmer_drier_result", filename
, pterrain
,
2949 &pterrain
->warmer_drier_result
)
2950 || !lookup_terrain(file
, "cooler_wetter_result", filename
, pterrain
,
2951 &pterrain
->cooler_wetter_result
)
2952 || !lookup_terrain(file
, "cooler_drier_result", filename
, pterrain
,
2953 &pterrain
->cooler_drier_result
)) {
2958 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", tsection
);
2959 BV_CLR_ALL(pterrain
->flags
);
2960 for (j
= 0; j
< nval
; j
++) {
2961 const char *sval
= slist
[j
];
2962 enum terrain_flag_id flag
2963 = terrain_flag_id_by_name(sval
, fc_strcasecmp
);
2965 if (!terrain_flag_id_is_valid(flag
)) {
2966 ruleset_error(LOG_ERROR
, "\"%s\" [%s] has unknown flag \"%s\".",
2967 filename
, tsection
, sval
);
2971 BV_SET(pterrain
->flags
, flag
);
2981 enum mapgen_terrain_property mtp
;
2982 for (mtp
= mapgen_terrain_property_begin();
2983 mtp
!= mapgen_terrain_property_end();
2984 mtp
= mapgen_terrain_property_next(mtp
)) {
2985 pterrain
->property
[mtp
]
2986 = secfile_lookup_int_default(file
, 0, "%s.property_%s", tsection
,
2987 mapgen_terrain_property_name(mtp
));
2991 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.native_to", tsection
);
2992 BV_CLR_ALL(pterrain
->native_to
);
2993 for (j
= 0; j
< nval
; j
++) {
2994 struct unit_class
*class = unit_class_by_rule_name(slist
[j
]);
2997 ruleset_error(LOG_ERROR
,
2998 "\"%s\" [%s] is native to unknown unit class \"%s\".",
2999 filename
, tsection
, slist
[j
]);
3003 BV_SET(pterrain
->native_to
, uclass_index(class));
3012 /* get terrain color */
3014 fc_assert_ret_val(pterrain
->rgb
== NULL
, FALSE
);
3015 if (!rgbcolor_load(file
, &pterrain
->rgb
, "%s.color", tsection
)) {
3016 ruleset_error(LOG_ERROR
, "Missing terrain color definition: %s",
3023 pterrain
->helptext
= lookup_strvec(file
, tsection
, "helptext");
3024 } terrain_type_iterate_end
;
3029 extra_type_iterate(pextra
) {
3030 BV_CLR_ALL(pextra
->conflicts
);
3031 } extra_type_iterate_end
;
3033 extra_type_iterate(pextra
) {
3034 if (!compat
->compat_mode
|| compat
->ver_terrain
>= 10 || pextra
->category
!= ECAT_RESOURCE
) {
3035 const char *section
= &extra_sections
[extra_index(pextra
) * MAX_SECTION_LABEL
];
3037 struct requirement_vector
*reqs
;
3038 const char *catname
;
3040 enum extra_cause cause
;
3041 enum extra_rmcause rmcause
;
3042 const char *eus_name
;
3043 const char *vis_req_name
;
3044 const struct advance
*vis_req
;
3046 catname
= secfile_lookup_str(file
, "%s.category", section
);
3047 if (catname
== NULL
) {
3048 ruleset_error(LOG_ERROR
, "\"%s\" extra \"%s\" has no category.",
3050 extra_rule_name(pextra
));
3054 pextra
->category
= extra_category_by_name(catname
, fc_strcasecmp
);
3055 if (!extra_category_is_valid(pextra
->category
)) {
3056 ruleset_error(LOG_ERROR
,
3057 "\"%s\" extra \"%s\" has invalid category \"%s\".",
3058 filename
, extra_rule_name(pextra
), catname
);
3063 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.causes", section
);
3065 for (cj
= 0; cj
< nval
; cj
++) {
3066 const char *sval
= slist
[cj
];
3067 cause
= extra_cause_by_name(sval
, fc_strcasecmp
);
3069 if (!extra_cause_is_valid(cause
)) {
3070 ruleset_error(LOG_ERROR
, "\"%s\" extra \"%s\": unknown cause \"%s\".",
3072 extra_rule_name(pextra
),
3077 pextra
->causes
|= (1 << cause
);
3078 extra_to_caused_by_list(pextra
, cause
);
3082 extra_to_category_list(pextra
, pextra
->category
);
3084 if (pextra
->causes
== 0) {
3085 /* Extras that do not have any causes added to EC_NONE list */
3086 extra_to_caused_by_list(pextra
, EC_NONE
);
3089 if (!is_extra_caused_by(pextra
, EC_BASE
)
3090 && !is_extra_caused_by(pextra
, EC_ROAD
)
3091 && !is_extra_caused_by(pextra
, EC_RESOURCE
)) {
3092 /* Not a base, road, nor resource, so special */
3093 pextra
->data
.special_idx
= extra_type_list_size(extra_type_list_by_cause(EC_SPECIAL
));
3094 extra_to_caused_by_list(pextra
, EC_SPECIAL
);
3099 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.rmcauses", section
);
3100 pextra
->rmcauses
= 0;
3101 for (j
= 0; j
< nval
; j
++) {
3102 const char *sval
= slist
[j
];
3103 rmcause
= extra_rmcause_by_name(sval
, fc_strcasecmp
);
3105 if (!extra_rmcause_is_valid(rmcause
)) {
3106 ruleset_error(LOG_ERROR
, "\"%s\" extra \"%s\": unknown rmcause \"%s\".",
3108 extra_rule_name(pextra
),
3113 pextra
->rmcauses
|= (1 << rmcause
);
3114 extra_to_removed_by_list(pextra
, rmcause
);
3120 sz_strlcpy(pextra
->activity_gfx
,
3121 secfile_lookup_str_default(file
, "-",
3122 "%s.activity_gfx", section
));
3123 sz_strlcpy(pextra
->act_gfx_alt
,
3124 secfile_lookup_str_default(file
, "-",
3125 "%s.act_gfx_alt", section
));
3126 sz_strlcpy(pextra
->act_gfx_alt2
,
3127 secfile_lookup_str_default(file
, "-",
3128 "%s.act_gfx_alt2", section
));
3129 sz_strlcpy(pextra
->rmact_gfx
,
3130 secfile_lookup_str_default(file
, "-",
3131 "%s.rmact_gfx", section
));
3132 sz_strlcpy(pextra
->rmact_gfx_alt
,
3133 secfile_lookup_str_default(file
, "-",
3134 "%s.rmact_gfx_alt", section
));
3135 sz_strlcpy(pextra
->graphic_str
,
3136 secfile_lookup_str_default(file
, "-", "%s.graphic", section
));
3137 sz_strlcpy(pextra
->graphic_alt
,
3138 secfile_lookup_str_default(file
, "-",
3139 "%s.graphic_alt", section
));
3141 reqs
= lookup_req_list(file
, compat
, section
, "reqs", extra_rule_name(pextra
));
3146 requirement_vector_copy(&pextra
->reqs
, reqs
);
3148 reqs
= lookup_req_list(file
, compat
, section
, "rmreqs", extra_rule_name(pextra
));
3153 requirement_vector_copy(&pextra
->rmreqs
, reqs
);
3155 reqs
= lookup_req_list(file
, compat
, section
, "appearance_reqs", extra_rule_name(pextra
));
3160 requirement_vector_copy(&pextra
->appearance_reqs
, reqs
);
3162 reqs
= lookup_req_list(file
, compat
, section
, "disappearance_reqs", extra_rule_name(pextra
));
3167 requirement_vector_copy(&pextra
->disappearance_reqs
, reqs
);
3169 pextra
->buildable
= secfile_lookup_bool_default(file
,
3170 is_extra_caused_by_worker_action(pextra
),
3171 "%s.buildable", section
);
3173 pextra
->build_time
= 0; /* default */
3174 lookup_time(file
, &pextra
->build_time
, section
, "build_time",
3175 filename
, extra_rule_name(pextra
), &ok
);
3176 pextra
->build_time_factor
= secfile_lookup_int_default(file
, 1,
3177 "%s.build_time_factor", section
);
3178 pextra
->removal_time
= 0; /* default */
3179 lookup_time(file
, &pextra
->removal_time
, section
, "removal_time",
3180 filename
, extra_rule_name(pextra
), &ok
);
3181 pextra
->removal_time_factor
= secfile_lookup_int_default(file
, 1,
3182 "%s.removal_time_factor", section
);
3184 pextra
->defense_bonus
= secfile_lookup_int_default(file
, 0,
3187 if (pextra
->defense_bonus
!= 0) {
3188 if (extra_has_flag(pextra
, EF_NATURAL_DEFENSE
)) {
3189 extra_to_caused_by_list(pextra
, EC_NATURAL_DEFENSIVE
);
3191 extra_to_caused_by_list(pextra
, EC_DEFENSIVE
);
3195 eus_name
= secfile_lookup_str_default(file
, "Normal", "%s.unit_seen", section
);
3196 pextra
->eus
= extra_unit_seen_type_by_name(eus_name
, fc_strcasecmp
);
3197 if (!extra_unit_seen_type_is_valid(pextra
->eus
)) {
3198 ruleset_error(LOG_ERROR
,
3199 "\"%s\" extra \"%s\" has illegal unit_seen value \"%s\".",
3200 filename
, extra_rule_name(pextra
),
3205 if (pextra
->eus
== EUS_HIDDEN
) {
3206 extra_type_list_append(extra_type_list_of_unit_hiders(), pextra
);
3209 pextra
->appearance_chance
= secfile_lookup_int_default(file
, RS_DEFAULT_EXTRA_APPEARANCE
,
3210 "%s.appearance_chance",
3212 pextra
->disappearance_chance
= secfile_lookup_int_default(file
,
3213 RS_DEFAULT_EXTRA_DISAPPEARANCE
,
3214 "%s.disappearance_chance",
3217 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.native_to", section
);
3218 BV_CLR_ALL(pextra
->native_to
);
3219 for (j
= 0; j
< nval
; j
++) {
3220 struct unit_class
*uclass
= unit_class_by_rule_name(slist
[j
]);
3222 if (uclass
== NULL
) {
3223 ruleset_error(LOG_ERROR
,
3224 "\"%s\" extra \"%s\" is native to unknown unit class \"%s\".",
3226 extra_rule_name(pextra
),
3231 BV_SET(pextra
->native_to
, uclass_index(uclass
));
3240 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", section
);
3241 BV_CLR_ALL(pextra
->flags
);
3242 for (j
= 0; j
< nval
; j
++) {
3243 const char *sval
= slist
[j
];
3244 enum extra_flag_id flag
= extra_flag_id_by_name(sval
, fc_strcasecmp
);
3246 if (!extra_flag_id_is_valid(flag
)) {
3247 ruleset_error(LOG_ERROR
, "\"%s\" extra \"%s\": unknown flag \"%s\".",
3249 extra_rule_name(pextra
),
3254 BV_SET(pextra
->flags
, flag
);
3263 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.conflicts", section
);
3264 for (j
= 0; j
< nval
; j
++) {
3265 const char *sval
= slist
[j
];
3266 struct extra_type
*pextra2
= extra_type_by_rule_name(sval
);
3268 if (pextra2
== NULL
) {
3269 ruleset_error(LOG_ERROR
, "\"%s\" extra \"%s\": unknown conflict extra \"%s\".",
3271 extra_rule_name(pextra
),
3276 BV_SET(pextra
->conflicts
, extra_index(pextra2
));
3277 BV_SET(pextra2
->conflicts
, extra_index(pextra
));
3287 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.hidden_by", section
);
3288 BV_CLR_ALL(pextra
->hidden_by
);
3289 for (j
= 0; j
< nval
; j
++) {
3290 const char *sval
= slist
[j
];
3291 const struct extra_type
*top
= extra_type_by_rule_name(sval
);
3294 ruleset_error(LOG_ERROR
, "\"%s\" extra \"%s\" hidden by unknown extra \"%s\".",
3296 extra_rule_name(pextra
),
3301 BV_SET(pextra
->hidden_by
, extra_index(top
));
3310 vis_req_name
= secfile_lookup_str_default(file
, "None",
3311 "%s.visibility_req", section
);
3312 vis_req
= advance_by_rule_name(vis_req_name
);
3314 if (vis_req
== NULL
) {
3315 ruleset_error(LOG_ERROR
, "\%s\" %s: unknown visibility_req %s.",
3316 filename
, section
, vis_req_name
);
3321 pextra
->visibility_req
= advance_number(vis_req
);
3323 pextra
->helptext
= lookup_strvec(file
, section
, "helptext");
3325 } extra_type_iterate_end
;
3330 /* resource details */
3332 extra_type_by_cause_iterate(EC_RESOURCE
, presource
) {
3333 char identifier
[MAX_LEN_NAME
];
3334 const char *rsection
= &resource_sections
[i
* MAX_SECTION_LABEL
];
3336 output_type_iterate (o
) {
3337 presource
->data
.resource
->output
[o
] =
3338 secfile_lookup_int_default(file
, 0, "%s.%s", rsection
,
3339 get_output_identifier(o
));
3340 } output_type_iterate_end
;
3342 sz_strlcpy(identifier
,
3343 secfile_lookup_str(file
,"%s.identifier", rsection
));
3344 presource
->data
.resource
->id_old_save
= identifier
[0];
3345 if (RESOURCE_NULL_IDENTIFIER
== presource
->data
.resource
->id_old_save
) {
3346 ruleset_error(LOG_ERROR
, "\"%s\" [%s] identifier missing value.",
3347 filename
, rsection
);
3351 if (RESOURCE_NONE_IDENTIFIER
== presource
->data
.resource
->id_old_save
) {
3352 ruleset_error(LOG_ERROR
,
3353 "\"%s\" [%s] cannot use '%c' as an identifier;"
3355 filename
, rsection
, presource
->data
.resource
->id_old_save
);
3365 } extra_type_by_cause_iterate_end
;
3369 /* This can't be part of previous loop as we don't want random data from previous
3370 * ruleset to play havoc on us when we have only some resource identifiers loaded
3371 * from the new ruleset. */
3372 extra_type_by_cause_iterate(EC_RESOURCE
, pres
) {
3373 extra_type_by_cause_iterate(EC_RESOURCE
, pres2
) {
3374 if (pres
->data
.resource
->id_old_save
== pres2
->data
.resource
->id_old_save
3376 ruleset_error(LOG_ERROR
,
3377 "\"%s\" [%s] has the same identifier as [%s].",
3379 extra_rule_name(pres
),
3380 extra_rule_name(pres2
));
3384 } extra_type_by_cause_iterate_end
;
3389 } extra_type_by_cause_iterate_end
;
3394 extra_type_by_cause_iterate(EC_BASE
, pextra
) {
3395 struct base_type
*pbase
= extra_base_get(pextra
);
3396 const char *section
= &base_sections
[base_number(pbase
) * MAX_SECTION_LABEL
];
3399 const char *gui_str
;
3401 gui_str
= secfile_lookup_str(file
,"%s.gui_type", section
);
3402 pbase
->gui_type
= base_gui_type_by_name(gui_str
, fc_strcasecmp
);
3403 if (!base_gui_type_is_valid(pbase
->gui_type
)) {
3404 ruleset_error(LOG_ERROR
, "\"%s\" base \"%s\": unknown gui_type \"%s\".",
3406 extra_rule_name(pextra
),
3412 pbase
->border_sq
= secfile_lookup_int_default(file
, -1, "%s.border_sq",
3414 pbase
->vision_main_sq
= secfile_lookup_int_default(file
, -1,
3415 "%s.vision_main_sq",
3417 pbase
->vision_invis_sq
= secfile_lookup_int_default(file
, -1,
3418 "%s.vision_invis_sq",
3421 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", section
);
3422 BV_CLR_ALL(pbase
->flags
);
3423 for (bj
= 0; bj
< nval
; bj
++) {
3424 const char *sval
= slist
[bj
];
3425 enum base_flag_id flag
= base_flag_id_by_name(sval
, fc_strcasecmp
);
3427 if (!base_flag_id_is_valid(flag
)) {
3428 ruleset_error(LOG_ERROR
, "\"%s\" base \"%s\": unknown flag \"%s\".",
3430 extra_rule_name(pextra
),
3434 } else if ((!compat
->compat_mode
|| compat
->ver_terrain
>= 10)
3435 && base_flag_is_retired(flag
)) {
3436 ruleset_error(LOG_ERROR
, "\"%s\" base \"%s\": retired flag "
3437 "\"%s\". Please update the ruleset.",
3439 extra_rule_name(pextra
),
3443 BV_SET(pbase
->flags
, flag
);
3453 if (territory_claiming_base(pbase
)) {
3454 extra_type_by_cause_iterate(EC_BASE
, pextra2
) {
3455 struct base_type
*pbase2
;
3457 if (pextra
== pextra2
) {
3458 /* End of the fully initialized bases iteration. */
3462 pbase2
= extra_base_get(pextra2
);
3463 if (territory_claiming_base(pbase2
)) {
3464 BV_SET(pextra
->conflicts
, extra_index(pextra2
));
3465 BV_SET(pextra2
->conflicts
, extra_index(pextra
));
3467 } extra_type_by_cause_iterate_end
;
3469 } extra_type_by_cause_iterate_end
;
3473 extra_type_by_cause_iterate(EC_ROAD
, pextra
) {
3474 struct road_type
*proad
= extra_road_get(pextra
);
3475 const char *section
= &road_sections
[road_number(proad
) * MAX_SECTION_LABEL
];
3477 const char *special
;
3478 const char *modestr
;
3479 struct requirement_vector
*reqs
;
3481 reqs
= lookup_req_list(file
, compat
, section
, "first_reqs", extra_rule_name(pextra
));
3486 requirement_vector_copy(&proad
->first_reqs
, reqs
);
3488 if (!secfile_lookup_int(file
, &proad
->move_cost
,
3489 "%s.move_cost", section
)) {
3490 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
3495 modestr
= secfile_lookup_str_default(file
, "FastAlways", "%s.move_mode",
3497 proad
->move_mode
= road_move_mode_by_name(modestr
, fc_strcasecmp
);
3498 if (!road_move_mode_is_valid(proad
->move_mode
)) {
3499 ruleset_error(LOG_ERROR
, "Illegal move_mode \"%s\" for road \"%s\"",
3500 modestr
, extra_rule_name(pextra
));
3505 output_type_iterate(o
) {
3506 proad
->tile_incr_const
[o
] =
3507 secfile_lookup_int_default(file
, 0, "%s.%s_incr_const",
3508 section
, get_output_identifier(o
));
3509 proad
->tile_incr
[o
] =
3510 secfile_lookup_int_default(file
, 0, "%s.%s_incr",
3511 section
, get_output_identifier(o
));
3512 proad
->tile_bonus
[o
] =
3513 secfile_lookup_int_default(file
, 0, "%s.%s_bonus",
3514 section
, get_output_identifier(o
));
3515 } output_type_iterate_end
;
3517 special
= secfile_lookup_str_default(file
, "None", "%s.compat_special", section
);
3518 if (!fc_strcasecmp(special
, "Road")) {
3520 ruleset_error(LOG_ERROR
, "Multiple roads marked as compatibility \"Road\"");
3524 proad
->compat
= ROCO_ROAD
;
3525 } else if (!fc_strcasecmp(special
, "Railroad")) {
3527 ruleset_error(LOG_ERROR
, "Multiple roads marked as compatibility \"Railroad\"");
3531 proad
->compat
= ROCO_RAILROAD
;
3532 } else if (!fc_strcasecmp(special
, "River")) {
3534 ruleset_error(LOG_ERROR
, "Multiple roads marked as compatibility \"River\"");
3537 compat_river
= TRUE
;
3538 proad
->compat
= ROCO_RIVER
;
3539 } else if (!fc_strcasecmp(special
, "None")) {
3540 proad
->compat
= ROCO_NONE
;
3542 ruleset_error(LOG_ERROR
, "Illegal compatibility special \"%s\" for road %s",
3543 special
, extra_rule_name(pextra
));
3551 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.integrates", section
);
3552 BV_CLR_ALL(proad
->integrates
);
3553 for (j
= 0; j
< nval
; j
++) {
3554 const char *sval
= slist
[j
];
3555 struct extra_type
*textra
= extra_type_by_rule_name(sval
);
3556 struct road_type
*top
= NULL
;
3558 if (textra
!= NULL
) {
3559 top
= extra_road_get(textra
);
3563 ruleset_error(LOG_ERROR
, "\"%s\" road \"%s\" integrates with unknown road \"%s\".",
3565 extra_rule_name(pextra
),
3570 BV_SET(proad
->integrates
, road_number(top
));
3579 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", section
);
3580 BV_CLR_ALL(proad
->flags
);
3581 for (j
= 0; j
< nval
; j
++) {
3582 const char *sval
= slist
[j
];
3583 enum road_flag_id flag
= road_flag_id_by_name(sval
, fc_strcasecmp
);
3585 if (!road_flag_id_is_valid(flag
)) {
3586 ruleset_error(LOG_ERROR
, "\"%s\" road \"%s\": unknown flag \"%s\".",
3588 extra_rule_name(pextra
),
3593 BV_SET(proad
->flags
, flag
);
3601 } extra_type_by_cause_iterate_end
;
3605 secfile_check_unused(file
);
3611 /**************************************************************************
3612 Load names of governments so other rulesets can refer to governments with
3613 their name. Also load multiplier names/count from governments.ruleset.
3614 **************************************************************************/
3615 static bool load_government_names(struct section_file
*file
,
3616 struct rscompat_info
*compat
)
3619 struct section_list
*sec
;
3620 const char *filename
= secfile_name(file
);
3623 compat
->ver_governments
= rscompat_check_capabilities(file
, filename
,
3625 if (compat
->ver_governments
<= 0) {
3629 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
3630 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
3632 sec
= secfile_sections_by_name_prefix(file
, GOVERNMENT_SECTION_PREFIX
);
3633 if (NULL
== sec
|| 0 == (nval
= section_list_size(sec
))) {
3634 ruleset_error(LOG_ERROR
, "\"%s\": No governments?!?", filename
);
3636 } else if (nval
> G_LAST
) {
3637 ruleset_error(LOG_ERROR
, "\"%s\": Too many governments (%d, max %d)",
3638 filename
, nval
, G_LAST
);
3643 governments_alloc(nval
);
3645 /* Government names are needed early so that get_government_by_name will
3647 governments_iterate(gov
) {
3648 const char *sec_name
=
3649 section_name(section_list_get(sec
, government_index(gov
)));
3651 if (!ruleset_load_names(&gov
->name
, NULL
, file
, sec_name
)) {
3655 } governments_iterate_end
;
3658 section_list_destroy(sec
);
3661 sec
= secfile_sections_by_name_prefix(file
, MULTIPLIER_SECTION_PREFIX
);
3662 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
3664 if (nval
> MAX_NUM_MULTIPLIERS
) {
3665 ruleset_error(LOG_ERROR
, "\"%s\": Too many multipliers (%d, max %d)",
3666 filename
, nval
, MAX_NUM_MULTIPLIERS
);
3670 game
.control
.num_multipliers
= nval
;
3674 multipliers_iterate(pmul
) {
3675 const char *sec_name
=
3676 section_name(section_list_get(sec
, multiplier_index(pmul
)));
3678 if (!ruleset_load_names(&pmul
->name
, NULL
, file
, sec_name
)) {
3679 ruleset_error(LOG_ERROR
, "\"%s\": Cannot load multiplier names",
3684 } multipliers_iterate_end
;
3688 section_list_destroy(sec
);
3693 /**************************************************************************
3694 This loads information from given governments.ruleset
3695 **************************************************************************/
3696 static bool load_ruleset_governments(struct section_file
*file
,
3697 struct rscompat_info
*compat
)
3699 struct section_list
*sec
;
3700 const char *filename
= secfile_name(file
);
3703 sec
= secfile_sections_by_name_prefix(file
, GOVERNMENT_SECTION_PREFIX
);
3705 game
.government_during_revolution
3706 = lookup_government(file
, "governments.during_revolution", filename
, NULL
);
3707 if (game
.government_during_revolution
== NULL
) {
3712 game
.info
.government_during_revolution_id
=
3713 government_number(game
.government_during_revolution
);
3716 governments_iterate(g
) {
3717 const int i
= government_index(g
);
3718 const char *sec_name
= section_name(section_list_get(sec
, i
));
3719 struct requirement_vector
*reqs
=
3720 lookup_req_list(file
, compat
, sec_name
, "reqs", government_rule_name(g
));
3727 if (NULL
!= secfile_entry_lookup(file
, "%s.ai_better", sec_name
)) {
3730 fc_snprintf(entry
, sizeof(entry
), "%s.ai_better", sec_name
);
3731 g
->ai
.better
= lookup_government(file
, entry
, filename
, NULL
);
3732 if (g
->ai
.better
== NULL
) {
3737 g
->ai
.better
= NULL
;
3739 requirement_vector_copy(&g
->reqs
, reqs
);
3741 sz_strlcpy(g
->graphic_str
,
3742 secfile_lookup_str(file
, "%s.graphic", sec_name
));
3743 sz_strlcpy(g
->graphic_alt
,
3744 secfile_lookup_str(file
, "%s.graphic_alt", sec_name
));
3746 g
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
3747 } governments_iterate_end
;
3753 governments_iterate(g
) {
3754 const char *sec_name
=
3755 section_name(section_list_get(sec
, government_index(g
)));
3756 const char *male
, *female
;
3758 if (!(male
= secfile_lookup_str(file
, "%s.ruler_male_title", sec_name
))
3759 || !(female
= secfile_lookup_str(file
, "%s.ruler_female_title",
3761 ruleset_error(LOG_ERROR
, "Lack of default ruler titles for "
3762 "government \"%s\" (nb %d): %s",
3763 government_rule_name(g
), government_number(g
),
3767 } else if (NULL
== government_ruler_title_new(g
, NULL
, male
, female
)) {
3768 ruleset_error(LOG_ERROR
, "Lack of default ruler titles for "
3769 "government \"%s\" (nb %d).",
3770 government_rule_name(g
), government_number(g
));
3774 } governments_iterate_end
;
3777 section_list_destroy(sec
);
3780 sec
= secfile_sections_by_name_prefix(file
, MULTIPLIER_SECTION_PREFIX
);
3781 multipliers_iterate(pmul
) {
3782 int id
= multiplier_index(pmul
);
3783 const char *sec_name
= section_name(section_list_get(sec
, id
));
3785 if (!secfile_lookup_int(file
, &pmul
->start
, "%s.start", sec_name
)) {
3786 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
3790 if (!secfile_lookup_int(file
, &pmul
->stop
, "%s.stop", sec_name
)) {
3791 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
3795 if (pmul
->stop
<= pmul
->start
) {
3796 ruleset_error(LOG_ERROR
, "Multiplier \"%s\" stop (%d) must be greater "
3797 "than start (%d)", multiplier_rule_name(pmul
),
3798 pmul
->stop
, pmul
->start
);
3802 if (!secfile_lookup_int(file
, &pmul
->step
, "%s.step", sec_name
)) {
3803 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
3807 if (((pmul
->stop
- pmul
->start
) % pmul
->step
) != 0) {
3808 ruleset_error(LOG_ERROR
, "Multiplier \"%s\" step (%d) does not fit "
3809 "exactly into interval start-stop (%d to %d)",
3810 multiplier_rule_name(pmul
), pmul
->step
,
3811 pmul
->start
, pmul
->stop
);
3815 if (!secfile_lookup_int(file
, &pmul
->def
, "%s.default", sec_name
)) {
3816 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
3820 if (pmul
->def
< pmul
->start
|| pmul
->def
> pmul
->stop
) {
3821 ruleset_error(LOG_ERROR
, "Multiplier \"%s\" default (%d) not within "
3822 "legal range (%d to %d)", multiplier_rule_name(pmul
),
3823 pmul
->def
, pmul
->start
, pmul
->stop
);
3827 if (((pmul
->def
- pmul
->start
) % pmul
->step
) != 0) {
3828 ruleset_error(LOG_ERROR
, "Multiplier \"%s\" default (%d) not legal "
3829 "with respect to step size %d",
3830 multiplier_rule_name(pmul
), pmul
->def
, pmul
->step
);
3834 pmul
->offset
= secfile_lookup_int_default(file
, 0,
3835 "%s.offset", sec_name
);
3836 pmul
->factor
= secfile_lookup_int_default(file
, 100,
3837 "%s.factor", sec_name
);
3838 if (pmul
->factor
== 0) {
3839 ruleset_error(LOG_ERROR
, "Multiplier \"%s\" scaling factor must "
3840 "not be zero", multiplier_rule_name(pmul
));
3845 pmul
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
3846 } multipliers_iterate_end
;
3847 section_list_destroy(sec
);
3851 secfile_check_unused(file
);
3857 /**************************************************************************
3858 Send information in packet_ruleset_control (numbers of units etc, and
3859 other miscellany) to specified connections.
3861 The client assumes that exactly one ruleset control packet is sent as
3862 a part of each ruleset send. So after sending this packet we have to
3863 resend every other part of the rulesets (and none of them should be
3864 is-info in the network code!). The client frees ruleset data when
3865 receiving this packet and then re-initializes as it receives the
3866 individual ruleset packets. See packhand.c.
3867 **************************************************************************/
3868 static void send_ruleset_control(struct conn_list
*dest
)
3870 int desc_left
= game
.control
.desc_length
;
3873 lsend_packet_ruleset_control(dest
, &(game
.control
));
3875 if (game
.ruleset_summary
!= NULL
) {
3876 struct packet_ruleset_summary summary
;
3878 strncpy(summary
.text
, game
.ruleset_summary
, MAX_LEN_CONTENT
);
3880 lsend_packet_ruleset_summary(dest
, &summary
);
3883 while (desc_left
> 0) {
3884 struct packet_ruleset_description_part part
;
3885 int this_len
= desc_left
;
3887 if (this_len
> MAX_LEN_CONTENT
- 21) {
3888 this_len
= MAX_LEN_CONTENT
- 1;
3891 part
.text
[this_len
] = '\0';
3893 strncpy(part
.text
, &game
.ruleset_description
[idx
], this_len
);
3895 desc_left
-= this_len
;
3897 lsend_packet_ruleset_description_part(dest
, &part
);
3901 /****************************************************************************
3902 Check for duplicate leader names in nation.
3903 If no duplicates return NULL; if yes return pointer to name which is
3905 ****************************************************************************/
3906 static const char *check_leader_names(struct nation_type
*pnation
)
3908 nation_leader_list_iterate(nation_leaders(pnation
), pleader
) {
3909 const char *name
= nation_leader_name(pleader
);
3911 nation_leader_list_iterate(nation_leaders(pnation
), prev_leader
) {
3912 if (prev_leader
== pleader
) {
3914 } else if (0 == fc_strcasecmp(name
, nation_leader_name(prev_leader
))) {
3917 } nation_leader_list_iterate_end
;
3918 } nation_leader_list_iterate_end
;
3922 /**************************************************************************
3923 Load names of nations so other rulesets can refer to nations with
3925 **************************************************************************/
3926 static bool load_nation_names(struct section_file
*file
,
3927 struct rscompat_info
*compat
)
3929 struct section_list
*sec
;
3932 const char *filename
= secfile_name(file
);
3934 compat
->ver_nations
= rscompat_check_capabilities(file
, filename
,
3936 if (compat
->ver_nations
<= 0) {
3940 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
3941 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
3943 sec
= secfile_sections_by_name_prefix(file
, NATION_SECTION_PREFIX
);
3945 ruleset_error(LOG_ERROR
, "No available nations in this ruleset!");
3947 } else if (section_list_size(sec
) > MAX_NUM_NATIONS
) {
3948 ruleset_error(LOG_ERROR
, "Too many nations (max %d, we have %d)!",
3949 MAX_NUM_NATIONS
, section_list_size(sec
));
3952 game
.control
.nation_count
= section_list_size(sec
);
3953 nations_alloc(game
.control
.nation_count
);
3955 nations_iterate(pl
) {
3956 const int i
= nation_index(pl
);
3957 const char *sec_name
= section_name(section_list_get(sec
, i
));
3958 const char *domain
= secfile_lookup_str_default(file
, NULL
,
3959 "%s.translation_domain", sec_name
);
3960 const char *noun_plural
= secfile_lookup_str(file
,
3961 "%s.plural", sec_name
);
3964 if (domain
== NULL
) {
3965 domain
= "freeciv-nations";
3968 if (!strcmp("freeciv", domain
)) {
3969 pl
->translation_domain
= NULL
;
3970 } else if (!strcmp("freeciv-nations", domain
)) {
3971 pl
->translation_domain
= fc_malloc(strlen(domain
) + 1);
3972 strcpy(pl
->translation_domain
, domain
);
3974 ruleset_error(LOG_ERROR
, "Unsupported translation domain \"%s\" for %s",
3980 if (!ruleset_load_names(&pl
->adjective
, domain
, file
, sec_name
)) {
3984 name_set(&pl
->noun_plural
, domain
, noun_plural
);
3986 /* Check if nation name is already defined. */
3987 for (j
= 0; j
< i
&& ok
; j
++) {
3988 struct nation_type
*n2
= nation_by_number(j
);
3990 /* Compare strings after stripping off qualifiers -- we don't want
3991 * two nations to end up with identical adjectives displayed to users.
3992 * (This check only catches English, not localisations, of course.) */
3993 if (0 == strcmp(Qn_(untranslated_name(&n2
->adjective
)),
3994 Qn_(untranslated_name(&pl
->adjective
)))) {
3995 ruleset_error(LOG_ERROR
,
3996 "Two nations defined with the same adjective \"%s\": "
3997 "in section \'%s\' and section \'%s\'",
3998 Qn_(untranslated_name(&pl
->adjective
)),
3999 section_name(section_list_get(sec
, j
)), sec_name
);
4001 } else if (!strcmp(rule_name_get(&n2
->adjective
),
4002 rule_name_get(&pl
->adjective
))) {
4003 /* We cannot have the same rule name, as the game needs them to be
4005 ruleset_error(LOG_ERROR
,
4006 "Two nations defined with the same rule_name \"%s\": "
4007 "in section \'%s\' and section \'%s\'",
4008 rule_name_get(&pl
->adjective
),
4009 section_name(section_list_get(sec
, j
)), sec_name
);
4011 } else if (0 == strcmp(Qn_(untranslated_name(&n2
->noun_plural
)),
4012 Qn_(untranslated_name(&pl
->noun_plural
)))) {
4013 /* We don't want identical English plural names either. */
4014 ruleset_error(LOG_ERROR
,
4015 "Two nations defined with the same plural name \"%s\": "
4016 "in section \'%s\' and section \'%s\'",
4017 Qn_(untranslated_name(&pl
->noun_plural
)),
4018 section_name(section_list_get(sec
, j
)), sec_name
);
4025 } nations_iterate_end
;
4028 section_list_destroy(sec
);
4031 sec
= secfile_sections_by_name_prefix(file
, NATION_GROUP_SECTION_PREFIX
);
4033 section_list_iterate(sec
, psection
) {
4034 struct nation_group
*pgroup
;
4037 name
= secfile_lookup_str(file
, "%s.name", section_name(psection
));
4039 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
4043 pgroup
= nation_group_new(name
);
4044 if (pgroup
== NULL
) {
4048 } section_list_iterate_end
;
4049 section_list_destroy(sec
);
4057 /**************************************************************************
4058 Check if a string is in a vector (case-insensitively).
4059 **************************************************************************/
4060 static bool is_on_allowed_list(const char *name
, const char **list
, size_t len
)
4064 for (i
= 0; i
< len
; i
++) {
4065 if (!fc_strcasecmp(name
, list
[i
])) {
4072 /****************************************************************************
4073 This function loads a city name list from a section file. The file and
4074 two section names (which will be concatenated) are passed in.
4075 ****************************************************************************/
4076 static bool load_city_name_list(struct section_file
*file
,
4077 struct nation_type
*pnation
,
4078 const char *secfile_str1
,
4079 const char *secfile_str2
,
4080 const char **allowed_terrains
,
4085 const char **cities
= secfile_lookup_str_vec(file
, &dim
, "%s.%s",
4086 secfile_str1
, secfile_str2
);
4088 /* Each string will be of the form "<cityname> (<label>, <label>, ...)".
4089 * The cityname is just the name for this city, while each "label" matches
4090 * a terrain type for the city (or "river"), with a preceeding ! to negate
4091 * it. The parentheses are optional (but necessary to have the settings,
4092 * of course). Our job is now to parse it. */
4093 for (j
= 0; j
< dim
; j
++) {
4094 size_t len
= strlen(cities
[j
]);
4095 char city_name
[len
+ 1], *p
, *next
, *end
;
4096 struct nation_city
*pncity
;
4098 sz_strlcpy(city_name
, cities
[j
]);
4100 /* Now we wish to determine values for all of the city labels. A value
4101 * of NCP_NONE means no preference (which is necessary so that the use
4102 * of this is optional); NCP_DISLIKE means the label is negated and
4103 * NCP_LIKE means it's labelled. Mostly the parsing just involves
4104 * a lot of ugly string handling... */
4105 if ((p
= strchr(city_name
, '('))) {
4108 if (!(end
= strchr(p
, ')'))) {
4109 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city name \"%s\" "
4110 "unmatched parenthesis.", secfile_name(file
),
4111 secfile_str1
, secfile_str2
, cities
[j
]);
4114 for (*end
++ = '\0'; '\0' != *end
; end
++) {
4115 if (!fc_isspace(*end
)) {
4116 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city name \"%s\" "
4117 "contains characters after last parenthesis.",
4118 secfile_name(file
), secfile_str1
, secfile_str2
,
4127 /* Build the nation_city. */
4128 remove_leading_trailing_spaces(city_name
);
4129 if (check_cityname(city_name
)) {
4130 /* The ruleset contains a name that is too long. This shouldn't
4131 * happen - if it does, the author should get immediate feedback. */
4132 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city name \"%s\" "
4133 "is too long.", secfile_name(file
),
4134 secfile_str1
, secfile_str2
, city_name
);
4136 city_name
[MAX_LEN_CITYNAME
- 1] = '\0';
4138 pncity
= nation_city_new(pnation
, city_name
);
4141 /* Handle the labels one at a time. */
4143 enum nation_city_preference prefer
;
4145 if ((next
= strchr(p
, ','))) {
4148 remove_leading_trailing_spaces(p
);
4150 /* The ! is used to mark a negative, which is recorded with
4151 * NCP_DISLIKE. Otherwise we use a NCP_LIKE.
4155 prefer
= NCP_DISLIKE
;
4160 if (0 == fc_strcasecmp(p
, "river")) {
4161 if (game
.server
.ruledit
.allowed_terrains
!= NULL
4162 && !is_on_allowed_list(p
,
4163 game
.server
.ruledit
.allowed_terrains
, atcount
)) {
4164 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city \"%s\" "
4165 "has terrain hint \"%s\" not in allowed_terrains.",
4166 secfile_name(file
), secfile_str1
, secfile_str2
,
4170 nation_city_set_river_preference(pncity
, prefer
);
4173 const struct terrain
*pterrain
= terrain_by_rule_name(p
);
4175 if (NULL
== pterrain
) {
4176 /* Try with removing frequent trailing 's'. */
4177 size_t l
= strlen(p
);
4179 if (0 < l
&& 's' == fc_tolower(p
[l
- 1])) {
4182 pterrain
= terrain_by_rule_name(p
);
4185 /* Nationset may have been devised with a specific set of terrains
4186 * in mind which don't quite match this ruleset, in which case we
4187 * (a) quietly ignore any hints mentioned that don't happen to be in
4188 * the current ruleset, (b) enforce that terrains mentioned by nations
4189 * must be on the list */
4190 if (pterrain
!= NULL
&& game
.server
.ruledit
.allowed_terrains
!= NULL
) {
4191 if (!is_on_allowed_list(p
,
4192 game
.server
.ruledit
.allowed_terrains
, atcount
)) {
4193 /* Terrain exists, but not intended for these nations */
4194 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city \"%s\" "
4195 "has terrain hint \"%s\" not in allowed_terrains.",
4196 secfile_name(file
), secfile_str1
, secfile_str2
,
4201 } else if (!pterrain
) {
4202 /* Terrain doesn't exist; only complain if it's not on any list */
4203 if (game
.server
.ruledit
.allowed_terrains
== NULL
4204 || !is_on_allowed_list(p
,
4205 game
.server
.ruledit
.allowed_terrains
, atcount
)) {
4206 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city \"%s\" "
4207 "has unknown terrain hint \"%s\".",
4208 secfile_name(file
), secfile_str1
, secfile_str2
,
4214 if (NULL
!= pterrain
) {
4215 nation_city_set_terrain_preference(pncity
, pterrain
, prefer
);
4219 p
= next
? next
+ 1 : NULL
;
4220 } while (NULL
!= p
&& '\0' != *p
);
4224 if (NULL
!= cities
) {
4231 /**************************************************************************
4232 Load nations.ruleset file
4233 **************************************************************************/
4234 static bool load_ruleset_nations(struct section_file
*file
,
4235 struct rscompat_info
*compat
)
4237 struct government
*gov
;
4240 char temp_name
[MAX_LEN_NAME
];
4242 const char *name
, *bad_leader
;
4245 const char *filename
= secfile_name(file
);
4246 struct section_list
*sec
;
4250 name
= secfile_lookup_str_default(file
, NULL
, "ruledit.nationlist");
4252 game
.server
.ruledit
.nationlist
= fc_strdup(name
);
4254 vec
= secfile_lookup_str_vec(file
, &game
.server
.ruledit
.embedded_nations_count
,
4255 "ruledit.embedded_nations");
4258 /* Copy to persistent vector */
4259 game
.server
.ruledit
.embedded_nations
4260 = fc_malloc(game
.server
.ruledit
.embedded_nations_count
* sizeof(char *));
4262 for (j
= 0; j
< game
.server
.ruledit
.embedded_nations_count
; j
++) {
4263 game
.server
.ruledit
.embedded_nations
[j
] = fc_strdup(vec
[j
]);
4269 game
.default_government
= NULL
;
4271 ruleset_load_traits(game
.server
.default_traits
, file
, "default_traits", "");
4272 for (tr
= trait_begin(); tr
!= trait_end(); tr
= trait_next(tr
)) {
4273 if (game
.server
.default_traits
[tr
].min
< 0) {
4274 game
.server
.default_traits
[tr
].min
= TRAIT_DEFAULT_VALUE
;
4276 if (game
.server
.default_traits
[tr
].max
< 0) {
4277 game
.server
.default_traits
[tr
].max
= TRAIT_DEFAULT_VALUE
;
4279 if (game
.server
.default_traits
[tr
].fixed
< 0) {
4280 int diff
= game
.server
.default_traits
[tr
].max
- game
.server
.default_traits
[tr
].min
;
4282 /* TODO: Should sometimes round the a / 2 = x.5 results up */
4283 game
.server
.default_traits
[tr
].fixed
= diff
/ 2 + game
.server
.default_traits
[tr
].min
;
4285 if (game
.server
.default_traits
[tr
].max
< game
.server
.default_traits
[tr
].min
) {
4286 ruleset_error(LOG_ERROR
, "Default values for trait %s not sane.",
4294 vec
= secfile_lookup_str_vec(file
, &game
.server
.ruledit
.ag_count
,
4295 "compatibility.allowed_govs");
4297 /* Copy to persistent vector */
4298 game
.server
.ruledit
.nc_agovs
4299 = fc_malloc(game
.server
.ruledit
.ag_count
* sizeof(char *));
4300 game
.server
.ruledit
.allowed_govs
=
4301 (const char **)game
.server
.ruledit
.nc_agovs
;
4303 for (j
= 0; j
< game
.server
.ruledit
.ag_count
; j
++) {
4304 game
.server
.ruledit
.allowed_govs
[j
] = fc_strdup(vec
[j
]);
4310 vec
= secfile_lookup_str_vec(file
, &game
.server
.ruledit
.at_count
,
4311 "compatibility.allowed_terrains");
4313 /* Copy to persistent vector */
4314 game
.server
.ruledit
.nc_aterrs
4315 = fc_malloc(game
.server
.ruledit
.at_count
* sizeof(char *));
4316 game
.server
.ruledit
.allowed_terrains
=
4317 (const char **)game
.server
.ruledit
.nc_aterrs
;
4319 for (j
= 0; j
< game
.server
.ruledit
.at_count
; j
++) {
4320 game
.server
.ruledit
.allowed_terrains
[j
] = fc_strdup(vec
[j
]);
4326 vec
= secfile_lookup_str_vec(file
, &game
.server
.ruledit
.as_count
,
4327 "compatibility.allowed_styles");
4329 /* Copy to persistent vector */
4330 game
.server
.ruledit
.nc_astyles
4331 = fc_malloc(game
.server
.ruledit
.as_count
* sizeof(char *));
4332 game
.server
.ruledit
.allowed_styles
=
4333 (const char **)game
.server
.ruledit
.nc_astyles
;
4335 for (j
= 0; j
< game
.server
.ruledit
.as_count
; j
++) {
4336 game
.server
.ruledit
.allowed_styles
[j
] = fc_strdup(vec
[j
]);
4342 sval
= secfile_lookup_str_default(file
, NULL
,
4343 "compatibility.default_government");
4344 /* We deliberately don't check this against allowed_govs. It's only
4345 * specified once so not vulnerable to typos, and may usefully be set in
4346 * a specific ruleset to a gov not explicitly known by the nation set. */
4348 game
.default_government
= government_by_rule_name(sval
);
4349 if (game
.default_government
== NULL
) {
4350 ruleset_error(LOG_ERROR
,
4351 "Tried to set unknown government type \"%s\" as default_government!",
4355 game
.info
.default_government_id
4356 = government_number(game
.default_government
);
4362 sec
= secfile_sections_by_name_prefix(file
, NATION_SET_SECTION_PREFIX
);
4364 section_list_iterate(sec
, psection
) {
4365 const char *set_name
, *set_rule_name
, *set_description
;
4367 set_name
= secfile_lookup_str(file
, "%s.name", section_name(psection
));
4369 secfile_lookup_str(file
, "%s.rule_name", section_name(psection
));
4370 set_description
= secfile_lookup_str_default(file
, "", "%s.description",
4371 section_name(psection
));
4372 if (NULL
== set_name
|| NULL
== set_rule_name
) {
4373 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
4377 if (nation_set_new(set_name
, set_rule_name
, set_description
) == NULL
) {
4381 } section_list_iterate_end
;
4382 section_list_destroy(sec
);
4385 ruleset_error(LOG_ERROR
,
4386 "At least one nation set [" NATION_SET_SECTION_PREFIX
"_*] "
4387 "must be defined.");
4393 /* Default set that every nation is a member of. */
4394 sval
= secfile_lookup_str_default(file
, NULL
,
4395 "compatibility.default_nationset");
4397 const struct nation_set
*pset
= nation_set_by_rule_name(sval
);
4399 default_set
= nation_set_number(pset
);
4401 ruleset_error(LOG_ERROR
,
4402 "Unknown default_nationset \"%s\".", sval
);
4405 } else if (nation_set_count() == 1) {
4406 /* If there's only one set defined, every nation is implicitly a
4407 * member of that set. */
4410 /* No default nation set; every nation must explicitly specify at
4411 * least one set to be a member of. */
4417 sec
= secfile_sections_by_name_prefix(file
, NATION_GROUP_SECTION_PREFIX
);
4419 section_list_iterate(sec
, psection
) {
4420 struct nation_group
*pgroup
;
4423 name
= secfile_lookup_str(file
, "%s.name", section_name(psection
));
4424 pgroup
= nation_group_by_rule_name(name
);
4425 if (pgroup
== NULL
) {
4430 hidden
= secfile_lookup_bool_default(file
, FALSE
, "%s.hidden",
4431 section_name(psection
));
4432 nation_group_set_hidden(pgroup
, hidden
);
4434 if (!secfile_lookup_int(file
, &j
, "%s.match", section_name(psection
))) {
4435 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
4439 nation_group_set_match(pgroup
, j
);
4440 } section_list_iterate_end
;
4441 section_list_destroy(sec
);
4447 sec
= secfile_sections_by_name_prefix(file
, NATION_SECTION_PREFIX
);
4448 nations_iterate(pnation
) {
4449 struct nation_type
*pconflict
;
4450 const int i
= nation_index(pnation
);
4451 char tmp
[200] = "\0";
4452 const char *barb_type
;
4453 const char *sec_name
= section_name(section_list_get(sec
, i
));
4456 /* Nation sets and groups. */
4457 if (default_set
>= 0) {
4458 nation_set_list_append(pnation
->sets
,
4459 nation_set_by_number(default_set
));
4461 vec
= secfile_lookup_str_vec(file
, &dim
, "%s.groups", sec_name
);
4462 for (j
= 0; j
< dim
; j
++) {
4463 struct nation_set
*pset
= nation_set_by_rule_name(vec
[j
]);
4464 struct nation_group
*pgroup
= nation_group_by_rule_name(vec
[j
]);
4466 fc_assert(pset
== NULL
|| pgroup
== NULL
);
4469 nation_set_list_append(pnation
->sets
, pset
);
4470 } else if (NULL
!= pgroup
) {
4471 nation_group_list_append(pnation
->groups
, pgroup
);
4473 /* For nation authors, this would probably be considered an error.
4474 * But it can happen normally. The civ1 compatibility ruleset only
4475 * uses the nations that were in civ1, so not all of the links will
4477 log_verbose("Nation %s: Unknown set/group \"%s\".",
4478 nation_rule_name(pnation
), vec
[j
]);
4484 if (nation_set_list_size(pnation
->sets
) < 1) {
4485 ruleset_error(LOG_ERROR
,
4486 "Nation %s is not a member of any nation set",
4487 nation_rule_name(pnation
));
4492 /* Nation conflicts. */
4493 vec
= secfile_lookup_str_vec(file
, &dim
, "%s.conflicts_with", sec_name
);
4494 for (j
= 0; j
< dim
; j
++) {
4495 pconflict
= nation_by_rule_name(vec
[j
]);
4497 if (pnation
== pconflict
) {
4498 ruleset_error(LOG_ERROR
, "Nation %s conflicts with itself",
4499 nation_rule_name(pnation
));
4502 } else if (NULL
!= pconflict
) {
4503 nation_list_append(pnation
->server
.conflicts_with
, pconflict
);
4505 /* For nation authors, this would probably be considered an error.
4506 * But it can happen normally. The civ1 compatibility ruleset only
4507 * uses the nations that were in civ1, so not all of the links will
4509 log_verbose("Nation %s: conflicts_with nation \"%s\" is unknown.",
4510 nation_rule_name(pnation
), vec
[j
]);
4520 /* Nation leaders. */
4521 for (j
= 0; j
< MAX_NUM_LEADERS
; j
++) {
4523 bool is_male
= FALSE
;
4525 name
= secfile_lookup_str(file
, "%s.leaders%d.name", sec_name
, j
);
4527 /* No more to read. */
4531 if (check_name(name
)) {
4532 /* The ruleset contains a name that is too long. This shouldn't
4533 * happen - if it does, the author should get immediate feedback */
4534 sz_strlcpy(temp_name
, name
);
4535 ruleset_error(LOG_ERROR
, "Nation %s: leader name \"%s\" "
4537 nation_rule_name(pnation
), name
);
4542 sex
= secfile_lookup_str(file
, "%s.leaders%d.sex", sec_name
, j
);
4544 ruleset_error(LOG_ERROR
, "Nation %s: leader \"%s\": %s.",
4545 nation_rule_name(pnation
), name
, secfile_error());
4548 } else if (0 == fc_strcasecmp("Male", sex
)) {
4550 } else if (0 != fc_strcasecmp("Female", sex
)) {
4551 ruleset_error(LOG_ERROR
, "Nation %s: leader \"%s\" has unsupported "
4552 "sex variant \"%s\".",
4553 nation_rule_name(pnation
), name
, sex
);
4557 (void) nation_leader_new(pnation
, name
, is_male
);
4563 /* Check the number of leaders. */
4564 if (MAX_NUM_LEADERS
== j
) {
4565 /* Too much leaders, get the real number defined in the ruleset. */
4566 while (NULL
!= secfile_entry_lookup(file
, "%s.leaders%d.name",
4570 ruleset_error(LOG_ERROR
, "Nation %s: Too many leaders; max is %d",
4571 nation_rule_name(pnation
), MAX_NUM_LEADERS
);
4574 } else if (0 == j
) {
4575 ruleset_error(LOG_ERROR
,
4576 "Nation %s: no leaders; at least one is required.",
4577 nation_rule_name(pnation
));
4582 /* Check if leader name is not already defined in this nation. */
4583 if ((bad_leader
= check_leader_names(pnation
))) {
4584 ruleset_error(LOG_ERROR
,
4585 "Nation %s: leader \"%s\" defined more than once.",
4586 nation_rule_name(pnation
), bad_leader
);
4591 /* Nation player color preference, if any */
4592 fc_assert_ret_val(pnation
->server
.rgb
== NULL
, FALSE
);
4593 (void) rgbcolor_load(file
, &pnation
->server
.rgb
, "%s.color", sec_name
);
4595 /* Load nation traits */
4596 ruleset_load_traits(pnation
->server
.traits
, file
, sec_name
, "trait_");
4597 for (tr
= trait_begin(); tr
!= trait_end(); tr
= trait_next(tr
)) {
4598 bool server_traits_used
= TRUE
;
4600 if (pnation
->server
.traits
[tr
].min
< 0) {
4601 pnation
->server
.traits
[tr
].min
= game
.server
.default_traits
[tr
].min
;
4603 server_traits_used
= FALSE
;
4605 if (pnation
->server
.traits
[tr
].max
< 0) {
4606 pnation
->server
.traits
[tr
].max
= game
.server
.default_traits
[tr
].max
;
4608 server_traits_used
= FALSE
;
4610 if (pnation
->server
.traits
[tr
].fixed
< 0) {
4611 if (server_traits_used
) {
4612 pnation
->server
.traits
[tr
].fixed
= game
.server
.default_traits
[tr
].fixed
;
4614 int diff
= pnation
->server
.traits
[tr
].max
- pnation
->server
.traits
[tr
].min
;
4616 /* TODO: Should sometimes round the a / 2 = x.5 results up */
4617 pnation
->server
.traits
[tr
].fixed
= diff
/ 2 + pnation
->server
.traits
[tr
].min
;
4620 if (pnation
->server
.traits
[tr
].max
< pnation
->server
.traits
[tr
].min
) {
4621 ruleset_error(LOG_ERROR
, "%s values for trait %s not sane.",
4622 nation_rule_name(pnation
), trait_name(tr
));
4632 pnation
->is_playable
=
4633 secfile_lookup_bool_default(file
, TRUE
, "%s.is_playable", sec_name
);
4635 /* Check barbarian type. Default is "None" meaning not a barbarian */
4636 barb_type
= secfile_lookup_str_default(file
, "None",
4637 "%s.barbarian_type", sec_name
);
4638 pnation
->barb_type
= barbarian_type_by_name(barb_type
, fc_strcasecmp
);
4639 if (!barbarian_type_is_valid(pnation
->barb_type
)) {
4640 ruleset_error(LOG_ERROR
,
4641 "Nation %s, barbarian_type is invalid (\"%s\")",
4642 nation_rule_name(pnation
), barb_type
);
4647 if (pnation
->barb_type
!= NOT_A_BARBARIAN
4648 && pnation
->is_playable
) {
4649 /* We can't allow players to use barbarian nations, barbarians
4650 * may run out of nations */
4651 ruleset_error(LOG_ERROR
,
4652 "Nation %s marked both barbarian and playable.",
4653 nation_rule_name(pnation
));
4659 sz_strlcpy(pnation
->flag_graphic_str
,
4660 secfile_lookup_str_default(file
, "-", "%s.flag", sec_name
));
4661 sz_strlcpy(pnation
->flag_graphic_alt
,
4662 secfile_lookup_str_default(file
, "-",
4663 "%s.flag_alt", sec_name
));
4667 const char *male
, *female
;
4669 name
= secfile_lookup_str_default(file
, NULL
,
4670 "%s.ruler_titles%d.government",
4673 /* End of the list of ruler titles. */
4677 /* NB: even if the government doesn't exist, we load the entries for
4678 * the ruler titles to avoid warnings about unused entries. */
4679 male
= secfile_lookup_str(file
, "%s.ruler_titles%d.male_title",
4681 female
= secfile_lookup_str(file
, "%s.ruler_titles%d.female_title",
4683 gov
= government_by_rule_name(name
);
4685 /* Nationset may have been devised with a specific set of govs in
4686 * mind which don't quite match this ruleset, in which case we
4687 * (a) quietly ignore any govs mentioned that don't happen to be in
4688 * the current ruleset, (b) enforce that govs mentioned by nations
4689 * must be on the list */
4690 if (gov
!= NULL
&& game
.server
.ruledit
.allowed_govs
!= NULL
) {
4691 if (!is_on_allowed_list(name
,
4692 game
.server
.ruledit
.allowed_govs
,
4693 game
.server
.ruledit
.ag_count
)) {
4694 /* Gov exists, but not intended for these nations */
4696 ruleset_error(LOG_ERROR
,
4697 "Nation %s: government \"%s\" not in allowed_govs.",
4698 nation_rule_name(pnation
), name
);
4703 /* Gov doesn't exist; only complain if it's not on any list */
4704 if (game
.server
.ruledit
.allowed_govs
== NULL
4705 || !is_on_allowed_list(name
,
4706 game
.server
.ruledit
.allowed_govs
,
4707 game
.server
.ruledit
.ag_count
)) {
4708 ruleset_error(LOG_ERROR
, "Nation %s: government \"%s\" not found.",
4709 nation_rule_name(pnation
), name
);
4714 if (NULL
!= male
&& NULL
!= female
) {
4716 (void) government_ruler_title_new(gov
, pnation
, male
, female
);
4719 ruleset_error(LOG_ERROR
, "%s", secfile_error());
4729 name
= secfile_lookup_str(file
, "%s.style", sec_name
);
4731 ruleset_error(LOG_ERROR
, "%s", secfile_error());
4735 pnation
->style
= style_by_rule_name(name
);
4736 if (pnation
->style
== NULL
) {
4737 if (game
.server
.ruledit
.allowed_styles
== NULL
4738 || !is_on_allowed_list(name
,
4739 game
.server
.ruledit
.allowed_styles
,
4740 game
.server
.ruledit
.as_count
)) {
4741 ruleset_error(LOG_ERROR
, "Nation %s: Illegal style \"%s\"",
4742 nation_rule_name(pnation
), name
);
4746 log_verbose("Nation %s: style \"%s\" not supported in this "
4747 "ruleset; using default.",
4748 nation_rule_name(pnation
), name
);
4749 pnation
->style
= style_by_number(0);
4753 /* Civilwar nations */
4754 vec
= secfile_lookup_str_vec(file
, &dim
,
4755 "%s.civilwar_nations", sec_name
);
4756 for (j
= 0; j
< dim
; j
++) {
4757 pconflict
= nation_by_rule_name(vec
[j
]);
4759 /* No test for duplicate nations is performed. If there is a duplicate
4760 * entry it will just cause that nation to have an increased
4761 * probability of being chosen. */
4762 if (pconflict
== pnation
) {
4763 ruleset_error(LOG_ERROR
, "Nation %s is its own civil war nation",
4764 nation_rule_name(pnation
));
4767 } else if (NULL
!= pconflict
) {
4768 nation_list_append(pnation
->server
.civilwar_nations
, pconflict
);
4769 nation_list_append(pconflict
->server
.parent_nations
, pnation
);
4771 /* For nation authors, this would probably be considered an error.
4772 * But it can happen normally. The civ1 compatability ruleset only
4773 * uses the nations that were in civ1, so not all of the links will
4775 log_verbose("Nation %s: civil war nation \"%s\" is unknown.",
4776 nation_rule_name(pnation
), vec
[j
]);
4786 /* Load nation specific initial items */
4787 if (!lookup_tech_list(file
, sec_name
, "init_techs",
4788 pnation
->init_techs
, filename
)) {
4792 if (!lookup_building_list(file
, sec_name
, "init_buildings",
4793 pnation
->init_buildings
, filename
)) {
4797 if (!lookup_unit_list(file
, sec_name
, "init_units",
4798 pnation
->init_units
, filename
)) {
4802 fc_strlcat(tmp
, sec_name
, 200);
4803 fc_strlcat(tmp
, ".init_government", 200);
4804 if (secfile_entry_by_path(file
, tmp
)) {
4805 pnation
->init_government
= lookup_government(file
, tmp
, filename
,
4807 /* If specified, init_government has to be in this specific ruleset,
4808 * not just allowed_govs */
4809 if (pnation
->init_government
== NULL
) {
4813 /* ...but if a list of govs has been specified, enforce that this
4814 * nation's init_government is on the list. */
4815 if (game
.server
.ruledit
.allowed_govs
!= NULL
4816 && !is_on_allowed_list(government_rule_name(pnation
->init_government
),
4817 game
.server
.ruledit
.allowed_govs
,
4818 game
.server
.ruledit
.ag_count
)) {
4819 ruleset_error(LOG_ERROR
,
4820 "Nation %s: init_government \"%s\" not allowed.",
4821 nation_rule_name(pnation
),
4822 government_rule_name(pnation
->init_government
));
4828 /* Read default city names. */
4829 if (!load_city_name_list(file
, pnation
, sec_name
, "cities",
4830 game
.server
.ruledit
.allowed_terrains
,
4831 game
.server
.ruledit
.at_count
)) {
4836 legend
= secfile_lookup_str_default(file
, "", "%s.legend", sec_name
);
4837 pnation
->legend
= fc_strdup(legend
);
4838 if (check_strlen(pnation
->legend
, MAX_LEN_MSG
, NULL
)) {
4839 ruleset_error(LOG_ERROR
,
4840 "Nation %s: legend \"%s\" is too long.",
4841 nation_rule_name(pnation
),
4847 pnation
->player
= NULL
;
4848 } nations_iterate_end
;
4849 section_list_destroy(sec
);
4853 /* Clean up on aborted load */
4856 section_list_destroy(sec
);
4860 secfile_check_unused(file
);
4864 /* Update cached number of playable nations in the current set */
4865 count_playable_nations();
4867 /* Sanity checks on all sets */
4868 nation_sets_iterate(pset
) {
4869 int num_playable
= 0, barb_land_count
= 0, barb_sea_count
= 0, barb_both_count
= 0;
4871 nations_iterate(pnation
) {
4872 if (nation_is_in_set(pnation
, pset
)) {
4873 switch (nation_barbarian_type(pnation
)) {
4874 case NOT_A_BARBARIAN
:
4875 if (is_nation_playable(pnation
)) {
4879 case LAND_BARBARIAN
:
4885 case ANIMAL_BARBARIAN
:
4886 /* Animals are optional */
4888 case LAND_AND_SEA_BARBARIAN
:
4892 fc_assert_ret_val(FALSE
, FALSE
);
4895 } nations_iterate_end
;
4896 if (num_playable
< 1) {
4897 ruleset_error(LOG_ERROR
,
4898 "Nation set \"%s\" has no playable nations. "
4899 "At least one required!", nation_set_rule_name(pset
));
4903 if (barb_land_count
== 0 && barb_both_count
== 0) {
4904 ruleset_error(LOG_ERROR
,
4905 "No land barbarian nation defined in set \"%s\". "
4906 "At least one required!", nation_set_rule_name(pset
));
4910 if (barb_sea_count
== 0 && barb_both_count
== 0) {
4911 ruleset_error(LOG_ERROR
,
4912 "No sea barbarian nation defined in set \"%s\". "
4913 "At least one required!", nation_set_rule_name(pset
));
4917 } nation_sets_iterate_end
;
4923 /**************************************************************************
4924 Load names of nation styles so other rulesets can refer to styles with
4926 **************************************************************************/
4927 static bool load_style_names(struct section_file
*file
,
4928 struct rscompat_info
*compat
)
4931 struct section_list
*sec
;
4932 const char *filename
= secfile_name(file
);
4934 compat
->ver_styles
= rscompat_check_capabilities(file
, filename
, compat
);
4935 if (compat
->ver_styles
<= 0) {
4939 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
4940 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
4942 sec
= secfile_sections_by_name_prefix(file
, STYLE_SECTION_PREFIX
);
4944 ruleset_error(LOG_ERROR
, "No available nation styles in this ruleset!");
4947 game
.control
.num_styles
= section_list_size(sec
);
4949 styles_alloc(game
.control
.num_styles
);
4951 styles_iterate(ps
) {
4952 const int i
= style_index(ps
);
4953 const char *sec_name
= section_name(section_list_get(sec
, i
));
4955 ruleset_load_names(&ps
->name
, NULL
, file
, sec_name
);
4956 } styles_iterate_end
;
4959 section_list_destroy(sec
);
4962 /* The citystyle sections: */
4965 sec
= secfile_sections_by_name_prefix(file
, CITYSTYLE_SECTION_PREFIX
);
4967 city_styles_alloc(section_list_size(sec
));
4968 section_list_iterate(sec
, style
) {
4969 if (!ruleset_load_names(&city_styles
[i
].name
, NULL
, file
, section_name(style
))) {
4974 } section_list_iterate_end
;
4976 section_list_destroy(sec
);
4978 city_styles_alloc(0);
4985 /**************************************************************************
4986 Load styles.ruleset file
4987 **************************************************************************/
4988 static bool load_ruleset_styles(struct section_file
*file
,
4989 struct rscompat_info
*compat
)
4991 struct section_list
*sec
;
4995 /* City Styles ... */
4997 sec
= secfile_sections_by_name_prefix(file
, CITYSTYLE_SECTION_PREFIX
);
5000 for (i
= 0; i
< game
.control
.styles_count
; i
++) {
5001 struct requirement_vector
*reqs
;
5002 const char *sec_name
= section_name(section_list_get(sec
, i
));
5004 sz_strlcpy(city_styles
[i
].graphic
,
5005 secfile_lookup_str(file
, "%s.graphic", sec_name
));
5006 sz_strlcpy(city_styles
[i
].graphic_alt
,
5007 secfile_lookup_str(file
, "%s.graphic_alt", sec_name
));
5008 sz_strlcpy(city_styles
[i
].citizens_graphic
,
5009 secfile_lookup_str_default(file
, "-",
5010 "%s.citizens_graphic", sec_name
));
5011 sz_strlcpy(city_styles
[i
].citizens_graphic_alt
,
5012 secfile_lookup_str_default(file
, "generic",
5013 "%s.citizens_graphic_alt", sec_name
));
5015 reqs
= lookup_req_list(file
, compat
, sec_name
, "reqs", city_style_rule_name(i
));
5020 requirement_vector_copy(&city_styles
[i
].reqs
, reqs
);
5023 section_list_destroy(sec
);
5026 sec
= secfile_sections_by_name_prefix(file
, MUSICSTYLE_SECTION_PREFIX
);
5031 game
.control
.num_music_styles
= section_list_size(sec
);
5032 music_styles_alloc(game
.control
.num_music_styles
);
5035 section_list_iterate(sec
, psection
) {
5036 struct requirement_vector
*reqs
;
5037 struct music_style
*pmus
= music_style_by_number(musi
);
5038 const char *sec_name
= section_name(psection
);
5040 sz_strlcpy(pmus
->music_peaceful
,
5041 secfile_lookup_str_default(file
, "-",
5042 "%s.music_peaceful", sec_name
));
5043 sz_strlcpy(pmus
->music_combat
,
5044 secfile_lookup_str_default(file
, "-",
5045 "%s.music_combat", sec_name
));
5047 reqs
= lookup_req_list(file
, compat
, sec_name
, "reqs", "Music Style");
5052 requirement_vector_copy(&pmus
->reqs
, reqs
);
5055 } section_list_iterate_end
;
5058 section_list_destroy(sec
);
5064 /**************************************************************************
5065 Load a list of unit type flags that must be absent from the actor unit
5066 if an action auto performer should be triggered into an action auto
5068 **************************************************************************/
5069 static bool load_action_auto_uflag_block(struct section_file
*file
,
5070 struct action_auto_perf
*auto_perf
,
5071 const char *uflags_path
,
5072 const char *filename
)
5074 /* Add each listed protected unit type flag as a !present
5076 if (secfile_entry_lookup(file
, "%s", uflags_path
)) {
5077 enum unit_type_flag_id
*protecor_flag
;
5082 secfile_lookup_enum_vec(file
, &psize
, unit_type_flag_id
,
5085 if (!protecor_flag
) {
5086 /* Entity exists but couldn't read it. */
5087 ruleset_error(LOG_ERROR
,
5088 "\"%s\": %s: bad unit type flag list.",
5089 filename
, uflags_path
);
5094 for (i
= 0; i
< psize
; i
++) {
5095 requirement_vector_append(&auto_perf
->reqs
,
5096 req_from_values(VUT_UTFLAG
,
5102 free(protecor_flag
);
5108 /**************************************************************************
5109 Load the list of actions an action auto performer should try. The
5110 actions will be tried in the given order.
5111 **************************************************************************/
5112 static bool load_action_auto_actions(struct section_file
*file
,
5113 struct action_auto_perf
*auto_perf
,
5114 const char *actions_path
,
5115 const char *filename
)
5117 /* Read the alternative actions. */
5118 if (secfile_entry_lookup(file
, "%s", actions_path
)) {
5119 enum gen_action
*unit_acts
;
5123 unit_acts
= secfile_lookup_enum_vec(file
, &asize
, gen_action
,
5124 "%s", actions_path
);
5127 /* Entity exists but couldn't read it. */
5128 ruleset_error(LOG_ERROR
,
5129 "\"%s\": %s: bad action list",
5130 filename
, actions_path
);
5135 for (i
= 0; i
< asize
; i
++) {
5136 auto_perf
->alternatives
[i
] = unit_acts
[i
];
5145 /**************************************************************************
5146 Load missing unit upkeep ruleset settings as action auto performers.
5147 **************************************************************************/
5148 static bool load_muuk_as_action_auto(struct section_file
*file
,
5149 struct action_auto_perf
*auto_perf
,
5151 const char *filename
)
5153 char uflags_path
[100];
5154 char action_path
[100];
5156 fc_snprintf(uflags_path
, sizeof(uflags_path
),
5157 "missing_unit_upkeep.%s_protected", item
);
5158 fc_snprintf(action_path
, sizeof(action_path
),
5159 "missing_unit_upkeep.%s_unit_act", item
);
5161 return (load_action_auto_uflag_block(file
, auto_perf
, uflags_path
,
5163 && load_action_auto_actions(file
, auto_perf
, action_path
,
5167 /**************************************************************************
5168 Load cities.ruleset file
5169 **************************************************************************/
5170 static bool load_ruleset_cities(struct section_file
*file
,
5171 struct rscompat_info
*compat
)
5173 const char *filename
= secfile_name(file
);
5175 struct section_list
*sec
;
5178 compat
->ver_cities
= rscompat_check_capabilities(file
, filename
, compat
);
5179 if (compat
->ver_cities
<= 0) {
5183 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
5184 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
5186 /* Specialist options */
5187 sec
= secfile_sections_by_name_prefix(file
, SPECIALIST_SECTION_PREFIX
);
5188 if (section_list_size(sec
) >= SP_MAX
) {
5189 ruleset_error(LOG_ERROR
, "\"%s\": Too many specialists (%d, max %d).",
5190 filename
, section_list_size(sec
), SP_MAX
);
5197 game
.control
.num_specialist_types
= section_list_size(sec
);
5199 section_list_iterate(sec
, psection
) {
5200 struct specialist
*s
= specialist_by_number(i
);
5201 struct requirement_vector
*reqs
;
5202 const char *sec_name
= section_name(psection
);
5204 if (!ruleset_load_names(&s
->name
, NULL
, file
, sec_name
)) {
5209 item
= secfile_lookup_str_default(file
, untranslated_name(&s
->name
),
5210 "%s.short_name", sec_name
);
5211 name_set(&s
->abbreviation
, NULL
, item
);
5213 sz_strlcpy(s
->graphic_alt
,
5214 secfile_lookup_str_default(file
, "-",
5215 "%s.graphic_alt", sec_name
));
5217 reqs
= lookup_req_list(file
, compat
, sec_name
, "reqs", specialist_rule_name(s
));
5222 requirement_vector_copy(&s
->reqs
, reqs
);
5224 s
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
5226 if (requirement_vector_size(&s
->reqs
) == 0 && DEFAULT_SPECIALIST
== -1) {
5227 DEFAULT_SPECIALIST
= i
;
5230 } section_list_iterate_end
;
5233 if (ok
&& DEFAULT_SPECIALIST
== -1) {
5234 ruleset_error(LOG_ERROR
,
5235 "\"%s\": must give a min_size of 0 for at least one "
5236 "specialist type.", filename
);
5239 section_list_destroy(sec
);
5243 /* City Parameters */
5245 game
.info
.celebratesize
=
5246 secfile_lookup_int_default(file
, GAME_DEFAULT_CELEBRATESIZE
,
5247 "parameters.celebrate_size_limit");
5248 game
.info
.add_to_size_limit
=
5249 secfile_lookup_int_default(file
, GAME_DEFAULT_ADDTOSIZE
, "parameters.add_to_size_limit");
5250 game
.info
.angrycitizen
=
5251 secfile_lookup_bool_default(file
, GAME_DEFAULT_ANGRYCITIZEN
,
5252 "parameters.angry_citizens");
5254 game
.info
.changable_tax
=
5255 secfile_lookup_bool_default(file
, GAME_DEFAULT_CHANGABLE_TAX
, "parameters.changable_tax");
5256 game
.info
.forced_science
=
5257 secfile_lookup_int_default(file
, 0, "parameters.forced_science");
5258 game
.info
.forced_luxury
=
5259 secfile_lookup_int_default(file
, 100, "parameters.forced_luxury");
5260 game
.info
.forced_gold
=
5261 secfile_lookup_int_default(file
, 0, "parameters.forced_gold");
5262 if (game
.info
.forced_science
+ game
.info
.forced_luxury
5263 + game
.info
.forced_gold
!= 100) {
5264 ruleset_error(LOG_ERROR
,
5265 "\"%s\": Forced taxes do not add up in ruleset!",
5272 /* civ1 & 2 didn't reveal tiles */
5273 game
.server
.vision_reveal_tiles
=
5274 secfile_lookup_bool_default(file
, GAME_DEFAULT_VISION_REVEAL_TILES
,
5275 "parameters.vision_reveal_tiles");
5277 game
.info
.pop_report_zeroes
=
5278 secfile_lookup_int_default(file
, 1, "parameters.pop_report_zeroes");
5280 /* Citizens configuration. */
5281 game
.info
.citizen_nationality
=
5282 secfile_lookup_bool_default(file
, GAME_DEFAULT_NATIONALITY
,
5283 "citizen.nationality");
5284 game
.info
.citizen_convert_speed
=
5285 secfile_lookup_int_default(file
, GAME_DEFAULT_CONVERT_SPEED
,
5286 "citizen.convert_speed");
5287 game
.info
.citizen_partisans_pct
=
5288 secfile_lookup_int_default(file
, 0, "citizen.partisans_pct");
5292 /* Missing unit upkeep. */
5293 struct action_auto_perf
*auto_perf
;
5295 /* Can't pay food upkeep! */
5296 auto_perf
= action_auto_perf_slot_number(ACTION_AUTO_UPKEEP_FOOD
);
5297 auto_perf
->cause
= AAPC_UNIT_UPKEEP
;
5299 /* This is about food upkeep. */
5300 requirement_vector_append(&auto_perf
->reqs
,
5301 req_from_str("OutputType", "Local",
5305 /* Internally represented as an action auto performer rule. */
5306 if (!load_muuk_as_action_auto(file
, auto_perf
, "food", filename
)) {
5310 game
.info
.muuk_food_wipe
=
5311 secfile_lookup_bool_default(file
, RS_DEFAULT_MUUK_FOOD_WIPE
,
5312 "missing_unit_upkeep.food_wipe");
5314 /* Can't pay gold upkeep! */
5315 auto_perf
= action_auto_perf_slot_number(ACTION_AUTO_UPKEEP_GOLD
);
5316 auto_perf
->cause
= AAPC_UNIT_UPKEEP
;
5318 /* This is about gold upkeep. */
5319 requirement_vector_append(&auto_perf
->reqs
,
5320 req_from_str("OutputType", "Local",
5324 /* Internally represented as an action auto performer rule. */
5325 if (!load_muuk_as_action_auto(file
, auto_perf
, "gold", filename
)) {
5329 game
.info
.muuk_gold_wipe
=
5330 secfile_lookup_bool_default(file
, RS_DEFAULT_MUUK_GOLD_WIPE
,
5331 "missing_unit_upkeep.gold_wipe");
5333 /* Can't pay shield upkeep! */
5334 auto_perf
= action_auto_perf_slot_number(ACTION_AUTO_UPKEEP_SHIELD
);
5335 auto_perf
->cause
= AAPC_UNIT_UPKEEP
;
5337 /* This is about shield upkeep. */
5338 requirement_vector_append(&auto_perf
->reqs
,
5339 req_from_str("OutputType", "Local",
5343 /* Internally represented as an action auto performer rule. */
5344 if (!load_muuk_as_action_auto(file
, auto_perf
, "shield", filename
)) {
5348 game
.info
.muuk_shield_wipe
=
5349 secfile_lookup_bool_default(file
, RS_DEFAULT_MUUK_SHIELD_WIPE
,
5350 "missing_unit_upkeep.shield_wipe");
5354 secfile_check_unused(file
);
5360 /**************************************************************************
5361 Load effects.ruleset file
5362 **************************************************************************/
5363 static bool load_ruleset_effects(struct section_file
*file
,
5364 struct rscompat_info
*compat
)
5366 struct section_list
*sec
;
5368 const char *filename
;
5370 bool effect_type_warned
= FALSE
;
5372 filename
= secfile_name(file
);
5374 compat
->ver_effects
= rscompat_check_capabilities(file
, filename
, compat
);
5375 if (compat
->ver_effects
<= 0) {
5378 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
5379 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
5381 /* Parse effects and add them to the effects ruleset cache. */
5382 sec
= secfile_sections_by_name_prefix(file
, EFFECT_SECTION_PREFIX
);
5383 section_list_iterate(sec
, psection
) {
5384 enum effect_type eff
;
5386 struct multiplier
*pmul
;
5387 struct effect
*peffect
;
5388 const char *sec_name
= section_name(psection
);
5389 struct requirement_vector
*reqs
;
5391 type
= secfile_lookup_str(file
, "%s.type", sec_name
);
5392 if (type
== NULL
&& compat
->compat_mode
) {
5393 /* Backward compatibility. Field used to be named "name" */
5394 type
= secfile_lookup_str(file
, "%s.name", sec_name
);
5395 if (type
!= NULL
&& !effect_type_warned
) {
5396 log_deprecation(_("Effects should have \"type\", not the same field with old name \"name\"."));
5397 effect_type_warned
= TRUE
;
5401 ruleset_error(LOG_ERROR
, "\"%s\" [%s] missing effect type.", filename
, sec_name
);
5406 eff
= effect_type_by_name(type
, fc_strcasecmp
);
5407 if (!effect_type_is_valid(eff
)) {
5408 ruleset_error(LOG_ERROR
, "\"%s\" [%s] lists unknown effect type \"%s\".",
5409 filename
, sec_name
, type
);
5414 value
= secfile_lookup_int_default(file
, 1, "%s.value", sec_name
);
5417 const char *multiplier_name
5418 = secfile_lookup_str(file
, "%s.multiplier", sec_name
);
5420 if (multiplier_name
) {
5421 pmul
= multiplier_by_rule_name(multiplier_name
);
5423 ruleset_error(LOG_ERROR
, "\"%s\" [%s] has unknown multiplier \"%s\".",
5424 filename
, sec_name
, multiplier_name
);
5433 peffect
= effect_new(eff
, value
, pmul
);
5435 reqs
= lookup_req_list(file
, compat
, sec_name
, "reqs", type
);
5441 requirement_vector_iterate(reqs
, preq
) {
5442 effect_req_append(peffect
, *preq
);
5443 } requirement_vector_iterate_end
;
5445 if (compat
->compat_mode
) {
5446 reqs
= lookup_req_list(file
, compat
, sec_name
, "nreqs", type
);
5451 requirement_vector_iterate(reqs
, preq
) {
5452 preq
->present
= !preq
->present
;
5453 effect_req_append(peffect
, *preq
);
5454 } requirement_vector_iterate_end
;
5456 } section_list_iterate_end
;
5457 section_list_destroy(sec
);
5460 secfile_check_unused(file
);
5466 /**************************************************************************
5467 Print an error message if the value is out of range.
5468 **************************************************************************/
5469 static int secfile_lookup_int_default_min_max(struct section_file
*file
,
5470 int def
, int min
, int max
,
5471 const char *path
, ...)
5472 fc__attribute((__format__ (__printf__
, 5, 6)));
5473 static int secfile_lookup_int_default_min_max(struct section_file
*file
,
5474 int def
, int min
, int max
,
5475 const char *path
, ...)
5481 va_start(args
, path
);
5482 fc_vsnprintf(fullpath
, sizeof(fullpath
), path
, args
);
5485 if (!secfile_lookup_int(file
, &ival
, "%s", fullpath
)) {
5490 ruleset_error(LOG_ERROR
,"\"%s\" should be in the interval [%d, %d] "
5491 "but is %d; using the minimal value.",
5492 fullpath
, min
, max
, ival
);
5497 ruleset_error(LOG_ERROR
,"\"%s\" should be in the interval [%d, %d] "
5498 "but is %d; using the maximal value.",
5499 fullpath
, min
, max
, ival
);
5506 /**************************************************************************
5508 **************************************************************************/
5509 static bool load_ruleset_game(struct section_file
*file
, bool act
,
5510 struct rscompat_info
*compat
)
5512 const char *sval
, **svec
;
5513 const char *filename
;
5517 const char *pref_text
;
5519 struct section_list
*sec
;
5527 filename
= secfile_name(file
);
5529 name
= secfile_lookup_str_default(file
, NULL
, "ruledit.description_file");
5531 game
.server
.ruledit
.description_file
= fc_strdup(name
);
5534 /* section: tileset */
5535 pref_text
= secfile_lookup_str_default(file
, "", "tileset.prefered");
5536 if (pref_text
[0] != '\0') {
5537 log_deprecation("Entry tileset.prefered in game.ruleset."
5538 " Use correct spelling tileset.preferred instead");
5540 pref_text
= secfile_lookup_str_default(file
, pref_text
, "tileset.preferred");
5541 if (pref_text
[0] != '\0') {
5542 /* There was tileset suggestion */
5543 sz_strlcpy(game
.control
.preferred_tileset
, pref_text
);
5545 /* No tileset suggestions */
5546 game
.control
.preferred_tileset
[0] = '\0';
5549 /* section: soundset */
5550 pref_text
= secfile_lookup_str_default(file
, "", "soundset.prefered");
5551 if (pref_text
[0] != '\0') {
5552 log_deprecation("Entry soundset.prefered in game.ruleset."
5553 " Use correct spelling soundset.preferred instead");
5555 pref_text
= secfile_lookup_str_default(file
, pref_text
, "soundset.preferred");
5556 if (pref_text
[0] != '\0') {
5557 /* There was soundset suggestion */
5558 sz_strlcpy(game
.control
.preferred_soundset
, pref_text
);
5560 /* No soundset suggestions */
5561 game
.control
.preferred_soundset
[0] = '\0';
5564 /* section: musicset */
5565 pref_text
= secfile_lookup_str_default(file
, "", "musicset.prefered");
5566 if (pref_text
[0] != '\0') {
5567 log_deprecation("Entry musicset.prefered in game.ruleset."
5568 " Use correct spelling musicset.preferred instead");
5570 pref_text
= secfile_lookup_str_default(file
, pref_text
, "musicset.preferred");
5571 if (pref_text
[0] != '\0') {
5572 /* There was musicset suggestion */
5573 sz_strlcpy(game
.control
.preferred_musicset
, pref_text
);
5575 /* No musicset suggestions */
5576 game
.control
.preferred_musicset
[0] = '\0';
5579 /* section: about */
5580 pref_text
= secfile_lookup_str(file
, "about.name");
5581 /* Ruleset/modpack name found */
5582 sz_strlcpy(game
.control
.name
, pref_text
);
5584 pref_text
= secfile_lookup_str_default(file
, "", "about.version");
5585 if (pref_text
[0] != '\0') {
5586 /* Ruleset/modpack version found */
5587 sz_strlcpy(game
.control
.version
, pref_text
);
5589 /* No version information */
5590 game
.control
.version
[0] = '\0';
5593 pref_text
= secfile_lookup_str_default(file
, "", "about.summary");
5594 if (pref_text
[0] != '\0') {
5597 /* Ruleset/modpack summary found */
5598 len
= strlen(pref_text
);
5599 game
.ruleset_summary
= fc_malloc(len
+ 1);
5600 fc_strlcpy(game
.ruleset_summary
, pref_text
, len
+ 1);
5603 if (game
.ruleset_summary
!= NULL
) {
5604 free(game
.ruleset_summary
);
5605 game
.ruleset_summary
= NULL
;
5609 pref_text
= secfile_lookup_str_default(file
, "", "about.description");
5610 if (pref_text
[0] != '\0') {
5613 /* Ruleset/modpack description found */
5614 len
= strlen(pref_text
);
5615 game
.ruleset_description
= fc_malloc(len
+ 1);
5616 fc_strlcpy(game
.ruleset_description
, pref_text
, len
+ 1);
5617 game
.control
.desc_length
= len
;
5619 /* No description */
5620 if (game
.ruleset_description
!= NULL
) {
5621 free(game
.ruleset_description
);
5622 game
.ruleset_description
= NULL
;
5624 game
.control
.desc_length
= 0;
5627 pref_text
= secfile_lookup_str_default(file
, "", "about.capabilities");
5628 if (pref_text
[0] != '\0') {
5629 int len
= strlen(pref_text
);
5631 game
.ruleset_capabilities
= fc_malloc(len
+ 1);
5632 fc_strlcpy(game
.ruleset_capabilities
, pref_text
, len
+1);
5634 game
.ruleset_capabilities
= fc_malloc(1);
5635 game
.ruleset_capabilities
[0] = '\0';
5638 /* section: options */
5639 if (!lookup_tech_list(file
, "options", "global_init_techs",
5640 game
.rgame
.global_init_techs
, filename
)) {
5645 if (!lookup_building_list(file
, "options", "global_init_buildings",
5646 game
.rgame
.global_init_buildings
, filename
)) {
5655 game
.control
.popup_tech_help
= secfile_lookup_bool_default(file
, FALSE
,
5656 "options.popup_tech_help");
5658 /* section: civstyle */
5659 game
.info
.base_pollution
5660 = secfile_lookup_int_default(file
, RS_DEFAULT_BASE_POLLUTION
,
5661 "civstyle.base_pollution");
5663 game
.info
.gameloss_style
= GAMELOSS_STYLE_CLASSICAL
;
5665 slist
= secfile_lookup_str_vec(file
, &nval
, "civstyle.gameloss_style");
5666 for (j
= 0; j
< nval
; j
++) {
5667 enum gameloss_style style
;
5670 if (strcmp(sval
, "") == 0) {
5673 style
= gameloss_style_by_name(sval
, fc_strcasecmp
);
5674 if (!gameloss_style_is_valid(style
)) {
5675 ruleset_error(LOG_ERROR
, "\"%s\": bad value \"%s\" for gameloss_style.",
5680 game
.info
.gameloss_style
|= style
;
5687 game
.info
.happy_cost
5688 = secfile_lookup_int_def_min_max(file
,
5689 RS_DEFAULT_HAPPY_COST
,
5692 "civstyle.happy_cost");
5694 = secfile_lookup_int_default_min_max(file
,
5695 RS_DEFAULT_FOOD_COST
,
5698 "civstyle.food_cost");
5699 game
.info
.civil_war_enabled
5700 = secfile_lookup_bool_default(file
, TRUE
, "civstyle.civil_war_enabled");
5702 game
.info
.paradrop_to_transport
5703 = secfile_lookup_bool_default(file
, FALSE
,
5704 "civstyle.paradrop_to_transport");
5706 /* TODO: move to global_unit_options */
5707 game
.info
.base_bribe_cost
5708 = secfile_lookup_int_default_min_max(file
,
5709 RS_DEFAULT_BASE_BRIBE_COST
,
5710 RS_MIN_BASE_BRIBE_COST
,
5711 RS_MAX_BASE_BRIBE_COST
,
5712 "civstyle.base_bribe_cost");
5713 /* TODO: move to global_unit_options */
5714 game
.server
.ransom_gold
5715 = secfile_lookup_int_default_min_max(file
,
5716 RS_DEFAULT_RANSOM_GOLD
,
5719 "civstyle.ransom_gold");
5720 /* TODO: move to global_unit_options */
5721 game
.info
.pillage_select
5722 = secfile_lookup_bool_default(file
, RS_DEFAULT_PILLAGE_SELECT
,
5723 "civstyle.pillage_select");
5725 game
.info
.tech_steal_allow_holes
5726 = secfile_lookup_bool_default(file
, RS_DEFAULT_TECH_STEAL_HOLES
,
5727 "civstyle.tech_steal_allow_holes");
5728 game
.info
.tech_trade_allow_holes
5729 = secfile_lookup_bool_default(file
, RS_DEFAULT_TECH_TRADE_HOLES
,
5730 "civstyle.tech_trade_allow_holes");
5731 game
.info
.tech_trade_loss_allow_holes
5732 = secfile_lookup_bool_default(file
, RS_DEFAULT_TECH_TRADE_LOSS_HOLES
,
5733 "civstyle.tech_trade_loss_allow_holes");
5734 game
.info
.tech_parasite_allow_holes
5735 = secfile_lookup_bool_default(file
, RS_DEFAULT_TECH_PARASITE_HOLES
,
5736 "civstyle.tech_parasite_allow_holes");
5737 game
.info
.tech_loss_allow_holes
5738 = secfile_lookup_bool_default(file
, RS_DEFAULT_TECH_LOSS_HOLES
,
5739 "civstyle.tech_loss_allow_holes");
5741 /* TODO: move to global_unit_options */
5742 game
.server
.upgrade_veteran_loss
5743 = secfile_lookup_int_default_min_max(file
,
5744 RS_DEFAULT_UPGRADE_VETERAN_LOSS
,
5745 RS_MIN_UPGRADE_VETERAN_LOSS
,
5746 RS_MAX_UPGRADE_VETERAN_LOSS
,
5747 "civstyle.upgrade_veteran_loss");
5748 /* TODO: move to global_unit_options */
5749 game
.server
.autoupgrade_veteran_loss
5750 = secfile_lookup_int_default_min_max(file
,
5751 RS_DEFAULT_UPGRADE_VETERAN_LOSS
,
5752 RS_MIN_UPGRADE_VETERAN_LOSS
,
5753 RS_MAX_UPGRADE_VETERAN_LOSS
,
5754 "civstyle.autoupgrade_veteran_loss");
5756 game
.info
.base_tech_cost
5757 = secfile_lookup_int_default_min_max(file
,
5758 RS_DEFAULT_BASE_TECH_COST
,
5759 RS_MIN_BASE_TECH_COST
,
5760 RS_MAX_BASE_TECH_COST
,
5761 "research.base_tech_cost");
5763 food_ini
= secfile_lookup_int_vec(file
, &gni_tmp
,
5764 "civstyle.granary_food_ini");
5765 game
.info
.granary_num_inis
= (int) gni_tmp
;
5767 if (game
.info
.granary_num_inis
> MAX_GRANARY_INIS
) {
5768 ruleset_error(LOG_ERROR
,
5769 "Too many granary_food_ini entries (%d, max %d)",
5770 game
.info
.granary_num_inis
, MAX_GRANARY_INIS
);
5772 } else if (game
.info
.granary_num_inis
== 0) {
5773 log_error("No values for granary_food_ini. Using default "
5774 "value %d.", RS_DEFAULT_GRANARY_FOOD_INI
);
5775 game
.info
.granary_num_inis
= 1;
5776 game
.info
.granary_food_ini
[0] = RS_DEFAULT_GRANARY_FOOD_INI
;
5780 /* check for <= 0 entries */
5781 for (gi
= 0; gi
< game
.info
.granary_num_inis
; gi
++) {
5782 if (food_ini
[gi
] <= 0) {
5784 food_ini
[gi
] = RS_DEFAULT_GRANARY_FOOD_INI
;
5786 food_ini
[gi
] = food_ini
[gi
- 1];
5788 log_error("Bad value for granary_food_ini[%i]. Using %i.",
5791 game
.info
.granary_food_ini
[gi
] = food_ini
[gi
];
5798 game
.info
.granary_food_inc
5799 = secfile_lookup_int_default_min_max(file
,
5800 RS_DEFAULT_GRANARY_FOOD_INC
,
5801 RS_MIN_GRANARY_FOOD_INC
,
5802 RS_MAX_GRANARY_FOOD_INC
,
5803 "civstyle.granary_food_inc");
5805 output_type_iterate(o
) {
5806 game
.info
.min_city_center_output
[o
]
5807 = secfile_lookup_int_default_min_max(file
,
5808 RS_DEFAULT_CITY_CENTER_OUTPUT
,
5809 RS_MIN_CITY_CENTER_OUTPUT
,
5810 RS_MAX_CITY_CENTER_OUTPUT
,
5811 "civstyle.min_city_center_%s",
5812 get_output_identifier(o
));
5813 } output_type_iterate_end
;
5817 const char *tus_text
;
5819 game
.server
.init_vis_radius_sq
5820 = secfile_lookup_int_default_min_max(file
,
5821 RS_DEFAULT_VIS_RADIUS_SQ
,
5822 RS_MIN_VIS_RADIUS_SQ
,
5823 RS_MAX_VIS_RADIUS_SQ
,
5824 "civstyle.init_vis_radius_sq");
5826 game
.info
.init_city_radius_sq
5827 = secfile_lookup_int_default_min_max(file
,
5828 RS_DEFAULT_CITY_RADIUS_SQ
,
5829 RS_MIN_CITY_RADIUS_SQ
,
5830 RS_MAX_CITY_RADIUS_SQ
,
5831 "civstyle.init_city_radius_sq");
5833 tus_text
= secfile_lookup_str_default(file
, RS_DEFAULT_GOLD_UPKEEP_STYLE
,
5834 "civstyle.gold_upkeep_style");
5835 game
.info
.gold_upkeep_style
= gold_upkeep_style_by_name(tus_text
,
5837 if (!gold_upkeep_style_is_valid(game
.info
.gold_upkeep_style
)) {
5838 ruleset_error(LOG_ERROR
, "Unknown gold upkeep style \"%s\"",
5843 /* section: illness */
5844 game
.info
.illness_on
5845 = secfile_lookup_bool_default(file
, RS_DEFAULT_ILLNESS_ON
,
5846 "illness.illness_on");
5847 game
.info
.illness_base_factor
5848 = secfile_lookup_int_default_min_max(file
,
5849 RS_DEFAULT_ILLNESS_BASE_FACTOR
,
5850 RS_MIN_ILLNESS_BASE_FACTOR
,
5851 RS_MAX_ILLNESS_BASE_FACTOR
,
5852 "illness.illness_base_factor");
5853 game
.info
.illness_min_size
5854 = secfile_lookup_int_default_min_max(file
,
5855 RS_DEFAULT_ILLNESS_MIN_SIZE
,
5856 RS_MIN_ILLNESS_MIN_SIZE
,
5857 RS_MAX_ILLNESS_MIN_SIZE
,
5858 "illness.illness_min_size");
5859 game
.info
.illness_trade_infection
5860 = secfile_lookup_int_default_min_max(file
,
5861 RS_DEFAULT_ILLNESS_TRADE_INFECTION_PCT
,
5862 RS_MIN_ILLNESS_TRADE_INFECTION_PCT
,
5863 RS_MAX_ILLNESS_TRADE_INFECTION_PCT
,
5864 "illness.illness_trade_infection");
5865 game
.info
.illness_pollution_factor
5866 = secfile_lookup_int_default_min_max(file
,
5867 RS_DEFAULT_ILLNESS_POLLUTION_PCT
,
5868 RS_MIN_ILLNESS_POLLUTION_PCT
,
5869 RS_MAX_ILLNESS_POLLUTION_PCT
,
5870 "illness.illness_pollution_factor");
5872 /* section: incite_cost */
5873 game
.server
.base_incite_cost
5874 = secfile_lookup_int_default_min_max(file
,
5875 RS_DEFAULT_INCITE_BASE_COST
,
5876 RS_MIN_INCITE_BASE_COST
,
5877 RS_MAX_INCITE_BASE_COST
,
5878 "incite_cost.base_incite_cost");
5879 game
.server
.incite_improvement_factor
5880 = secfile_lookup_int_default_min_max(file
,
5881 RS_DEFAULT_INCITE_IMPROVEMENT_FCT
,
5882 RS_MIN_INCITE_IMPROVEMENT_FCT
,
5883 RS_MAX_INCITE_IMPROVEMENT_FCT
,
5884 "incite_cost.improvement_factor");
5885 game
.server
.incite_unit_factor
5886 = secfile_lookup_int_default_min_max(file
,
5887 RS_DEFAULT_INCITE_UNIT_FCT
,
5888 RS_MIN_INCITE_UNIT_FCT
,
5889 RS_MAX_INCITE_UNIT_FCT
,
5890 "incite_cost.unit_factor");
5891 game
.server
.incite_total_factor
5892 = secfile_lookup_int_default_min_max(file
,
5893 RS_DEFAULT_INCITE_TOTAL_FCT
,
5894 RS_MIN_INCITE_TOTAL_FCT
,
5895 RS_MAX_INCITE_TOTAL_FCT
,
5896 "incite_cost.total_factor");
5898 /* section: global_unit_options */
5899 game
.info
.slow_invasions
5900 = secfile_lookup_bool_default(file
, RS_DEFAULT_SLOW_INVASIONS
,
5901 "global_unit_options.slow_invasions");
5905 struct action_auto_perf
*auto_perf
;
5907 /* A unit moved next to this unit and the autoattack server setting
5909 auto_perf
= action_auto_perf_slot_number(ACTION_AUTO_MOVED_ADJ
);
5910 auto_perf
->cause
= AAPC_UNIT_MOVED_ADJ
;
5912 /* Auto attack happens during war. */
5913 requirement_vector_append(&auto_perf
->reqs
,
5914 req_from_values(VUT_DIPLREL
,
5916 FALSE
, TRUE
, TRUE
, DS_WAR
));
5918 /* Needs a movement point to auto attack. */
5919 requirement_vector_append(&auto_perf
->reqs
,
5920 req_from_values(VUT_MINMOVES
,
5922 FALSE
, TRUE
, TRUE
, 1));
5924 /* Internally represented as an action auto performer rule. */
5925 if (!load_action_auto_uflag_block(file
, auto_perf
,
5926 "auto_attack.will_never",
5931 /* TODO: It would be great if unit_survive_autoattack() could be made
5932 * flexible enough to also handle diplomatic actions etc. */
5933 auto_perf
->alternatives
[0] = ACTION_CAPTURE_UNITS
;
5934 auto_perf
->alternatives
[1] = ACTION_BOMBARD
;
5935 auto_perf
->alternatives
[2] = ACTION_ATTACK
;
5938 /* section: actions */
5941 int force_capture_units
, force_bombard
, force_explode_nuclear
;
5943 if (secfile_lookup_bool_default(file
, RS_DEFAULT_FORCE_TRADE_ROUTE
,
5944 "actions.force_trade_route")) {
5945 /* Forbid entering the marketplace when a trade route can be
5947 BV_SET(action_by_number(ACTION_MARKETPLACE
)->blocked_by
,
5948 ACTION_TRADE_ROUTE
);
5951 /* Forbid bombarding, exploading nuclear or attacking when it is
5952 * legal to capture units. */
5954 = secfile_lookup_bool_default(file
, RS_DEFAULT_FORCE_CAPTURE_UNITS
,
5955 "actions.force_capture_units");
5957 if (force_capture_units
) {
5958 BV_SET(action_by_number(ACTION_BOMBARD
)->blocked_by
,
5959 ACTION_CAPTURE_UNITS
);
5960 BV_SET(action_by_number(ACTION_NUKE
)->blocked_by
,
5961 ACTION_CAPTURE_UNITS
);
5962 BV_SET(action_by_number(ACTION_ATTACK
)->blocked_by
,
5963 ACTION_CAPTURE_UNITS
);
5964 BV_SET(action_by_number(ACTION_CONQUER_CITY
)->blocked_by
,
5965 ACTION_CAPTURE_UNITS
);
5968 /* Forbid exploding nuclear or attacking when it is legal to
5971 = secfile_lookup_bool_default(file
, RS_DEFAULT_FORCE_BOMBARD
,
5972 "actions.force_bombard");
5974 if (force_bombard
) {
5975 BV_SET(action_by_number(ACTION_NUKE
)->blocked_by
,
5977 BV_SET(action_by_number(ACTION_ATTACK
)->blocked_by
,
5979 BV_SET(action_by_number(ACTION_CONQUER_CITY
)->blocked_by
,
5983 /* Forbid attacking when it is legal to do explode nuclear. */
5984 force_explode_nuclear
5985 = secfile_lookup_bool_default(file
,
5986 RS_DEFAULT_FORCE_EXPLODE_NUCLEAR
,
5987 "actions.force_explode_nuclear");
5989 if (force_explode_nuclear
) {
5990 BV_SET(action_by_number(ACTION_ATTACK
)->blocked_by
,
5992 BV_SET(action_by_number(ACTION_CONQUER_CITY
)->blocked_by
,
5996 /* If the poison city action should empty the granary. */
5997 /* TODO: empty granary and reduce population should become separate
5998 * action effect flags when actions are generalized. */
5999 game
.info
.poison_empties_food_stock
6000 = secfile_lookup_bool_default(file
,
6001 RS_DEFAULT_POISON_EMPTIES_FOOD_STOCK
,
6002 "actions.poison_empties_food_stock");
6004 /* Allow setting max distance for bombardment before generalized
6007 struct entry
*pentry
;
6010 pentry
= secfile_entry_lookup(file
, "actions.bombard_max_range");
6013 max_range
= RS_DEFAULT_BOMBARD_MAX_RANGE
;
6015 switch (entry_type(pentry
)) {
6017 if (entry_int_get(pentry
, &max_range
)) {
6020 /* Fall through to error handling. */
6025 if (entry_str_get(pentry
, &custom
)
6026 && !fc_strcasecmp(custom
, RS_ACTION_NO_MAX_DISTANCE
)) {
6027 max_range
= ACTION_DISTANCE_UNLIMITED
;
6031 /* Fall through to error handling. */
6033 ruleset_error(LOG_ERROR
, "Bad actions.bombard_max_range");
6035 max_range
= RS_DEFAULT_BOMBARD_MAX_RANGE
;
6040 action_by_number(ACTION_BOMBARD
)->max_distance
= max_range
;
6043 text
= secfile_lookup_str_default(file
,
6044 /* TRANS: _Poison City (3% chance of success). */
6045 N_("%sPoison City%s"),
6046 "actions.ui_name_poison_city");
6047 sz_strlcpy(action_by_number(ACTION_SPY_POISON
)->ui_name
,
6050 text
= secfile_lookup_str_default(file
,
6051 /* TRANS: S_abotage Enemy Unit (3% chance of success). */
6052 N_("S%sabotage Enemy Unit%s"),
6053 "actions.ui_name_sabotage_unit");
6054 sz_strlcpy(action_by_number(ACTION_SPY_SABOTAGE_UNIT
)->ui_name
,
6057 text
= secfile_lookup_str_default(file
,
6058 /* TRANS: Bribe Enemy _Unit (3% chance of success). */
6059 N_("Bribe Enemy %sUnit%s"),
6060 "actions.ui_name_bribe_unit");
6061 sz_strlcpy(action_by_number(ACTION_SPY_BRIBE_UNIT
)->ui_name
,
6064 text
= secfile_lookup_str_default(file
,
6065 /* TRANS: _Sabotage City (3% chance of success). */
6066 N_("%sSabotage City%s"),
6067 "actions.ui_name_sabotage_city");
6068 sz_strlcpy(action_by_number(ACTION_SPY_SABOTAGE_CITY
)->ui_name
,
6071 text
= secfile_lookup_str_default(file
,
6072 /* TRANS: Industria_l Sabotage (3% chance of success). */
6073 N_("Industria%sl Sabotage%s"),
6074 "actions.ui_name_targeted_sabotage_city");
6076 action_by_number(ACTION_SPY_TARGETED_SABOTAGE_CITY
)->ui_name
,
6079 text
= secfile_lookup_str_default(file
,
6080 /* TRANS: Incite a Re_volt (3% chance of success). */
6081 N_("Incite a Re%svolt%s"),
6082 "actions.ui_name_incite_city");
6083 sz_strlcpy(action_by_number(ACTION_SPY_INCITE_CITY
)->ui_name
,
6086 text
= secfile_lookup_str_default(file
,
6087 /* TRANS: Incite a Re_volt and Escape (3% chance of success). */
6088 N_("Incite a Re%svolt and Escape%s"),
6089 "actions.ui_name_incite_city_escape");
6090 sz_strlcpy(action_by_number(ACTION_SPY_INCITE_CITY_ESC
)->ui_name
,
6093 text
= secfile_lookup_str_default(file
,
6094 /* TRANS: Establish _Embassy (100% chance of success). */
6095 N_("Establish %sEmbassy%s"),
6096 "actions.ui_name_establish_embassy");
6097 sz_strlcpy(action_by_number(ACTION_ESTABLISH_EMBASSY
)->ui_name
,
6100 text
= secfile_lookup_str_default(file
,
6101 /* TRANS: Becom_e Ambassador (100% chance of success). */
6102 N_("Becom%se Ambassador%s"),
6103 "actions.ui_name_establish_embassy_stay");
6104 sz_strlcpy(action_by_number(ACTION_ESTABLISH_EMBASSY_STAY
)->ui_name
,
6107 text
= secfile_lookup_str_default(file
,
6108 /* TRANS: Steal _Technology (3% chance of success). */
6109 N_("Steal %sTechnology%s"),
6110 "actions.ui_name_steal_tech");
6111 sz_strlcpy(action_by_number(ACTION_SPY_STEAL_TECH
)->ui_name
,
6114 text
= secfile_lookup_str_default(file
,
6115 /* TRANS: In_dustrial Espionage (3% chance of success). */
6116 N_("In%sdustrial Espionage%s"),
6117 "actions.ui_name_targeted_steal_tech");
6118 sz_strlcpy(action_by_number(ACTION_SPY_TARGETED_STEAL_TECH
)->ui_name
,
6121 text
= secfile_lookup_str_default(file
,
6122 /* TRANS: _Investigate City (100% chance of success). */
6123 N_("%sInvestigate City%s"),
6124 "actions.ui_name_investigate_city");
6125 sz_strlcpy(action_by_number(ACTION_SPY_INVESTIGATE_CITY
)->ui_name
,
6128 text
= secfile_lookup_str_default(file
,
6129 /* TRANS: _Investigate City (spends the unit) (100% chance of
6131 N_("%sInvestigate City (spends the unit)%s"),
6132 "actions.ui_name_investigate_city_spend_unit");
6133 sz_strlcpy(action_by_number(ACTION_INV_CITY_SPEND
)->ui_name
,
6136 text
= secfile_lookup_str_default(file
,
6137 /* TRANS: Steal _Gold (100% chance of success). */
6138 N_("Steal %sGold%s"),
6139 "actions.ui_name_steal_gold");
6140 sz_strlcpy(action_by_number(ACTION_SPY_STEAL_GOLD
)->ui_name
,
6143 text
= secfile_lookup_str_default(file
,
6144 /* TRANS: Steal _Maps (100% chance of success). */
6145 N_("Steal %sMaps%s"),
6146 "actions.ui_name_steal_maps");
6147 sz_strlcpy(action_by_number(ACTION_STEAL_MAPS
)->ui_name
,
6150 text
= secfile_lookup_str_default(file
,
6151 /* TRANS: Establish Trade _Route (100% chance of success). */
6152 N_("Establish Trade %sRoute%s"),
6153 "actions.ui_name_establish_trade_route");
6154 sz_strlcpy(action_by_number(ACTION_TRADE_ROUTE
)->ui_name
,
6157 text
= secfile_lookup_str_default(file
,
6158 /* TRANS: Enter _Marketplace (100% chance of success). */
6159 N_("Enter %sMarketplace%s"),
6160 "actions.ui_name_enter_marketplace");
6161 sz_strlcpy(action_by_number(ACTION_MARKETPLACE
)->ui_name
,
6164 text
= secfile_lookup_str_default(file
,
6165 /* TRANS: Help _build Wonder (100% chance of success). */
6166 N_("Help %sbuild Wonder%s"),
6167 "actions.ui_name_help_wonder");
6168 sz_strlcpy(action_by_number(ACTION_HELP_WONDER
)->ui_name
,
6171 text
= secfile_lookup_str_default(file
,
6172 /* TRANS: _Capture Units (100% chance of success). */
6173 N_("%sCapture Units%s"),
6174 "actions.ui_name_capture_units");
6175 sz_strlcpy(action_by_number(ACTION_CAPTURE_UNITS
)->ui_name
,
6178 text
= secfile_lookup_str_default(file
,
6179 /* TRANS: _Expel Unit (100% chance of success). */
6180 N_("%sExpel Unit%s"),
6181 "actions.ui_name_expel_unit");
6182 sz_strlcpy(action_by_number(ACTION_EXPEL_UNIT
)->ui_name
,
6185 text
= secfile_lookup_str_default(file
,
6186 /* TRANS: _Found City (100% chance of success). */
6187 N_("%sFound City%s"),
6188 "actions.ui_name_found_city");
6189 sz_strlcpy(action_by_number(ACTION_FOUND_CITY
)->ui_name
,
6192 text
= secfile_lookup_str_default(file
,
6193 /* TRANS: _Join City (100% chance of success). */
6194 N_("%sJoin City%s"),
6195 "actions.ui_name_join_city");
6196 sz_strlcpy(action_by_number(ACTION_JOIN_CITY
)->ui_name
,
6199 text
= secfile_lookup_str_default(file
,
6200 /* TRANS: B_ombard (100% chance of success). */
6202 "actions.ui_name_bombard");
6203 sz_strlcpy(action_by_number(ACTION_BOMBARD
)->ui_name
,
6206 text
= secfile_lookup_str_default(file
,
6207 /* TRANS: Suitcase _Nuke (100% chance of success). */
6208 N_("Suitcase %sNuke%s"),
6209 "actions.ui_name_suitcase_nuke");
6210 sz_strlcpy(action_by_number(ACTION_SPY_NUKE
)->ui_name
,
6213 text
= secfile_lookup_str_default(file
,
6214 /* TRANS: Suitcase _Nuke and Escape (100% chance of success). */
6215 N_("Suitcase %sNuke and Escape%s"),
6216 "actions.ui_name_suitcase_nuke_escape");
6217 sz_strlcpy(action_by_number(ACTION_SPY_NUKE_ESC
)->ui_name
,
6220 text
= secfile_lookup_str_default(file
,
6221 /* TRANS: Explode _Nuclear (100% chance of success). */
6222 N_("Explode %sNuclear%s"),
6223 "actions.ui_name_explode_nuclear");
6224 sz_strlcpy(action_by_number(ACTION_NUKE
)->ui_name
,
6227 text
= secfile_lookup_str_default(file
,
6228 /* TRANS: Destroy _City (100% chance of success). */
6229 N_("Destroy %sCity%s"),
6230 "actions.ui_name_destroy_city");
6231 sz_strlcpy(action_by_number(ACTION_DESTROY_CITY
)->ui_name
,
6234 text
= secfile_lookup_str_default(file
,
6235 /* TRANS: Rec_ycle Unit (100% chance of success). */
6236 N_("Rec%sycle Unit%s"),
6237 "actions.ui_name_recycle_unit");
6238 sz_strlcpy(action_by_number(ACTION_RECYCLE_UNIT
)->ui_name
,
6241 text
= secfile_lookup_str_default(file
,
6242 /* TRANS: _You're Fired (100% chance of success). */
6243 N_("%sYou're Fired%s"),
6244 "actions.ui_name_disband_unit");
6245 sz_strlcpy(action_by_number(ACTION_DISBAND_UNIT
)->ui_name
,
6248 text
= secfile_lookup_str_default(file
,
6249 /* TRANS: Set _Home City (100% chance of success). */
6250 N_("Set %sHome City%s"),
6251 "actions.ui_name_home_city");
6252 sz_strlcpy(action_by_number(ACTION_HOME_CITY
)->ui_name
,
6255 text
= secfile_lookup_str_default(file
,
6256 /* TRANS: _Upgrade Unit (100% chance of success). */
6257 N_("%sUpgrade Unit%s"),
6258 "actions.ui_upgrade_unit");
6259 sz_strlcpy(action_by_number(ACTION_UPGRADE_UNIT
)->ui_name
,
6262 text
= secfile_lookup_str_default(file
,
6263 /* TRANS: Drop _Paratrooper (100% chance of success). */
6264 N_("Drop %sParatrooper%s"),
6265 "actions.ui_paradrop_unit");
6266 sz_strlcpy(action_by_number(ACTION_PARADROP
)->ui_name
,
6269 text
= secfile_lookup_str_default(file
,
6270 /* TRANS: _Airlift to City (100% chance of success). */
6271 N_("%sAirlift to City%s"),
6272 "actions.ui_airlift_unit");
6273 sz_strlcpy(action_by_number(ACTION_AIRLIFT
)->ui_name
,
6276 text
= secfile_lookup_str_default(file
,
6277 /* TRANS: _Attack (100% chance of success). */
6279 "actions.ui_name_attack");
6280 sz_strlcpy(action_by_number(ACTION_ATTACK
)->ui_name
,
6283 text
= secfile_lookup_str_default(file
,
6284 /* TRANS: _Conquer City (100% chance of success). */
6285 N_("%sConquer City%s"),
6286 "actions.ui_name_conquer_city");
6287 sz_strlcpy(action_by_number(ACTION_CONQUER_CITY
)->ui_name
,
6290 text
= secfile_lookup_str_default(file
,
6291 /* TRANS: Heal _Unit (3% chance of success). */
6292 N_("Heal %sUnit%s"),
6293 "actions.ui_name_heal_unit");
6294 sz_strlcpy(action_by_number(ACTION_HEAL_UNIT
)->ui_name
,
6297 /* The quiet (don't auto generate help for) property of all actions
6298 * live in a single enum vector. This avoids generic action
6300 if (secfile_entry_by_path(file
, "actions.quiet_actions")) {
6301 enum gen_action
*quiet_actions
;
6306 secfile_lookup_enum_vec(file
, &asize
, gen_action
,
6307 "actions.quiet_actions");
6309 if (!quiet_actions
) {
6310 /* Entity exists but couldn't read it. */
6311 ruleset_error(LOG_ERROR
,
6312 "\"%s\": actions.quiet_actions: bad action list",
6318 for (j
= 0; j
< asize
; j
++) {
6319 /* Don't auto generate help text for this action. */
6320 action_by_number(quiet_actions
[j
])->quiet
= TRUE
;
6323 free(quiet_actions
);
6328 sec
= secfile_sections_by_name_prefix(file
,
6329 ACTION_ENABLER_SECTION_PREFIX
);
6332 section_list_iterate(sec
, psection
) {
6333 struct action_enabler
*enabler
;
6334 const char *sec_name
= section_name(psection
);
6335 struct action
*paction
;
6336 struct requirement_vector
*actor_reqs
;
6337 struct requirement_vector
*target_reqs
;
6338 const char *action_text
;
6340 enabler
= action_enabler_new();
6342 action_text
= secfile_lookup_str(file
, "%s.action", sec_name
);
6344 if (action_text
== NULL
) {
6345 ruleset_error(LOG_ERROR
, "\"%s\" [%s] missing action to enable.",
6346 filename
, sec_name
);
6351 paction
= action_by_rule_name(action_text
);
6353 ruleset_error(LOG_ERROR
, "\"%s\" [%s] lists unknown action type \"%s\".",
6354 filename
, sec_name
, action_text
);
6359 enabler
->action
= paction
->id
;
6361 actor_reqs
= lookup_req_list(file
, compat
, sec_name
, "actor_reqs", action_text
);
6362 if (actor_reqs
== NULL
) {
6367 requirement_vector_copy(&enabler
->actor_reqs
, actor_reqs
);
6369 target_reqs
= lookup_req_list(file
, compat
, sec_name
, "target_reqs", action_text
);
6370 if (target_reqs
== NULL
) {
6375 requirement_vector_copy(&enabler
->target_reqs
, target_reqs
);
6377 action_enabler_add(enabler
);
6378 } section_list_iterate_end
;
6379 section_list_destroy(sec
);
6385 const char *tus_text
;
6387 /* section: combat_rules */
6388 game
.info
.tired_attack
6389 = secfile_lookup_bool_default(file
, RS_DEFAULT_TIRED_ATTACK
,
6390 "combat_rules.tired_attack");
6392 /* section: borders */
6393 game
.info
.border_city_radius_sq
6394 = secfile_lookup_int_default_min_max(file
,
6395 RS_DEFAULT_BORDER_RADIUS_SQ_CITY
,
6396 RS_MIN_BORDER_RADIUS_SQ_CITY
,
6397 RS_MAX_BORDER_RADIUS_SQ_CITY
,
6398 "borders.radius_sq_city");
6399 game
.info
.border_size_effect
6400 = secfile_lookup_int_default_min_max(file
,
6401 RS_DEFAULT_BORDER_SIZE_EFFECT
,
6402 RS_MIN_BORDER_SIZE_EFFECT
,
6403 RS_MAX_BORDER_SIZE_EFFECT
,
6404 "borders.size_effect");
6406 game
.info
.border_city_permanent_radius_sq
6407 = secfile_lookup_int_default_min_max(file
,
6408 RS_DEFAULT_BORDER_RADIUS_SQ_CITY_PERMANENT
,
6409 RS_MIN_BORDER_RADIUS_SQ_CITY_PERMANENT
,
6410 RS_MAX_BORDER_RADIUS_SQ_CITY_PERMANENT
,
6411 "borders.radius_sq_city_permanent");
6413 /* section: research */
6414 tus_text
= secfile_lookup_str_default(file
, RS_DEFAULT_TECH_COST_STYLE
,
6415 "research.tech_cost_style");
6416 game
.info
.tech_cost_style
= tech_cost_style_by_name(tus_text
,
6418 if (!tech_cost_style_is_valid(game
.info
.tech_cost_style
)) {
6419 ruleset_error(LOG_ERROR
, "Unknown tech cost style \"%s\"",
6424 tus_text
= secfile_lookup_str_default(file
, RS_DEFAULT_TECH_LEAKAGE
,
6425 "research.tech_leakage");
6426 game
.info
.tech_leakage
= tech_leakage_style_by_name(tus_text
,
6428 if (!tech_leakage_style_is_valid(game
.info
.tech_leakage
)) {
6429 ruleset_error(LOG_ERROR
, "Unknown tech leakage \"%s\"",
6433 if (game
.info
.tech_cost_style
== TECH_COST_CIV1CIV2
6434 && game
.info
.tech_leakage
!= TECH_LEAKAGE_NONE
) {
6435 log_error("Only tech_leakage \"%s\" supported with "
6436 "tech_cost_style \"%s\". ",
6437 tech_leakage_style_name(TECH_LEAKAGE_NONE
),
6438 tech_cost_style_name(TECH_COST_CIV1CIV2
));
6439 log_error("Switching to tech_leakage \"%s\".",
6440 tech_leakage_style_name(TECH_LEAKAGE_NONE
));
6441 game
.info
.tech_leakage
= TECH_LEAKAGE_NONE
;
6443 game
.info
.base_tech_cost
6444 = secfile_lookup_int_default_min_max(file
,
6445 RS_DEFAULT_BASE_TECH_COST
,
6446 RS_MIN_BASE_TECH_COST
,
6447 RS_MAX_BASE_TECH_COST
,
6448 "research.base_tech_cost");
6450 tus_text
= secfile_lookup_str_default(file
, RS_DEFAULT_TECH_UPKEEP_STYLE
,
6451 "research.tech_upkeep_style");
6453 game
.info
.tech_upkeep_style
= tech_upkeep_style_by_name(tus_text
, fc_strcasecmp
);
6455 if (!tech_upkeep_style_is_valid(game
.info
.tech_upkeep_style
)) {
6456 ruleset_error(LOG_ERROR
, "Unknown tech upkeep style \"%s\"",
6463 game
.info
.tech_upkeep_divider
6464 = secfile_lookup_int_default_min_max(file
,
6465 RS_DEFAULT_TECH_UPKEEP_DIVIDER
,
6466 RS_MIN_TECH_UPKEEP_DIVIDER
,
6467 RS_MAX_TECH_UPKEEP_DIVIDER
,
6468 "research.tech_upkeep_divider");
6470 sval
= secfile_lookup_str_default(file
, NULL
, "research.free_tech_method");
6472 ruleset_error(LOG_ERROR
, "No free_tech_method given");
6475 game
.info
.free_tech_method
= free_tech_method_by_name(sval
, fc_strcasecmp
);
6476 if (!free_tech_method_is_valid(game
.info
.free_tech_method
)) {
6477 ruleset_error(LOG_ERROR
, "Bad value %s for free_tech_method.", sval
);
6486 /* section: culture */
6487 game
.info
.culture_vic_points
6488 = secfile_lookup_int_default(file
, RS_DEFAULT_CULTURE_VIC_POINTS
,
6489 "culture.victory_min_points");
6490 game
.info
.culture_vic_lead
6491 = secfile_lookup_int_default(file
, RS_DEFAULT_CULTURE_VIC_LEAD
,
6492 "culture.victory_lead_pct");
6493 game
.info
.culture_migration_pml
6494 = secfile_lookup_int_default(file
, RS_DEFAULT_CULTURE_MIGRATION_PML
,
6495 "culture.migration_pml");
6497 /* section: calendar */
6498 game
.calendar
.calendar_skip_0
6499 = secfile_lookup_bool_default(file
, RS_DEFAULT_CALENDAR_SKIP_0
,
6500 "calendar.skip_year_0");
6501 game
.server
.start_year
6502 = secfile_lookup_int_default(file
, GAME_START_YEAR
,
6503 "calendar.start_year");
6504 game
.calendar
.calendar_fragments
6505 = secfile_lookup_int_default(file
, 0, "calendar.fragments");
6507 if (game
.calendar
.calendar_fragments
> MAX_CALENDAR_FRAGMENTS
) {
6508 ruleset_error(LOG_ERROR
, "Too many calendar fragments. Max is %d",
6509 MAX_CALENDAR_FRAGMENTS
);
6511 game
.calendar
.calendar_fragments
= 0;
6513 sz_strlcpy(game
.calendar
.positive_year_label
,
6514 secfile_lookup_str_default(file
,
6515 RS_DEFAULT_POS_YEAR_LABEL
,
6516 "calendar.positive_label"));
6517 sz_strlcpy(game
.calendar
.negative_year_label
,
6518 secfile_lookup_str_default(file
,
6519 RS_DEFAULT_NEG_YEAR_LABEL
,
6520 "calendar.negative_label"));
6522 for (cf
= 0; cf
< game
.calendar
.calendar_fragments
; cf
++) {
6525 fname
= secfile_lookup_str_default(file
, NULL
, "calendar.fragment_name%d", cf
);
6526 if (fname
!= NULL
) {
6527 strncpy(game
.calendar
.calendar_fragment_name
[cf
], fname
,
6528 sizeof(game
.calendar
.calendar_fragment_name
[cf
]));
6534 /* section playercolors */
6535 struct rgbcolor
*prgbcolor
= NULL
;
6536 bool color_read
= TRUE
;
6538 /* Check if the player list is defined and empty. */
6539 if (playercolor_count() != 0) {
6544 while (color_read
) {
6547 color_read
= rgbcolor_load(file
, &prgbcolor
, "playercolors.colorlist%d", i
);
6549 playercolor_add(prgbcolor
);
6555 if (playercolor_count() == 0) {
6556 ruleset_error(LOG_ERROR
, "No player colors defined!");
6561 fc_assert(game
.plr_bg_color
== NULL
);
6562 if (!rgbcolor_load(file
, &game
.plr_bg_color
, "playercolors.background")) {
6563 ruleset_error(LOG_ERROR
, "No background player color defined! (%s)",
6572 /* section: teams */
6573 svec
= secfile_lookup_str_vec(file
, &teams
, "teams.names");
6574 if (team_slot_count() < teams
) {
6575 teams
= team_slot_count();
6577 game
.server
.ruledit
.named_teams
= teams
;
6578 for (i
= 0; i
< teams
; i
++) {
6579 team_slot_set_defined_name(team_slot_by_number(i
), svec
[i
]);
6583 sec
= secfile_sections_by_name_prefix(file
, DISASTER_SECTION_PREFIX
);
6584 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
6585 if (nval
> MAX_DISASTER_TYPES
) {
6586 int num
= nval
; /* No "size_t" to printf */
6588 ruleset_error(LOG_ERROR
, "\"%s\": Too many disaster types (%d, max %d)",
6589 filename
, num
, MAX_DISASTER_TYPES
);
6590 section_list_destroy(sec
);
6593 game
.control
.num_disaster_types
= nval
;
6598 disaster_type_iterate(pdis
) {
6599 int id
= disaster_index(pdis
);
6602 struct requirement_vector
*reqs
;
6603 const char *sec_name
= section_name(section_list_get(sec
, id
));
6605 if (!ruleset_load_names(&pdis
->name
, NULL
, file
, sec_name
)) {
6606 ruleset_error(LOG_ERROR
, "\"%s\": Cannot load disaster names",
6612 reqs
= lookup_req_list(file
, compat
, sec_name
, "reqs", disaster_rule_name(pdis
));
6617 requirement_vector_copy(&pdis
->reqs
, reqs
);
6619 pdis
->frequency
= secfile_lookup_int_default(file
, GAME_DEFAULT_DISASTER_FREQ
,
6620 "%s.frequency", sec_name
);
6622 svec
= secfile_lookup_str_vec(file
, &eff_count
, "%s.effects", sec_name
);
6624 BV_CLR_ALL(pdis
->effects
);
6625 for (j
= 0; j
< eff_count
; j
++) {
6626 const char *dsval
= svec
[j
];
6627 enum disaster_effect_id effect
;
6629 effect
= disaster_effect_id_by_name(dsval
, fc_strcasecmp
);
6631 if (!disaster_effect_id_is_valid(effect
)) {
6632 ruleset_error(LOG_ERROR
,
6633 "\"%s\" disaster \"%s\": unknown effect \"%s\".",
6635 disaster_rule_name(pdis
),
6640 BV_SET(pdis
->effects
, effect
);
6649 } disaster_type_iterate_end
;
6650 section_list_destroy(sec
);
6654 sec
= secfile_sections_by_name_prefix(file
, ACHIEVEMENT_SECTION_PREFIX
);
6656 achievements_iterate(pach
) {
6657 int id
= achievement_index(pach
);
6658 const char *sec_name
= section_name(section_list_get(sec
, id
));
6659 const char *typename
;
6662 typename
= secfile_lookup_str_default(file
, NULL
, "%s.type", sec_name
);
6664 pach
->type
= achievement_type_by_name(typename
, fc_strcasecmp
);
6665 if (!achievement_type_is_valid(pach
->type
)) {
6666 ruleset_error(LOG_ERROR
, "Achievement has unknown type \"%s\".",
6667 typename
!= NULL
? typename
: "(NULL)");
6672 pach
->unique
= secfile_lookup_bool_default(file
, GAME_DEFAULT_ACH_UNIQUE
,
6673 "%s.unique", sec_name
);
6675 pach
->value
= secfile_lookup_int_default(file
, GAME_DEFAULT_ACH_VALUE
,
6676 "%s.value", sec_name
);
6677 pach
->culture
= secfile_lookup_int_default(file
, 0,
6678 "%s.culture", sec_name
);
6680 msg
= secfile_lookup_str_default(file
, NULL
, "%s.first_msg", sec_name
);
6682 ruleset_error(LOG_ERROR
, "Achievement %s has no first msg!", sec_name
);
6685 pach
->first_msg
= fc_strdup(msg
);
6690 msg
= secfile_lookup_str_default(file
, NULL
, "%s.cons_msg", sec_name
);
6692 if (!pach
->unique
) {
6693 ruleset_error(LOG_ERROR
, "Achievement %s has no msg for consecutive gainers!", sec_name
);
6697 pach
->cons_msg
= fc_strdup(msg
);
6704 } achievements_iterate_end
;
6705 section_list_destroy(sec
);
6709 for (i
= 0; (name
= secfile_lookup_str_default(file
, NULL
,
6710 "trade.settings%d.type",
6712 enum trade_route_type type
= trade_route_type_by_name(name
);
6714 if (type
== TRT_LAST
) {
6715 ruleset_error(LOG_ERROR
,
6716 "\"%s\" unknown trade route type \"%s\".",
6720 struct trade_route_settings
*set
= trade_route_settings_by_type(type
);
6721 const char *cancelling
;
6724 set
->trade_pct
= secfile_lookup_int_default(file
, 100,
6725 "trade.settings%d.pct", i
);
6726 cancelling
= secfile_lookup_str_default(file
, "Active",
6727 "trade.settings%d.cancelling", i
);
6728 set
->cancelling
= traderoute_cancelling_type_by_name(cancelling
);
6729 if (set
->cancelling
== TRI_LAST
) {
6730 ruleset_error(LOG_ERROR
,
6731 "\"%s\" unknown traderoute cancelling type \"%s\".",
6732 filename
, cancelling
);
6736 bonus
= secfile_lookup_str_default(file
, "None", "trade.settings%d.bonus", i
);
6738 set
->bonus_type
= traderoute_bonus_type_by_name(bonus
, fc_strcasecmp
);
6740 if (!traderoute_bonus_type_is_valid(set
->bonus_type
)) {
6741 ruleset_error(LOG_ERROR
,
6742 "\"%s\" unknown traderoute bonus type \"%s\".",
6751 const char *str
= secfile_lookup_str_default(file
, "Leaving", "trade.goods_selection");
6753 game
.info
.goods_selection
= goods_selection_method_by_name(str
, fc_strcasecmp
);
6755 if (!goods_selection_method_is_valid(game
.info
.goods_selection
)) {
6756 ruleset_error(LOG_ERROR
,
6757 "\"%s\" goods selection method \"%s\" unknown.",
6764 sec
= secfile_sections_by_name_prefix(file
, GOODS_SECTION_PREFIX
);
6766 goods_type_iterate(pgood
) {
6767 int id
= goods_index(pgood
);
6768 const char *sec_name
= section_name(section_list_get(sec
, id
));
6769 struct requirement_vector
*reqs
;
6773 reqs
= lookup_req_list(file
, compat
, sec_name
, "reqs", goods_rule_name(pgood
));
6778 requirement_vector_copy(&pgood
->reqs
, reqs
);
6780 pgood
->from_pct
= secfile_lookup_int_default(file
, 100,
6781 "%s.from_pct", sec_name
);
6782 pgood
->to_pct
= secfile_lookup_int_default(file
, 100,
6783 "%s.to_pct", sec_name
);
6785 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", sec_name
);
6786 BV_CLR_ALL(pgood
->flags
);
6787 for (j
= 0; j
< nval
; j
++) {
6788 enum goods_flag_id flag
;
6791 flag
= goods_flag_id_by_name(sval
, fc_strcasecmp
);
6792 if (!goods_flag_id_is_valid(flag
)) {
6793 ruleset_error(LOG_ERROR
, "\"%s\" good \"%s\": unknown flag \"%s\".",
6795 goods_rule_name(pgood
),
6800 BV_SET(pgood
->flags
, flag
);
6805 pgood
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
6806 } goods_type_iterate_end
;
6807 section_list_destroy(sec
);
6810 /* secfile_check_unused() is not here, but only after also settings section
6811 * has been loaded. */
6816 /**************************************************************************
6817 Send the units ruleset information (all individual unit classes) to the
6818 specified connections.
6819 **************************************************************************/
6820 static void send_ruleset_unit_classes(struct conn_list
*dest
)
6822 struct packet_ruleset_unit_class packet
;
6823 struct packet_ruleset_unit_class_flag fpacket
;
6826 for (i
= 0; i
< MAX_NUM_USER_UCLASS_FLAGS
; i
++) {
6827 const char *flagname
;
6828 const char *helptxt
;
6830 fpacket
.id
= i
+ UCF_USER_FLAG_1
;
6832 flagname
= unit_class_flag_id_name(i
+ UCF_USER_FLAG_1
);
6833 if (flagname
== NULL
) {
6834 fpacket
.name
[0] = '\0';
6836 sz_strlcpy(fpacket
.name
, flagname
);
6839 helptxt
= unit_class_flag_helptxt(i
+ UCF_USER_FLAG_1
);
6840 if (helptxt
== NULL
) {
6841 fpacket
.helptxt
[0] = '\0';
6843 sz_strlcpy(fpacket
.helptxt
, helptxt
);
6846 lsend_packet_ruleset_unit_class_flag(dest
, &fpacket
);
6849 unit_class_iterate(c
) {
6850 packet
.id
= uclass_number(c
);
6851 sz_strlcpy(packet
.name
, untranslated_name(&c
->name
));
6852 sz_strlcpy(packet
.rule_name
, rule_name_get(&c
->name
));
6853 packet
.min_speed
= c
->min_speed
;
6854 packet
.hp_loss_pct
= c
->hp_loss_pct
;
6855 packet
.hut_behavior
= c
->hut_behavior
;
6856 packet
.non_native_def_pct
= c
->non_native_def_pct
;
6857 packet
.flags
= c
->flags
;
6859 PACKET_STRVEC_COMPUTE(packet
.helptext
, c
->helptext
);
6861 lsend_packet_ruleset_unit_class(dest
, &packet
);
6862 } unit_class_iterate_end
;
6865 /**************************************************************************
6866 Send the units ruleset information (all individual units) to the
6867 specified connections.
6868 **************************************************************************/
6869 static void send_ruleset_units(struct conn_list
*dest
)
6871 struct packet_ruleset_unit packet
;
6872 struct packet_ruleset_unit_flag fpacket
;
6875 for (i
= 0; i
< MAX_NUM_USER_UNIT_FLAGS
; i
++) {
6876 const char *flagname
;
6877 const char *helptxt
;
6879 fpacket
.id
= i
+ UTYF_USER_FLAG_1
;
6881 flagname
= unit_type_flag_id_name(i
+ UTYF_USER_FLAG_1
);
6882 if (flagname
== NULL
) {
6883 fpacket
.name
[0] = '\0';
6885 sz_strlcpy(fpacket
.name
, flagname
);
6888 helptxt
= unit_type_flag_helptxt(i
+ UTYF_USER_FLAG_1
);
6889 if (helptxt
== NULL
) {
6890 fpacket
.helptxt
[0] = '\0';
6892 sz_strlcpy(fpacket
.helptxt
, helptxt
);
6895 lsend_packet_ruleset_unit_flag(dest
, &fpacket
);
6898 unit_type_iterate(u
) {
6899 packet
.id
= utype_number(u
);
6900 sz_strlcpy(packet
.name
, untranslated_name(&u
->name
));
6901 sz_strlcpy(packet
.rule_name
, rule_name_get(&u
->name
));
6902 sz_strlcpy(packet
.sound_move
, u
->sound_move
);
6903 sz_strlcpy(packet
.sound_move_alt
, u
->sound_move_alt
);
6904 sz_strlcpy(packet
.sound_fight
, u
->sound_fight
);
6905 sz_strlcpy(packet
.sound_fight_alt
, u
->sound_fight_alt
);
6906 sz_strlcpy(packet
.graphic_str
, u
->graphic_str
);
6907 sz_strlcpy(packet
.graphic_alt
, u
->graphic_alt
);
6908 packet
.unit_class_id
= uclass_number(utype_class(u
));
6909 packet
.build_cost
= u
->build_cost
;
6910 packet
.pop_cost
= u
->pop_cost
;
6911 packet
.attack_strength
= u
->attack_strength
;
6912 packet
.defense_strength
= u
->defense_strength
;
6913 packet
.move_rate
= u
->move_rate
;
6914 packet
.tech_requirement
= u
->require_advance
6915 ? advance_number(u
->require_advance
)
6917 packet
.impr_requirement
= u
->need_improvement
6918 ? improvement_number(u
->need_improvement
)
6919 : improvement_count();
6920 packet
.gov_requirement
= u
->need_government
6921 ? government_number(u
->need_government
)
6922 : government_count();
6923 packet
.vision_radius_sq
= u
->vision_radius_sq
;
6924 packet
.transport_capacity
= u
->transport_capacity
;
6926 packet
.firepower
= u
->firepower
;
6927 packet
.obsoleted_by
= u
->obsoleted_by
6928 ? utype_number(u
->obsoleted_by
)
6930 packet
.converted_to
= u
->converted_to
6931 ? utype_number(u
->converted_to
)
6933 packet
.convert_time
= u
->convert_time
;
6934 packet
.fuel
= u
->fuel
;
6935 packet
.flags
= u
->flags
;
6936 packet
.roles
= u
->roles
;
6937 packet
.happy_cost
= u
->happy_cost
;
6938 output_type_iterate(o
) {
6939 packet
.upkeep
[o
] = u
->upkeep
[o
];
6940 } output_type_iterate_end
;
6941 packet
.paratroopers_range
= u
->paratroopers_range
;
6942 packet
.paratroopers_mr_req
= u
->paratroopers_mr_req
;
6943 packet
.paratroopers_mr_sub
= u
->paratroopers_mr_sub
;
6944 packet
.bombard_rate
= u
->bombard_rate
;
6945 packet
.city_size
= u
->city_size
;
6946 packet
.city_slots
= u
->city_slots
;
6947 packet
.cargo
= u
->cargo
;
6948 packet
.targets
= u
->targets
;
6949 packet
.embarks
= u
->embarks
;
6950 packet
.disembarks
= u
->disembarks
;
6952 if (u
->veteran
== NULL
) {
6953 /* Use the default veteran system. */
6954 packet
.veteran_levels
= 0;
6956 /* Per unit veteran system definition. */
6957 packet
.veteran_levels
= utype_veteran_levels(u
);
6959 for (i
= 0; i
< packet
.veteran_levels
; i
++) {
6960 const struct veteran_level
*vlevel
= utype_veteran_level(u
, i
);
6962 sz_strlcpy(packet
.veteran_name
[i
], untranslated_name(&vlevel
->name
));
6963 packet
.power_fact
[i
] = vlevel
->power_fact
;
6964 packet
.move_bonus
[i
] = vlevel
->move_bonus
;
6967 PACKET_STRVEC_COMPUTE(packet
.helptext
, u
->helptext
);
6969 lsend_packet_ruleset_unit(dest
, &packet
);
6971 combat_bonus_list_iterate(u
->bonuses
, pbonus
) {
6972 struct packet_ruleset_unit_bonus bonuspacket
;
6974 bonuspacket
.unit
= packet
.id
;
6975 bonuspacket
.flag
= pbonus
->flag
;
6976 bonuspacket
.type
= pbonus
->type
;
6977 bonuspacket
.value
= pbonus
->value
;
6978 bonuspacket
.quiet
= pbonus
->quiet
;
6980 lsend_packet_ruleset_unit_bonus(dest
, &bonuspacket
);
6981 } combat_bonus_list_iterate_end
;
6982 } unit_type_iterate_end
;
6985 /**************************************************************************
6986 Send the specialists ruleset information (all individual specialist
6987 types) to the specified connections.
6988 **************************************************************************/
6989 static void send_ruleset_specialists(struct conn_list
*dest
)
6991 struct packet_ruleset_specialist packet
;
6993 specialist_type_iterate(spec_id
) {
6994 struct specialist
*s
= specialist_by_number(spec_id
);
6997 packet
.id
= spec_id
;
6998 sz_strlcpy(packet
.plural_name
, untranslated_name(&s
->name
));
6999 sz_strlcpy(packet
.rule_name
, rule_name_get(&s
->name
));
7000 sz_strlcpy(packet
.short_name
, untranslated_name(&s
->abbreviation
));
7001 sz_strlcpy(packet
.graphic_alt
, s
->graphic_alt
);
7003 requirement_vector_iterate(&s
->reqs
, preq
) {
7004 packet
.reqs
[j
++] = *preq
;
7005 } requirement_vector_iterate_end
;
7006 packet
.reqs_count
= j
;
7008 PACKET_STRVEC_COMPUTE(packet
.helptext
, s
->helptext
);
7010 lsend_packet_ruleset_specialist(dest
, &packet
);
7011 } specialist_type_iterate_end
;
7013 /**************************************************************************
7014 Send the techs class information to the specified connections.
7015 **************************************************************************/
7016 static void send_ruleset_tech_classes(struct conn_list
*dest
)
7018 struct packet_ruleset_tech_class packet
;
7020 tech_class_iterate(ptclass
) {
7021 packet
.id
= ptclass
->idx
;
7022 sz_strlcpy(packet
.name
, untranslated_name(&ptclass
->name
));
7023 sz_strlcpy(packet
.rule_name
, rule_name_get(&ptclass
->name
));
7024 packet
.cost_pct
= ptclass
->cost_pct
;
7026 lsend_packet_ruleset_tech_class(dest
, &packet
);
7027 } tech_class_iterate_end
;
7030 /**************************************************************************
7031 Send the techs ruleset information (all individual advances) to the
7032 specified connections.
7033 **************************************************************************/
7034 static void send_ruleset_techs(struct conn_list
*dest
)
7036 struct packet_ruleset_tech packet
;
7037 struct packet_ruleset_tech_flag fpacket
;
7040 for (i
= 0; i
< MAX_NUM_USER_TECH_FLAGS
; i
++) {
7041 const char *flagname
;
7042 const char *helptxt
;
7044 fpacket
.id
= i
+ TECH_USER_1
;
7046 flagname
= tech_flag_id_name_cb(i
+ TECH_USER_1
);
7047 if (flagname
== NULL
) {
7048 fpacket
.name
[0] = '\0';
7050 sz_strlcpy(fpacket
.name
, flagname
);
7053 helptxt
= tech_flag_helptxt(i
+ TECH_USER_1
);
7054 if (helptxt
== NULL
) {
7055 fpacket
.helptxt
[0] = '\0';
7057 sz_strlcpy(fpacket
.helptxt
, helptxt
);
7060 lsend_packet_ruleset_tech_flag(dest
, &fpacket
);
7063 advance_iterate(A_FIRST
, a
) {
7064 packet
.id
= advance_number(a
);
7065 packet
.removed
= !valid_advance(a
);
7066 if (a
->tclass
== NULL
) {
7069 packet
.tclass
= a
->tclass
->idx
;
7071 sz_strlcpy(packet
.name
, untranslated_name(&a
->name
));
7072 sz_strlcpy(packet
.rule_name
, rule_name_get(&a
->name
));
7073 sz_strlcpy(packet
.graphic_str
, a
->graphic_str
);
7074 sz_strlcpy(packet
.graphic_alt
, a
->graphic_alt
);
7076 /* Current size of the packet's research_reqs requirement vector. */
7079 /* The requirements req1 and req2 are needed to research a tech. Send
7080 * them in the research_reqs requirement vector. Range is set to player
7081 * since pooled research is configurable. */
7083 if ((a
->require
[AR_ONE
] != A_NEVER
)
7084 && advance_number(a
->require
[AR_ONE
]) > A_NONE
) {
7085 packet
.research_reqs
[i
++]
7086 = req_from_values(VUT_ADVANCE
, REQ_RANGE_PLAYER
,
7088 advance_number(a
->require
[AR_ONE
]));
7091 if ((a
->require
[AR_TWO
] != A_NEVER
)
7092 && advance_number(a
->require
[AR_TWO
]) > A_NONE
) {
7093 packet
.research_reqs
[i
++]
7094 = req_from_values(VUT_ADVANCE
, REQ_RANGE_PLAYER
,
7096 advance_number(a
->require
[AR_TWO
]));;
7099 /* The requirements of the tech's research_reqs also goes in the
7100 * packet's research_reqs requirement vector. */
7101 requirement_vector_iterate(&a
->research_reqs
, req
) {
7102 packet
.research_reqs
[i
++] = *req
;
7103 } requirement_vector_iterate_end
;
7105 /* The packet's research_reqs should contain req1, req2 and the
7106 * requirements of the tech's research_reqs. */
7107 packet
.research_reqs_count
= i
;
7109 packet
.root_req
= a
->require
[AR_ROOT
]
7110 ? advance_number(a
->require
[AR_ROOT
])
7113 packet
.flags
= a
->flags
;
7114 packet
.cost
= a
->cost
;
7115 packet
.num_reqs
= a
->num_reqs
;
7116 PACKET_STRVEC_COMPUTE(packet
.helptext
, a
->helptext
);
7118 lsend_packet_ruleset_tech(dest
, &packet
);
7119 } advance_iterate_end
;
7122 /**************************************************************************
7123 Send the buildings ruleset information (all individual improvements and
7124 wonders) to the specified connections.
7125 **************************************************************************/
7126 static void send_ruleset_buildings(struct conn_list
*dest
)
7128 improvement_iterate(b
) {
7129 struct packet_ruleset_building packet
;
7132 packet
.id
= improvement_number(b
);
7133 packet
.genus
= b
->genus
;
7134 sz_strlcpy(packet
.name
, untranslated_name(&b
->name
));
7135 sz_strlcpy(packet
.rule_name
, rule_name_get(&b
->name
));
7136 sz_strlcpy(packet
.graphic_str
, b
->graphic_str
);
7137 sz_strlcpy(packet
.graphic_alt
, b
->graphic_alt
);
7139 requirement_vector_iterate(&b
->reqs
, preq
) {
7140 packet
.reqs
[j
++] = *preq
;
7141 } requirement_vector_iterate_end
;
7142 packet
.reqs_count
= j
;
7144 requirement_vector_iterate(&b
->obsolete_by
, pobs
) {
7145 packet
.obs_reqs
[j
++] = *pobs
;
7146 } requirement_vector_iterate_end
;
7147 packet
.obs_count
= j
;
7148 packet
.build_cost
= b
->build_cost
;
7149 packet
.upkeep
= b
->upkeep
;
7150 packet
.sabotage
= b
->sabotage
;
7151 packet
.flags
= b
->flags
;
7152 sz_strlcpy(packet
.soundtag
, b
->soundtag
);
7153 sz_strlcpy(packet
.soundtag_alt
, b
->soundtag_alt
);
7154 PACKET_STRVEC_COMPUTE(packet
.helptext
, b
->helptext
);
7156 lsend_packet_ruleset_building(dest
, &packet
);
7157 } improvement_iterate_end
;
7160 /**************************************************************************
7161 Send the terrain ruleset information (terrain_control, and the individual
7162 terrain types) to the specified connections.
7163 **************************************************************************/
7164 static void send_ruleset_terrain(struct conn_list
*dest
)
7166 struct packet_ruleset_terrain packet
;
7167 struct packet_ruleset_terrain_flag fpacket
;
7170 lsend_packet_ruleset_terrain_control(dest
, &terrain_control
);
7172 for (i
= 0; i
< MAX_NUM_USER_TER_FLAGS
; i
++) {
7173 const char *flagname
;
7174 const char *helptxt
;
7176 fpacket
.id
= i
+ TER_USER_1
;
7178 flagname
= terrain_flag_id_name_cb(i
+ TER_USER_1
);
7179 if (flagname
== NULL
) {
7180 fpacket
.name
[0] = '\0';
7182 sz_strlcpy(fpacket
.name
, flagname
);
7185 helptxt
= terrain_flag_helptxt(i
+ TER_USER_1
);
7186 if (helptxt
== NULL
) {
7187 fpacket
.helptxt
[0] = '\0';
7189 sz_strlcpy(fpacket
.helptxt
, helptxt
);
7192 lsend_packet_ruleset_terrain_flag(dest
, &fpacket
);
7195 terrain_type_iterate(pterrain
) {
7196 struct extra_type
**r
;
7198 packet
.id
= terrain_number(pterrain
);
7199 packet
.tclass
= pterrain
->tclass
;
7200 packet
.native_to
= pterrain
->native_to
;
7202 sz_strlcpy(packet
.name
, untranslated_name(&pterrain
->name
));
7203 sz_strlcpy(packet
.rule_name
, rule_name_get(&pterrain
->name
));
7204 sz_strlcpy(packet
.graphic_str
, pterrain
->graphic_str
);
7205 sz_strlcpy(packet
.graphic_alt
, pterrain
->graphic_alt
);
7207 packet
.movement_cost
= pterrain
->movement_cost
;
7208 packet
.defense_bonus
= pterrain
->defense_bonus
;
7210 output_type_iterate(o
) {
7211 packet
.output
[o
] = pterrain
->output
[o
];
7212 } output_type_iterate_end
;
7214 packet
.num_resources
= 0;
7215 for (r
= pterrain
->resources
; *r
; r
++) {
7216 packet
.resources
[packet
.num_resources
++] = extra_number(*r
);
7219 output_type_iterate(o
) {
7220 packet
.road_output_incr_pct
[o
] = pterrain
->road_output_incr_pct
[o
];
7221 } output_type_iterate_end
;
7223 packet
.base_time
= pterrain
->base_time
;
7224 packet
.road_time
= pterrain
->road_time
;
7226 packet
.irrigation_result
= (pterrain
->irrigation_result
7227 ? terrain_number(pterrain
->irrigation_result
)
7229 packet
.irrigation_food_incr
= pterrain
->irrigation_food_incr
;
7230 packet
.irrigation_time
= pterrain
->irrigation_time
;
7232 packet
.mining_result
= (pterrain
->mining_result
7233 ? terrain_number(pterrain
->mining_result
)
7235 packet
.mining_shield_incr
= pterrain
->mining_shield_incr
;
7236 packet
.mining_time
= pterrain
->mining_time
;
7238 packet
.animal
= (pterrain
->animal
== NULL
? -1 : utype_number(pterrain
->animal
));
7239 packet
.transform_result
= (pterrain
->transform_result
7240 ? terrain_number(pterrain
->transform_result
)
7242 packet
.pillage_time
= pterrain
->pillage_time
;
7243 packet
.transform_time
= pterrain
->transform_time
;
7244 packet
.clean_pollution_time
= pterrain
->clean_pollution_time
;
7245 packet
.clean_fallout_time
= pterrain
->clean_fallout_time
;
7247 packet
.flags
= pterrain
->flags
;
7249 packet
.color_red
= pterrain
->rgb
->r
;
7250 packet
.color_green
= pterrain
->rgb
->g
;
7251 packet
.color_blue
= pterrain
->rgb
->b
;
7253 PACKET_STRVEC_COMPUTE(packet
.helptext
, pterrain
->helptext
);
7255 lsend_packet_ruleset_terrain(dest
, &packet
);
7256 } terrain_type_iterate_end
;
7259 /****************************************************************************
7260 Send the resource ruleset information to the specified connections.
7261 ****************************************************************************/
7262 static void send_ruleset_resources(struct conn_list
*dest
)
7264 struct packet_ruleset_resource packet
;
7266 extra_type_by_cause_iterate(EC_RESOURCE
, presource
) {
7267 packet
.id
= extra_index(presource
);
7269 output_type_iterate(o
) {
7270 packet
.output
[o
] = presource
->data
.resource
->output
[o
];
7271 } output_type_iterate_end
;
7273 lsend_packet_ruleset_resource(dest
, &packet
);
7274 } extra_type_by_cause_iterate_end
;
7277 /**************************************************************************
7278 Send the extra ruleset information (all individual extra types) to the
7279 specified connections.
7280 **************************************************************************/
7281 static void send_ruleset_extras(struct conn_list
*dest
)
7283 struct packet_ruleset_extra packet
;
7284 struct packet_ruleset_extra_flag fpacket
;
7287 for (i
= 0; i
< MAX_NUM_USER_EXTRA_FLAGS
; i
++) {
7288 const char *flagname
;
7289 const char *helptxt
;
7291 fpacket
.id
= i
+ EF_USER_FLAG_1
;
7293 flagname
= extra_flag_id_name(i
+ EF_USER_FLAG_1
);
7294 if (flagname
== NULL
) {
7295 fpacket
.name
[0] = '\0';
7297 sz_strlcpy(fpacket
.name
, flagname
);
7300 helptxt
= extra_flag_helptxt(i
+ EF_USER_FLAG_1
);
7301 if (helptxt
== NULL
) {
7302 fpacket
.helptxt
[0] = '\0';
7304 sz_strlcpy(fpacket
.helptxt
, helptxt
);
7307 lsend_packet_ruleset_extra_flag(dest
, &fpacket
);
7310 extra_type_iterate(e
) {
7313 packet
.id
= extra_number(e
);
7314 sz_strlcpy(packet
.name
, untranslated_name(&e
->name
));
7315 sz_strlcpy(packet
.rule_name
, rule_name_get(&e
->name
));
7317 packet
.category
= e
->category
;
7318 packet
.causes
= e
->causes
;
7319 packet
.rmcauses
= e
->rmcauses
;
7321 sz_strlcpy(packet
.activity_gfx
, e
->activity_gfx
);
7322 sz_strlcpy(packet
.act_gfx_alt
, e
->act_gfx_alt
);
7323 sz_strlcpy(packet
.act_gfx_alt2
, e
->act_gfx_alt2
);
7324 sz_strlcpy(packet
.rmact_gfx
, e
->rmact_gfx
);
7325 sz_strlcpy(packet
.rmact_gfx_alt
, e
->rmact_gfx_alt
);
7326 sz_strlcpy(packet
.graphic_str
, e
->graphic_str
);
7327 sz_strlcpy(packet
.graphic_alt
, e
->graphic_alt
);
7330 requirement_vector_iterate(&e
->reqs
, preq
) {
7331 packet
.reqs
[j
++] = *preq
;
7332 } requirement_vector_iterate_end
;
7333 packet
.reqs_count
= j
;
7336 requirement_vector_iterate(&e
->rmreqs
, preq
) {
7337 packet
.rmreqs
[j
++] = *preq
;
7338 } requirement_vector_iterate_end
;
7339 packet
.rmreqs_count
= j
;
7341 packet
.appearance_chance
= e
->appearance_chance
;
7343 requirement_vector_iterate(&e
->appearance_reqs
, preq
) {
7344 packet
.appearance_reqs
[j
++] = *preq
;
7345 } requirement_vector_iterate_end
;
7346 packet
.appearance_reqs_count
= j
;
7348 packet
.disappearance_chance
= e
->disappearance_chance
;
7350 requirement_vector_iterate(&e
->disappearance_reqs
, preq
) {
7351 packet
.disappearance_reqs
[j
++] = *preq
;
7352 } requirement_vector_iterate_end
;
7353 packet
.disappearance_reqs_count
= j
;
7355 packet
.visibility_req
= e
->visibility_req
;
7356 packet
.buildable
= e
->buildable
;
7357 packet
.build_time
= e
->build_time
;
7358 packet
.build_time_factor
= e
->build_time_factor
;
7359 packet
.removal_time
= e
->removal_time
;
7360 packet
.removal_time_factor
= e
->removal_time_factor
;
7361 packet
.defense_bonus
= e
->defense_bonus
;
7362 packet
.eus
= e
->eus
;
7364 packet
.native_to
= e
->native_to
;
7366 packet
.flags
= e
->flags
;
7367 packet
.hidden_by
= e
->hidden_by
;
7368 packet
.conflicts
= e
->conflicts
;
7370 PACKET_STRVEC_COMPUTE(packet
.helptext
, e
->helptext
);
7372 lsend_packet_ruleset_extra(dest
, &packet
);
7373 } extra_type_iterate_end
;
7376 /**************************************************************************
7377 Send the base ruleset information (all individual base types) to the
7378 specified connections.
7379 **************************************************************************/
7380 static void send_ruleset_bases(struct conn_list
*dest
)
7382 extra_type_by_cause_iterate(EC_BASE
, pextra
) {
7383 struct base_type
*b
= extra_base_get(pextra
);
7384 struct packet_ruleset_base packet
;
7386 packet
.id
= base_number(b
);
7388 packet
.gui_type
= b
->gui_type
;
7389 packet
.border_sq
= b
->border_sq
;
7390 packet
.vision_main_sq
= b
->vision_main_sq
;
7391 packet
.vision_invis_sq
= b
->vision_invis_sq
;
7393 packet
.flags
= b
->flags
;
7395 lsend_packet_ruleset_base(dest
, &packet
);
7396 } extra_type_by_cause_iterate_end
;
7399 /**************************************************************************
7400 Send the road ruleset information (all individual road types) to the
7401 specified connections.
7402 **************************************************************************/
7403 static void send_ruleset_roads(struct conn_list
*dest
)
7405 struct packet_ruleset_road packet
;
7407 extra_type_by_cause_iterate(EC_ROAD
, pextra
) {
7408 struct road_type
*r
= extra_road_get(pextra
);
7411 packet
.id
= road_number(r
);
7414 requirement_vector_iterate(&r
->first_reqs
, preq
) {
7415 packet
.first_reqs
[j
++] = *preq
;
7416 } requirement_vector_iterate_end
;
7417 packet
.first_reqs_count
= j
;
7419 packet
.move_cost
= r
->move_cost
;
7420 packet
.move_mode
= r
->move_mode
;
7422 output_type_iterate(o
) {
7423 packet
.tile_incr_const
[o
] = r
->tile_incr_const
[o
];
7424 packet
.tile_incr
[o
] = r
->tile_incr
[o
];
7425 packet
.tile_bonus
[o
] = r
->tile_bonus
[o
];
7426 } output_type_iterate_end
;
7428 packet
.compat
= r
->compat
;
7430 packet
.integrates
= r
->integrates
;
7431 packet
.flags
= r
->flags
;
7433 lsend_packet_ruleset_road(dest
, &packet
);
7434 } extra_type_by_cause_iterate_end
;
7437 /**************************************************************************
7438 Send the goods ruleset information (all individual goods types) to the
7439 specified connections.
7440 **************************************************************************/
7441 static void send_ruleset_goods(struct conn_list
*dest
)
7443 struct packet_ruleset_goods packet
;
7445 goods_type_iterate(g
) {
7448 packet
.id
= goods_number(g
);
7449 sz_strlcpy(packet
.name
, untranslated_name(&g
->name
));
7450 sz_strlcpy(packet
.rule_name
, rule_name_get(&g
->name
));
7453 requirement_vector_iterate(&g
->reqs
, preq
) {
7454 packet
.reqs
[j
++] = *preq
;
7455 } requirement_vector_iterate_end
;
7456 packet
.reqs_count
= j
;
7458 packet
.from_pct
= g
->from_pct
;
7459 packet
.to_pct
= g
->to_pct
;
7460 packet
.flags
= g
->flags
;
7462 PACKET_STRVEC_COMPUTE(packet
.helptext
, g
->helptext
);
7464 lsend_packet_ruleset_goods(dest
, &packet
);
7465 } goods_type_iterate_end
;
7468 /**************************************************************************
7469 Send the disaster ruleset information (all individual disaster types) to the
7470 specified connections.
7471 **************************************************************************/
7472 static void send_ruleset_disasters(struct conn_list
*dest
)
7474 struct packet_ruleset_disaster packet
;
7476 disaster_type_iterate(d
) {
7479 packet
.id
= disaster_number(d
);
7481 sz_strlcpy(packet
.name
, untranslated_name(&d
->name
));
7482 sz_strlcpy(packet
.rule_name
, rule_name_get(&d
->name
));
7485 requirement_vector_iterate(&d
->reqs
, preq
) {
7486 packet
.reqs
[j
++] = *preq
;
7487 } requirement_vector_iterate_end
;
7488 packet
.reqs_count
= j
;
7490 packet
.frequency
= d
->frequency
;
7492 packet
.effects
= d
->effects
;
7494 lsend_packet_ruleset_disaster(dest
, &packet
);
7495 } disaster_type_iterate_end
;
7498 /**************************************************************************
7499 Send the achievement ruleset information (all individual achievement types)
7500 to the specified connections.
7501 **************************************************************************/
7502 static void send_ruleset_achievements(struct conn_list
*dest
)
7504 struct packet_ruleset_achievement packet
;
7506 achievements_iterate(a
) {
7507 packet
.id
= achievement_number(a
);
7509 sz_strlcpy(packet
.name
, untranslated_name(&a
->name
));
7510 sz_strlcpy(packet
.rule_name
, rule_name_get(&a
->name
));
7512 packet
.type
= a
->type
;
7513 packet
.unique
= a
->unique
;
7514 packet
.value
= a
->value
;
7516 lsend_packet_ruleset_achievement(dest
, &packet
);
7517 } achievements_iterate_end
;
7520 /**************************************************************************
7521 Send action ruleset information to the specified connections.
7522 **************************************************************************/
7523 static void send_ruleset_actions(struct conn_list
*dest
)
7525 struct packet_ruleset_action packet
;
7527 action_iterate(act
) {
7529 sz_strlcpy(packet
.ui_name
, action_by_number(act
)->ui_name
);
7530 packet
.quiet
= action_by_number(act
)->quiet
;
7532 packet
.act_kind
= action_by_number(act
)->actor_kind
;
7533 packet
.tgt_kind
= action_by_number(act
)->target_kind
;
7535 packet
.min_distance
= action_by_number(act
)->min_distance
;
7536 packet
.max_distance
= action_by_number(act
)->max_distance
;
7537 packet
.blocked_by
= action_by_number(act
)->blocked_by
;
7539 lsend_packet_ruleset_action(dest
, &packet
);
7540 } action_iterate_end
;
7543 /**************************************************************************
7544 Send the action enabler ruleset information to the specified connections.
7545 **************************************************************************/
7546 static void send_ruleset_action_enablers(struct conn_list
*dest
)
7549 struct packet_ruleset_action_enabler packet
;
7551 action_enablers_iterate(enabler
) {
7552 packet
.enabled_action
= enabler
->action
;
7555 requirement_vector_iterate(&enabler
->actor_reqs
, req
) {
7556 packet
.actor_reqs
[counter
++] = *req
;
7557 } requirement_vector_iterate_end
;
7558 packet
.actor_reqs_count
= counter
;
7561 requirement_vector_iterate(&enabler
->target_reqs
, req
) {
7562 packet
.target_reqs
[counter
++] = *req
;
7563 } requirement_vector_iterate_end
;
7564 packet
.target_reqs_count
= counter
;
7566 lsend_packet_ruleset_action_enabler(dest
, &packet
);
7567 } action_enablers_iterate_end
;
7570 /**************************************************************************
7571 Send action auto performer ruleset information to the specified
7573 **************************************************************************/
7574 static void send_ruleset_action_auto_performers(struct conn_list
*dest
)
7578 struct packet_ruleset_action_auto packet
;
7581 action_auto_perf_iterate(aperf
) {
7584 packet
.cause
= aperf
->cause
;
7587 requirement_vector_iterate(&aperf
->reqs
, req
) {
7588 packet
.reqs
[counter
++] = *req
;
7589 } requirement_vector_iterate_end
;
7590 packet
.reqs_count
= counter
;
7593 /* Can't list more actions than all actions. */
7594 counter
< NUM_ACTIONS
7595 /* ACTION_NONE terminates the list. */
7596 && aperf
->alternatives
[counter
] != ACTION_NONE
;
7598 packet
.alternatives
[counter
] = aperf
->alternatives
[counter
];
7600 packet
.alternatives_count
= counter
;
7602 lsend_packet_ruleset_action_auto(dest
, &packet
);
7603 } action_auto_perf_iterate_end
;
7606 /**************************************************************************
7607 Send the disaster ruleset information (all individual disaster types) to the
7608 specified connections.
7609 **************************************************************************/
7610 static void send_ruleset_trade_routes(struct conn_list
*dest
)
7612 struct packet_ruleset_trade packet
;
7613 enum trade_route_type type
;
7615 for (type
= TRT_NATIONAL
; type
< TRT_LAST
; type
++) {
7616 struct trade_route_settings
*set
= trade_route_settings_by_type(type
);
7619 packet
.trade_pct
= set
->trade_pct
;
7620 packet
.cancelling
= set
->cancelling
;
7621 packet
.bonus_type
= set
->bonus_type
;
7623 lsend_packet_ruleset_trade(dest
, &packet
);
7627 /**************************************************************************
7628 Send the government ruleset information to the specified connections.
7629 One packet per government type, and for each type one per ruler title.
7630 **************************************************************************/
7631 static void send_ruleset_governments(struct conn_list
*dest
)
7633 struct packet_ruleset_government gov
;
7634 struct packet_ruleset_government_ruler_title title
;
7637 governments_iterate(g
) {
7638 /* send one packet_government */
7639 gov
.id
= government_number(g
);
7642 requirement_vector_iterate(&g
->reqs
, preq
) {
7643 gov
.reqs
[j
++] = *preq
;
7644 } requirement_vector_iterate_end
;
7647 sz_strlcpy(gov
.name
, untranslated_name(&g
->name
));
7648 sz_strlcpy(gov
.rule_name
, rule_name_get(&g
->name
));
7649 sz_strlcpy(gov
.graphic_str
, g
->graphic_str
);
7650 sz_strlcpy(gov
.graphic_alt
, g
->graphic_alt
);
7651 PACKET_STRVEC_COMPUTE(gov
.helptext
, g
->helptext
);
7653 lsend_packet_ruleset_government(dest
, &gov
);
7655 /* Send one packet_government_ruler_title per ruler title. */
7656 ruler_titles_iterate(government_ruler_titles(g
), pruler_title
) {
7657 const struct nation_type
*pnation
= ruler_title_nation(pruler_title
);
7659 title
.gov
= government_number(g
);
7660 title
.nation
= pnation
? nation_number(pnation
) : nation_count();
7661 sz_strlcpy(title
.male_title
,
7662 ruler_title_male_untranslated_name(pruler_title
));
7663 sz_strlcpy(title
.female_title
,
7664 ruler_title_female_untranslated_name(pruler_title
));
7665 lsend_packet_ruleset_government_ruler_title(dest
, &title
);
7666 } ruler_titles_iterate_end
;
7667 } governments_iterate_end
;
7670 /**************************************************************************
7671 Send the nations ruleset information (info on each nation) to the
7672 specified connections.
7673 **************************************************************************/
7674 static void send_ruleset_nations(struct conn_list
*dest
)
7676 struct packet_ruleset_nation_sets sets_packet
;
7677 struct packet_ruleset_nation_groups groups_packet
;
7678 struct packet_ruleset_nation packet
;
7681 sets_packet
.nsets
= nation_set_count();
7683 nation_sets_iterate(pset
) {
7684 sz_strlcpy(sets_packet
.names
[i
], nation_set_untranslated_name(pset
));
7685 sz_strlcpy(sets_packet
.rule_names
[i
], nation_set_rule_name(pset
));
7686 sz_strlcpy(sets_packet
.descriptions
[i
], nation_set_description(pset
));
7688 } nation_sets_iterate_end
;
7689 lsend_packet_ruleset_nation_sets(dest
, &sets_packet
);
7691 groups_packet
.ngroups
= nation_group_count();
7693 nation_groups_iterate(pgroup
) {
7694 sz_strlcpy(groups_packet
.groups
[i
],
7695 nation_group_untranslated_name(pgroup
));
7696 groups_packet
.hidden
[i
] = pgroup
->hidden
;
7698 } nation_groups_iterate_end
;
7699 lsend_packet_ruleset_nation_groups(dest
, &groups_packet
);
7701 nations_iterate(n
) {
7702 packet
.id
= nation_number(n
);
7703 if (n
->translation_domain
== NULL
) {
7704 packet
.translation_domain
[0] = '\0';
7706 sz_strlcpy(packet
.translation_domain
, n
->translation_domain
);
7708 sz_strlcpy(packet
.adjective
, untranslated_name(&n
->adjective
));
7709 sz_strlcpy(packet
.rule_name
, rule_name_get(&n
->adjective
));
7710 sz_strlcpy(packet
.noun_plural
, untranslated_name(&n
->noun_plural
));
7711 sz_strlcpy(packet
.graphic_str
, n
->flag_graphic_str
);
7712 sz_strlcpy(packet
.graphic_alt
, n
->flag_graphic_alt
);
7715 nation_leader_list_iterate(nation_leaders(n
), pleader
) {
7716 sz_strlcpy(packet
.leader_name
[i
], nation_leader_name(pleader
));
7717 packet
.leader_is_male
[i
] = nation_leader_is_male(pleader
);
7719 } nation_leader_list_iterate_end
;
7720 packet
.leader_count
= i
;
7722 packet
.style
= style_number(n
->style
);
7723 packet
.is_playable
= n
->is_playable
;
7724 packet
.barbarian_type
= n
->barb_type
;
7726 sz_strlcpy(packet
.legend
, n
->legend
);
7729 nation_set_list_iterate(n
->sets
, pset
) {
7730 packet
.sets
[i
++] = nation_set_number(pset
);
7731 } nation_set_list_iterate_end
;
7735 nation_group_list_iterate(n
->groups
, pgroup
) {
7736 packet
.groups
[i
++] = nation_group_number(pgroup
);
7737 } nation_group_list_iterate_end
;
7740 packet
.init_government_id
= n
->init_government
7741 ? government_number(n
->init_government
) : government_count();
7742 fc_assert(ARRAY_SIZE(packet
.init_techs
) == ARRAY_SIZE(n
->init_techs
));
7743 for (i
= 0; i
< MAX_NUM_TECH_LIST
; i
++) {
7744 packet
.init_techs
[i
] = n
->init_techs
[i
];
7746 fc_assert(ARRAY_SIZE(packet
.init_units
) == ARRAY_SIZE(n
->init_units
));
7747 for (i
= 0; i
< MAX_NUM_UNIT_LIST
; i
++) {
7748 const struct unit_type
*t
= n
->init_units
[i
];
7749 packet
.init_units
[i
] = t
? utype_number(t
) : U_LAST
;
7751 fc_assert(ARRAY_SIZE(packet
.init_buildings
)
7752 == ARRAY_SIZE(n
->init_buildings
));
7753 for (i
= 0; i
< MAX_NUM_BUILDING_LIST
; i
++) {
7754 /* Impr_type_id to int */
7755 packet
.init_buildings
[i
] = n
->init_buildings
[i
];
7758 lsend_packet_ruleset_nation(dest
, &packet
);
7759 } nations_iterate_end
;
7761 /* Send initial values of is_pickable */
7762 send_nation_availability(dest
, FALSE
);
7765 /**************************************************************************
7766 Send the nation style ruleset information (each style) to the specified
7768 **************************************************************************/
7769 static void send_ruleset_styles(struct conn_list
*dest
)
7771 struct packet_ruleset_style packet
;
7774 packet
.id
= style_index(s
);
7775 sz_strlcpy(packet
.name
, untranslated_name(&s
->name
));
7776 sz_strlcpy(packet
.rule_name
, rule_name_get(&s
->name
));
7778 lsend_packet_ruleset_style(dest
, &packet
);
7779 } styles_iterate_end
;
7782 /**************************************************************************
7783 Send the multiplier ruleset information to the specified
7785 **************************************************************************/
7786 static void send_ruleset_multipliers(struct conn_list
*dest
)
7788 char helptext
[MAX_LEN_PACKET
];
7790 multipliers_iterate(pmul
) {
7791 PACKET_STRVEC_COMPUTE(helptext
, pmul
->helptext
);
7793 dlsend_packet_ruleset_multiplier(dest
, multiplier_number(pmul
),
7794 pmul
->start
, pmul
->stop
,
7795 pmul
->step
, pmul
->def
,
7796 pmul
->offset
, pmul
->factor
,
7797 untranslated_name(&pmul
->name
),
7798 rule_name_get(&pmul
->name
),
7800 } multipliers_iterate_end
;
7803 /**************************************************************************
7804 Send the city-style ruleset information (each style) to the specified
7806 **************************************************************************/
7807 static void send_ruleset_cities(struct conn_list
*dest
)
7809 struct packet_ruleset_city city_p
;
7812 for (k
= 0; k
< game
.control
.styles_count
; k
++) {
7813 city_p
.style_id
= k
;
7816 requirement_vector_iterate(&city_styles
[k
].reqs
, preq
) {
7817 city_p
.reqs
[j
++] = *preq
;
7818 } requirement_vector_iterate_end
;
7819 city_p
.reqs_count
= j
;
7821 sz_strlcpy(city_p
.name
, untranslated_name(&city_styles
[k
].name
));
7822 sz_strlcpy(city_p
.rule_name
, rule_name_get(&city_styles
[k
].name
));
7823 sz_strlcpy(city_p
.graphic
, city_styles
[k
].graphic
);
7824 sz_strlcpy(city_p
.graphic_alt
, city_styles
[k
].graphic_alt
);
7825 sz_strlcpy(city_p
.citizens_graphic
, city_styles
[k
].citizens_graphic
);
7826 sz_strlcpy(city_p
.citizens_graphic_alt
,
7827 city_styles
[k
].citizens_graphic_alt
);
7829 lsend_packet_ruleset_city(dest
, &city_p
);
7833 /**************************************************************************
7834 Send the music-style ruleset information (each style) to the specified
7836 **************************************************************************/
7837 static void send_ruleset_musics(struct conn_list
*dest
)
7839 struct packet_ruleset_music packet
;
7841 music_styles_iterate(pmus
) {
7844 packet
.id
= pmus
->id
;
7846 sz_strlcpy(packet
.music_peaceful
, pmus
->music_peaceful
);
7847 sz_strlcpy(packet
.music_combat
, pmus
->music_combat
);
7850 requirement_vector_iterate(&(pmus
->reqs
), preq
) {
7851 packet
.reqs
[j
++] = *preq
;
7852 } requirement_vector_iterate_end
;
7853 packet
.reqs_count
= j
;
7855 lsend_packet_ruleset_music(dest
, &packet
);
7856 } music_styles_iterate_end
;
7859 /**************************************************************************
7860 Send information in packet_ruleset_game (miscellaneous rules) to the
7861 specified connections.
7862 **************************************************************************/
7863 static void send_ruleset_game(struct conn_list
*dest
)
7865 struct packet_ruleset_game misc_p
;
7868 fc_assert_ret(game
.veteran
!= NULL
);
7870 /* Per unit veteran system definition. */
7871 misc_p
.veteran_levels
= game
.veteran
->levels
;
7873 for (i
= 0; i
< misc_p
.veteran_levels
; i
++) {
7874 const struct veteran_level
*vlevel
= game
.veteran
->definitions
+ i
;
7876 sz_strlcpy(misc_p
.veteran_name
[i
], untranslated_name(&vlevel
->name
));
7877 misc_p
.power_fact
[i
] = vlevel
->power_fact
;
7878 misc_p
.move_bonus
[i
] = vlevel
->move_bonus
;
7881 fc_assert(sizeof(misc_p
.global_init_techs
)
7882 == sizeof(game
.rgame
.global_init_techs
));
7883 fc_assert(ARRAY_SIZE(misc_p
.global_init_techs
)
7884 == ARRAY_SIZE(game
.rgame
.global_init_techs
));
7885 memcpy(misc_p
.global_init_techs
, game
.rgame
.global_init_techs
,
7886 sizeof(misc_p
.global_init_techs
));
7888 fc_assert(ARRAY_SIZE(misc_p
.global_init_buildings
)
7889 == ARRAY_SIZE(game
.rgame
.global_init_buildings
));
7890 for (i
= 0; i
< MAX_NUM_BUILDING_LIST
; i
++) {
7891 /* Impr_type_id to int */
7892 misc_p
.global_init_buildings
[i
] =
7893 game
.rgame
.global_init_buildings
[i
];
7896 misc_p
.default_specialist
= DEFAULT_SPECIALIST
;
7898 fc_assert_ret(game
.plr_bg_color
!= NULL
);
7900 misc_p
.background_red
= game
.plr_bg_color
->r
;
7901 misc_p
.background_green
= game
.plr_bg_color
->g
;
7902 misc_p
.background_blue
= game
.plr_bg_color
->b
;
7904 lsend_packet_ruleset_game(dest
, &misc_p
);
7907 /**************************************************************************
7908 Send all team names defined in the ruleset file(s) to the
7909 specified connections.
7910 **************************************************************************/
7911 static void send_ruleset_team_names(struct conn_list
*dest
)
7913 struct packet_team_name_info team_name_info_p
;
7915 team_slots_iterate(tslot
) {
7916 const char *name
= team_slot_defined_name(tslot
);
7919 /* End of defined names. */
7923 team_name_info_p
.team_id
= team_slot_index(tslot
);
7924 sz_strlcpy(team_name_info_p
.team_name
, name
);
7926 lsend_packet_team_name_info(dest
, &team_name_info_p
);
7927 } team_slots_iterate_end
;
7930 /**************************************************************************
7931 Make it clear to everyone that requested ruleset has not been loaded.
7932 **************************************************************************/
7933 static void notify_ruleset_fallback(const char *msg
)
7935 notify_conn(NULL
, NULL
, E_LOG_FATAL
, ftc_warning
, "%s", msg
);
7938 /**************************************************************************
7940 **************************************************************************/
7941 bool load_rulesets(const char *restore
, bool compat_mode
,
7942 bool act
, bool buffer_script
)
7944 if (load_rulesetdir(game
.server
.rulesetdir
, compat_mode
, act
, buffer_script
)) {
7948 /* Fallback to previous one. */
7949 if (restore
!= NULL
) {
7950 if (load_rulesetdir(restore
, compat_mode
, act
, buffer_script
)) {
7951 sz_strlcpy(game
.server
.rulesetdir
, restore
);
7953 notify_ruleset_fallback(_("Ruleset couldn't be loaded. Keeping previous one."));
7955 /* We're in sane state as restoring previous ruleset succeeded,
7956 * but return failure to indicate that this is not what caller
7962 /* Fallback to default one, but not if that's what we tried already */
7963 if (strcmp(GAME_DEFAULT_RULESETDIR
, game
.server
.rulesetdir
)
7964 && (restore
== NULL
|| strcmp(GAME_DEFAULT_RULESETDIR
, restore
))) {
7965 if (load_rulesetdir(GAME_DEFAULT_RULESETDIR
, FALSE
, act
, buffer_script
)) {
7966 /* We're in sane state as fallback ruleset loading succeeded,
7967 * but return failure to indicate that this is not what caller
7969 sz_strlcpy(game
.server
.rulesetdir
, GAME_DEFAULT_RULESETDIR
);
7971 notify_ruleset_fallback(_("Ruleset couldn't be loaded. Switching to default one."));
7978 log_normal(_("Cannot load any ruleset. Freeciv-web ruleset is available from "
7979 "https://github.com/freeciv/freeciv-web"));
7980 #endif /* FREECIV_WEB */
7982 /* Cannot load even default ruleset, we're in completely unusable state */
7986 /**************************************************************************
7987 destroy secfile. Handle NULL parameter gracefully.
7988 **************************************************************************/
7989 static void nullcheck_secfile_destroy(struct section_file
*file
)
7992 secfile_destroy(file
);
7996 /**************************************************************************
7997 Completely deinitialize ruleset system. Server is not in usable
7999 **************************************************************************/
8000 void rulesets_deinit(void)
8002 script_server_free();
8003 requirement_vector_free(&reqs_list
);
8006 /**************************************************************************
8007 Loads the rulesets from directory.
8008 This may be called more than once and it will free any stale data.
8009 **************************************************************************/
8010 static bool load_rulesetdir(const char *rsdir
, bool compat_mode
,
8011 bool act
, bool buffer_script
)
8013 struct section_file
*techfile
, *unitfile
, *buildfile
, *govfile
, *terrfile
;
8014 struct section_file
*stylefile
, *cityfile
, *nationfile
, *effectfile
, *gamefile
;
8016 struct rscompat_info compat_info
;
8018 log_normal(_("Loading rulesets."));
8020 rscompat_init_info(&compat_info
);
8021 compat_info
.compat_mode
= compat_mode
;
8023 game_ruleset_free();
8024 /* Reset the list of available player colors. */
8027 game_ruleset_init();
8029 if (script_buffer
!= NULL
) {
8030 FC_FREE(script_buffer
);
8031 script_buffer
= NULL
;
8033 if (parser_buffer
!= NULL
) {
8034 FC_FREE(parser_buffer
);
8035 parser_buffer
= NULL
;
8038 server
.playable_nations
= 0;
8040 techfile
= openload_ruleset_file("techs", rsdir
);
8041 buildfile
= openload_ruleset_file("buildings", rsdir
);
8042 govfile
= openload_ruleset_file("governments", rsdir
);
8043 unitfile
= openload_ruleset_file("units", rsdir
);
8044 terrfile
= openload_ruleset_file("terrain", rsdir
);
8045 stylefile
= openload_ruleset_file("styles", rsdir
);
8046 cityfile
= openload_ruleset_file("cities", rsdir
);
8047 nationfile
= openload_ruleset_file("nations", rsdir
);
8048 effectfile
= openload_ruleset_file("effects", rsdir
);
8049 gamefile
= openload_ruleset_file("game", rsdir
);
8050 game
.server
.luadata
= openload_luadata_file(rsdir
);
8052 if (techfile
== NULL
8053 || buildfile
== NULL
8057 || stylefile
== NULL
8059 || nationfile
== NULL
8060 || effectfile
== NULL
8061 || gamefile
== NULL
) {
8066 ok
= load_game_names(gamefile
, &compat_info
)
8067 && load_tech_names(techfile
, &compat_info
)
8068 && load_building_names(buildfile
, &compat_info
)
8069 && load_government_names(govfile
, &compat_info
)
8070 && load_unit_names(unitfile
, &compat_info
)
8071 && load_terrain_names(terrfile
, &compat_info
)
8072 && load_style_names(stylefile
, &compat_info
)
8073 && load_nation_names(nationfile
, &compat_info
);
8077 ok
= rscompat_names(&compat_info
);
8081 ok
= load_ruleset_techs(techfile
, &compat_info
);
8084 ok
= load_ruleset_styles(stylefile
, &compat_info
);
8087 ok
= load_ruleset_cities(cityfile
, &compat_info
);
8090 ok
= load_ruleset_governments(govfile
, &compat_info
);
8093 /* terrain must precede nations and units */
8094 ok
= load_ruleset_terrain(terrfile
, &compat_info
);
8097 ok
= load_ruleset_units(unitfile
, &compat_info
);
8100 ok
= load_ruleset_buildings(buildfile
, &compat_info
);
8103 ok
= load_ruleset_nations(nationfile
, &compat_info
);
8106 ok
= load_ruleset_effects(effectfile
, &compat_info
);
8109 ok
= load_ruleset_game(gamefile
, act
, &compat_info
);
8113 /* Init nations we just loaded. */
8114 update_nations_with_startpos();
8116 /* Needed by role_unit_precalcs(). */
8117 unit_type_action_cache_init();
8119 /* Prepare caches we want to sanity check. */
8120 role_unit_precalcs();
8121 road_integrators_cache_init();
8122 actions_rs_pre_san_gen();
8124 ok
= autoadjust_ruleset_data()
8125 && sanity_check_ruleset_data(compat_info
.compat_mode
);
8129 /* Only load settings for a sane ruleset */
8130 ok
= settings_ruleset(gamefile
, "settings", act
);
8133 secfile_check_unused(gamefile
);
8137 nullcheck_secfile_destroy(techfile
);
8138 nullcheck_secfile_destroy(stylefile
);
8139 nullcheck_secfile_destroy(cityfile
);
8140 nullcheck_secfile_destroy(govfile
);
8141 nullcheck_secfile_destroy(terrfile
);
8142 nullcheck_secfile_destroy(unitfile
);
8143 nullcheck_secfile_destroy(buildfile
);
8144 nullcheck_secfile_destroy(nationfile
);
8145 nullcheck_secfile_destroy(effectfile
);
8146 nullcheck_secfile_destroy(gamefile
);
8148 if (extra_sections
) {
8149 free(extra_sections
);
8150 extra_sections
= NULL
;
8152 if (base_sections
) {
8153 free(base_sections
);
8154 base_sections
= NULL
;
8156 if (road_sections
) {
8157 free(road_sections
);
8158 road_sections
= NULL
;
8160 if (resource_sections
) {
8161 free(resource_sections
);
8162 resource_sections
= NULL
;
8164 if (terrain_sections
) {
8165 free(terrain_sections
);
8166 terrain_sections
= NULL
;
8170 rscompat_postprocess(&compat_info
);
8174 char **buffer
= buffer_script
? &script_buffer
: NULL
;
8176 script_server_free();
8178 script_server_init();
8180 ok
= openload_script_file("script", rsdir
, buffer
);
8184 char **buffer
= buffer_script
? &parser_buffer
: NULL
;
8186 ok
= openload_script_file("parser", rsdir
, buffer
);
8189 if (ok
&& !buffer_script
) {
8190 ok
= openload_script_file("default", rsdir
, NULL
);
8194 /* Populate remaining caches. */
8195 techs_precalc_data();
8196 improvement_feature_cache_init();
8197 unit_class_iterate(pclass
) {
8198 set_unit_class_caches(pclass
);
8199 } unit_class_iterate_end
;
8200 unit_type_iterate(ptype
) {
8201 ptype
->unknown_move_cost
= utype_unknown_move_cost(ptype
);
8202 set_unit_type_caches(ptype
);
8203 } unit_type_iterate_end
;
8204 city_production_caravan_shields_init();
8206 /* Build advisors unit class cache corresponding to loaded rulesets */
8207 adv_units_ruleset_init();
8208 CALL_FUNC_EACH_AI(units_ruleset_init
);
8210 /* We may need to adjust the number of AI players
8211 * if the number of available nations changed. */
8212 (void) aifill(game
.info
.aifill
);
8218 /**************************************************************************
8219 Reload the game settings saved in the ruleset file.
8220 **************************************************************************/
8221 bool reload_rulesets_settings(void)
8223 struct section_file
*file
;
8226 file
= openload_ruleset_file("game", game
.server
.rulesetdir
);
8228 ruleset_error(LOG_ERROR
, "Could not load game.ruleset:\n%s",
8233 settings_ruleset(file
, "settings", TRUE
);
8234 secfile_destroy(file
);
8240 /**************************************************************************
8241 Send all ruleset information to the specified connections.
8242 **************************************************************************/
8243 void send_rulesets(struct conn_list
*dest
)
8245 conn_list_compression_freeze(dest
);
8247 /* ruleset_control also indicates to client that ruleset sending starts. */
8248 send_ruleset_control(dest
);
8250 send_ruleset_game(dest
);
8251 send_ruleset_disasters(dest
);
8252 send_ruleset_achievements(dest
);
8253 send_ruleset_trade_routes(dest
);
8254 send_ruleset_team_names(dest
);
8255 send_ruleset_actions(dest
);
8256 send_ruleset_action_enablers(dest
);
8257 send_ruleset_action_auto_performers(dest
);
8258 send_ruleset_tech_classes(dest
);
8259 send_ruleset_techs(dest
);
8260 send_ruleset_governments(dest
);
8261 send_ruleset_unit_classes(dest
);
8262 send_ruleset_units(dest
);
8263 send_ruleset_specialists(dest
);
8264 send_ruleset_extras(dest
);
8265 send_ruleset_bases(dest
);
8266 send_ruleset_roads(dest
);
8267 send_ruleset_resources(dest
);
8268 send_ruleset_terrain(dest
);
8269 send_ruleset_goods(dest
);
8270 send_ruleset_buildings(dest
);
8271 send_ruleset_nations(dest
);
8272 send_ruleset_styles(dest
);
8273 send_ruleset_cities(dest
);
8274 send_ruleset_multipliers(dest
);
8275 send_ruleset_musics(dest
);
8276 send_ruleset_cache(dest
);
8278 /* Indicate client that all rulesets have now been sent. */
8279 lsend_packet_rulesets_ready(dest
);
8281 /* changed game settings will be send in
8282 * connecthand.c:establish_new_connection() */
8284 conn_list_compression_thaw(dest
);