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
;
198 /**************************************************************************
199 Notifications about ruleset errors to clients. Especially important in
200 case of internal server crashing.
201 **************************************************************************/
202 void ruleset_error_real(const char *file
, const char *function
,
203 int line
, enum log_level level
,
204 const char *format
, ...)
209 va_start(args
, format
);
210 vdo_log(file
, function
, line
, FALSE
, level
, buf
, sizeof(buf
), format
, args
);
213 if (LOG_FATAL
>= level
) {
218 /**************************************************************************
219 datafilename() wrapper: tries to match in two ways.
220 Returns NULL on failure, the (statically allocated) filename on success.
221 **************************************************************************/
222 static const char *valid_ruleset_filename(const char *subdir
,
224 const char *extension
)
227 const char *dfilename
;
229 fc_assert_ret_val(subdir
&& name
&& extension
, NULL
);
231 fc_snprintf(filename
, sizeof(filename
), "%s" DIR_SEPARATOR
"%s.%s",
232 subdir
, name
, extension
);
233 log_verbose("Trying \"%s\".", filename
);
234 dfilename
= fileinfoname(get_data_dirs(), filename
);
239 fc_snprintf(filename
, sizeof(filename
), "default" DIR_SEPARATOR
"%s.%s", name
, extension
);
240 log_verbose("Trying \"%s\": default ruleset directory.", filename
);
241 dfilename
= fileinfoname(get_data_dirs(), filename
);
246 fc_snprintf(filename
, sizeof(filename
), "%s_%s.%s",
247 subdir
, name
, extension
);
248 log_verbose("Trying \"%s\": alternative ruleset filename syntax.",
250 dfilename
= fileinfoname(get_data_dirs(), filename
);
254 ruleset_error(LOG_ERROR
,
255 /* TRANS: message about an installation error. */
256 _("Could not find a readable \"%s.%s\" ruleset file."),
263 /**************************************************************************
264 Return current script.lua buffer.
265 **************************************************************************/
266 char *get_script_buffer(void)
268 return script_buffer
;
271 /**************************************************************************
272 Do initial section_file_load on a ruleset file.
273 "whichset" = "techs", "units", "buildings", "terrain", ...
274 **************************************************************************/
275 static struct section_file
*openload_ruleset_file(const char *whichset
,
279 const char *dfilename
= valid_ruleset_filename(rsdir
, whichset
,
281 struct section_file
*secfile
;
283 if (dfilename
== NULL
) {
287 /* Need to save a copy of the filename for following message, since
288 section_file_load() may call datafilename() for includes. */
289 sz_strlcpy(sfilename
, dfilename
);
290 secfile
= secfile_load(sfilename
, FALSE
);
292 if (secfile
== NULL
) {
293 ruleset_error(LOG_ERROR
, "Could not load ruleset '%s':\n%s",
294 sfilename
, secfile_error());
300 /**************************************************************************
302 **************************************************************************/
303 static bool openload_script_file(const char *whichset
, const char *rsdir
,
306 const char *dfilename
= valid_ruleset_filename(rsdir
, whichset
,
309 if (dfilename
== NULL
) {
313 if (buffer
== NULL
) {
314 if (!script_server_do_file(NULL
, dfilename
)) {
315 ruleset_error(LOG_ERROR
, "\"%s\": could not load ruleset script.",
321 script_server_load_file(dfilename
, buffer
);
327 /**************************************************************************
328 Load a requirement list. The list is returned as a static vector
329 (callers need not worry about freeing anything).
330 **************************************************************************/
331 static struct requirement_vector
*lookup_req_list(struct section_file
*file
,
332 struct rscompat_info
*compat
,
337 const char *type
, *name
;
339 const char *filename
;
341 filename
= secfile_name(file
);
343 requirement_vector_reserve(&reqs_list
, 0);
345 for (j
= 0; (type
= secfile_lookup_str_default(file
, NULL
, "%s.%s%d.type",
346 sec
, sub
, j
)); j
++) {
347 char buf
[MAX_LEN_NAME
];
349 bool survives
, present
, quiet
;
350 struct entry
*pentry
;
351 struct requirement req
;
353 if (!(pentry
= secfile_entry_lookup(file
, "%s.%s%d.name",
355 ruleset_error(LOG_ERROR
, "%s", secfile_error());
360 switch (entry_type(pentry
)) {
365 if (entry_bool_get(pentry
, &val
)) {
366 fc_snprintf(buf
, sizeof(buf
), "%d", val
);
375 if (entry_int_get(pentry
, &val
)) {
376 fc_snprintf(buf
, sizeof(buf
), "%d", val
);
382 (void) entry_str_get(pentry
, &name
);
385 fc_assert(entry_type(pentry
) != ENTRY_FLOAT
);
386 ruleset_error(LOG_ERROR
,
387 "\"%s\": trying to have an floating point entry as a requirement name in '%s.%s%d'.",
388 filename
, sec
, sub
, j
);
390 case ENTRY_FILEREFERENCE
:
391 fc_assert(entry_type(pentry
) != ENTRY_FILEREFERENCE
);
394 ruleset_error(LOG_ERROR
,
395 "\"%s\": error in handling requirement name for '%s.%s%d'.",
396 filename
, sec
, sub
, j
);
400 if (!(range
= secfile_lookup_str(file
, "%s.%s%d.range", sec
, sub
, j
))) {
401 ruleset_error(LOG_ERROR
, "%s", secfile_error());
407 if ((pentry
= secfile_entry_lookup(file
, "%s.%s%d.survives",
409 && !entry_bool_get(pentry
, &survives
)) {
410 ruleset_error(LOG_ERROR
,
411 "\"%s\": invalid boolean value for survives for "
412 "'%s.%s%d'.", filename
, sec
, sub
, j
);
416 if ((pentry
= secfile_entry_lookup(file
, "%s.%s%d.present",
418 && !entry_bool_get(pentry
, &present
)) {
419 ruleset_error(LOG_ERROR
,
420 "\"%s\": invalid boolean value for present for "
421 "'%s.%s%d'.", filename
, sec
, sub
, j
);
424 if ((pentry
= secfile_entry_lookup(file
, "%s.%s%d.quiet",
426 && !entry_bool_get(pentry
, &quiet
)) {
427 ruleset_error(LOG_ERROR
,
428 "\"%s\": invalid boolean value for quiet for "
429 "'%s.%s%d'.", filename
, sec
, sub
, j
);
432 if (compat
->compat_mode
) {
433 if (!fc_strcasecmp(type
, universals_n_name(VUT_UTFLAG
))) {
434 name
= rscompat_utype_flag_name_3_1(compat
, name
);
438 if (compat
->compat_mode
) {
439 name
= rscompat_req_name_3_1(type
, name
);
442 req
= req_from_str(type
, range
, survives
, present
, quiet
, name
);
443 if (req
.source
.kind
== universals_n_invalid()) {
444 ruleset_error(LOG_ERROR
, "\"%s\" [%s] has invalid or unknown req: "
446 filename
, sec
, type
, name
);
451 requirement_vector_append(&reqs_list
, req
);
454 if (j
> MAX_NUM_REQS
) {
455 ruleset_error(LOG_ERROR
, "Too many (%d) requirements for %s. Max is %d",
456 j
, rfor
, MAX_NUM_REQS
);
464 /**************************************************************************
465 Load combat bonus list
466 **************************************************************************/
467 static bool lookup_cbonus_list(struct rscompat_info
*compat
,
468 struct combat_bonus_list
*list
,
469 struct section_file
*file
,
475 const char *filename
;
478 filename
= secfile_name(file
);
480 for (j
= 0; (flag
= secfile_lookup_str_default(file
, NULL
, "%s.%s%d.flag",
481 sec
, sub
, j
)); j
++) {
482 struct combat_bonus
*bonus
= fc_malloc(sizeof(*bonus
));
485 bonus
->flag
= unit_type_flag_id_by_name(rscompat_utype_flag_name_3_1(compat
, flag
),
487 if (!unit_type_flag_id_is_valid(bonus
->flag
)) {
488 log_error("\"%s\": unknown flag name \"%s\" in '%s.%s'.",
489 filename
, flag
, sec
, sub
);
494 type
= secfile_lookup_str(file
, "%s.%s%d.type", sec
, sub
, j
);
495 bonus
->type
= combat_bonus_type_by_name(type
, fc_strcasecmp
);
496 if (!combat_bonus_type_is_valid(bonus
->type
)) {
497 log_error("\"%s\": unknown bonus type \"%s\" in '%s.%s'.",
498 filename
, type
, sec
, sub
);
503 if (!secfile_lookup_int(file
, &bonus
->value
, "%s.%s%d.value",
505 log_error("\"%s\": failed to get value from '%s.%s%d'.",
506 filename
, sec
, sub
, j
);
511 bonus
->quiet
= secfile_lookup_bool_default(file
, FALSE
,
514 combat_bonus_list_append(list
, bonus
);
520 /**************************************************************************
521 Lookup a string prefix.entry in the file and return the corresponding
522 advances pointer. If (!required), return A_NEVER for match "Never" or
523 can't match. If (required), die when can't match. Note the first tech
524 should have name "None" so that will always match.
525 If description is not NULL, it is used in the warning message
526 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
527 **************************************************************************/
528 static bool lookup_tech(struct section_file
*file
,
529 struct advance
**result
,
530 const char *prefix
, const char *entry
,
531 const char *filename
,
532 const char *description
)
536 sval
= secfile_lookup_str_default(file
, NULL
, "%s.%s", prefix
, entry
);
537 if (!sval
|| !strcmp(sval
, "Never")) {
540 *result
= advance_by_rule_name(sval
);
542 if (A_NEVER
== *result
) {
543 ruleset_error(LOG_ERROR
,
544 "\"%s\" %s %s: couldn't match \"%s\".",
545 filename
, (description
? description
: prefix
), entry
, sval
);
553 /**************************************************************************
554 Lookup a string prefix.entry in the file and return the corresponding
555 improvement pointer. Return B_NEVER for match "None" or
557 If description is not NULL, it is used in the warning message
558 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
559 **************************************************************************/
560 static bool lookup_building(struct section_file
*file
,
561 const char *prefix
, const char *entry
,
562 struct impr_type
**result
,
563 const char *filename
,
564 const char *description
)
569 sval
= secfile_lookup_str_default(file
, NULL
, "%s.%s", prefix
, entry
);
570 if (!sval
|| strcmp(sval
, "None") == 0) {
573 *result
= improvement_by_rule_name(sval
);
575 if (B_NEVER
== *result
) {
576 ruleset_error(LOG_ERROR
,
577 "\"%s\" %s %s: couldn't match \"%s\".",
578 filename
, (description
? description
: prefix
), entry
, sval
);
586 /**************************************************************************
587 Lookup a prefix.entry string vector in the file and fill in the
588 array, which should hold MAX_NUM_UNIT_LIST items. The output array is
589 either NULL terminated or full (contains MAX_NUM_UNIT_LIST
590 items). If the vector is not found and the required parameter is set,
591 we report it as an error, otherwise we just punt.
592 **************************************************************************/
593 static bool lookup_unit_list(struct section_file
*file
, const char *prefix
,
595 struct unit_type
**output
,
596 const char *filename
)
603 /* pre-fill with NULL: */
604 for (i
= 0; i
< MAX_NUM_UNIT_LIST
; i
++) {
607 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.%s", prefix
, entry
);
609 /* 'No vector' is considered same as empty vector */
615 if (nval
> MAX_NUM_UNIT_LIST
) {
616 ruleset_error(LOG_ERROR
,
617 "\"%s\": string vector %s.%s too long (%d, max %d)",
618 filename
, prefix
, entry
, (int) nval
, MAX_NUM_UNIT_LIST
);
620 } else if (nval
== 1 && strcmp(slist
[0], "") == 0) {
625 for (i
= 0; i
< nval
; i
++) {
626 const char *sval
= slist
[i
];
627 struct unit_type
*punittype
= unit_type_by_rule_name(sval
);
630 ruleset_error(LOG_ERROR
,
631 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
632 filename
, prefix
, entry
, i
, sval
);
636 output
[i
] = punittype
;
637 log_debug("\"%s\" %s.%s (%d): %s (%d)", filename
, prefix
, entry
, i
, sval
,
638 utype_number(punittype
));
646 /**************************************************************************
647 Lookup a prefix.entry string vector in the file and fill in the
648 array, which should hold MAX_NUM_TECH_LIST items. The output array is
649 either A_LAST terminated or full (contains MAX_NUM_TECH_LIST
650 items). All valid entries of the output array are guaranteed to
652 **************************************************************************/
653 static bool lookup_tech_list(struct section_file
*file
, const char *prefix
,
654 const char *entry
, int *output
,
655 const char *filename
)
662 /* pre-fill with A_LAST: */
663 for (i
= 0; i
< MAX_NUM_TECH_LIST
; i
++) {
666 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.%s", prefix
, entry
);
667 if (slist
== NULL
|| nval
== 0) {
669 } else if (nval
> MAX_NUM_TECH_LIST
) {
670 ruleset_error(LOG_ERROR
,
671 "\"%s\": string vector %s.%s too long (%d, max %d)",
672 filename
, prefix
, entry
, (int) nval
, MAX_NUM_TECH_LIST
);
677 if (nval
== 1 && strcmp(slist
[0], "") == 0) {
681 for (i
= 0; i
< nval
&& ok
; i
++) {
682 const char *sval
= slist
[i
];
683 struct advance
*padvance
= advance_by_rule_name(sval
);
685 if (NULL
== padvance
) {
686 ruleset_error(LOG_ERROR
,
687 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
688 filename
, prefix
, entry
, i
, sval
);
691 if (!valid_advance(padvance
)) {
692 ruleset_error(LOG_ERROR
, "\"%s\" %s.%s (%d): \"%s\" is removed.",
693 filename
, prefix
, entry
, i
, sval
);
698 output
[i
] = advance_number(padvance
);
699 log_debug("\"%s\" %s.%s (%d): %s (%d)", filename
, prefix
, entry
, i
, sval
,
700 advance_number(padvance
));
709 /**************************************************************************
710 Lookup a prefix.entry string vector in the file and fill in the
711 array, which should hold MAX_NUM_BUILDING_LIST items. The output array is
712 either B_LAST terminated or full (contains MAX_NUM_BUILDING_LIST
713 items). [All valid entries of the output array are guaranteed to pass
714 improvement_exist()?]
715 **************************************************************************/
716 static bool lookup_building_list(struct section_file
*file
,
717 const char *prefix
, const char *entry
,
718 int *output
, const char *filename
)
725 /* pre-fill with B_LAST: */
726 for (i
= 0; i
< MAX_NUM_BUILDING_LIST
; i
++) {
729 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.%s", prefix
, entry
);
730 if (nval
> MAX_NUM_BUILDING_LIST
) {
731 ruleset_error(LOG_ERROR
,
732 "\"%s\": string vector %s.%s too long (%d, max %d)",
733 filename
, prefix
, entry
, (int) nval
, MAX_NUM_BUILDING_LIST
);
735 } else if (nval
== 0 || (nval
== 1 && strcmp(slist
[0], "") == 0)) {
742 for (i
= 0; i
< nval
; i
++) {
743 const char *sval
= slist
[i
];
744 struct impr_type
*pimprove
= improvement_by_rule_name(sval
);
746 if (NULL
== pimprove
) {
747 ruleset_error(LOG_ERROR
,
748 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
749 filename
, prefix
, entry
, i
, sval
);
753 output
[i
] = improvement_number(pimprove
);
754 log_debug("%s.%s,%d %s %d", prefix
, entry
, i
, sval
, output
[i
]);
762 /**************************************************************************
763 Lookup a string prefix.entry in the file and set result to the corresponding
765 If description is not NULL, it is used in the warning message
766 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
767 **************************************************************************/
768 static bool lookup_unit_type(struct section_file
*file
,
771 struct unit_type
**result
,
772 const char *filename
,
773 const char *description
)
777 sval
= secfile_lookup_str_default(file
, "None", "%s.%s", prefix
, entry
);
779 if (strcmp(sval
, "None") == 0) {
782 *result
= unit_type_by_rule_name(sval
);
783 if (*result
== NULL
) {
784 ruleset_error(LOG_ERROR
,
785 "\"%s\" %s %s: couldn't match \"%s\".",
786 filename
, (description
? description
: prefix
), entry
, sval
);
795 /**************************************************************************
796 Lookup entry in the file and return the corresponding government index.
797 filename is for error message.
798 **************************************************************************/
799 static struct government
*lookup_government(struct section_file
*file
,
801 const char *filename
,
802 struct government
*fallback
)
805 struct government
*gov
;
807 sval
= secfile_lookup_str_default(file
, NULL
, "%s", entry
);
811 gov
= government_by_rule_name(sval
);
814 ruleset_error(LOG_ERROR
,
815 "\"%s\" %s: couldn't match \"%s\".",
816 filename
, entry
, sval
);
821 /****************************************************************************
822 Lookup optional string, returning allocated memory or NULL.
823 ****************************************************************************/
824 static char *lookup_string(struct section_file
*file
, const char *prefix
,
827 const char *sval
= secfile_lookup_str(file
, "%s.%s", prefix
, suffix
);
830 char copy
[strlen(sval
) + 1];
833 remove_leading_trailing_spaces(copy
);
834 if (strlen(copy
) > 0) {
835 return fc_strdup(copy
);
841 /****************************************************************************
842 Lookup optional string vector, returning allocated memory or NULL.
843 ****************************************************************************/
844 static struct strvec
*lookup_strvec(struct section_file
*file
,
845 const char *prefix
, const char *suffix
)
848 const char **vec
= secfile_lookup_str_vec(file
, &dim
,
849 "%s.%s", prefix
, suffix
);
852 struct strvec
*dest
= strvec_new();
854 strvec_store(dest
, vec
, dim
);
861 /**************************************************************************
862 Look up the resource section name and return its pointer.
863 **************************************************************************/
864 static struct extra_type
*lookup_resource(const char *filename
,
866 const char *jsection
)
868 struct extra_type
*pres
;
870 pres
= extra_type_by_rule_name(name
);
873 ruleset_error(LOG_ERROR
,
874 "\"%s\" [%s] has unknown \"%s\".",
883 /**************************************************************************
884 Look up the terrain by name and return its pointer.
885 filename is for error message.
886 **************************************************************************/
887 static bool lookup_terrain(struct section_file
*file
,
889 const char *filename
,
890 struct terrain
*pthis
,
891 struct terrain
**result
)
893 const int j
= terrain_index(pthis
);
894 const char *jsection
= &terrain_sections
[j
* MAX_SECTION_LABEL
];
895 const char *name
= secfile_lookup_str(file
, "%s.%s", jsection
, entry
);
896 struct terrain
*pterr
;
900 || (0 == strcmp(name
, "none"))
901 || (0 == strcmp(name
, "no"))) {
906 if (0 == strcmp(name
, "yes")) {
912 pterr
= terrain_by_rule_name(name
);
916 ruleset_error(LOG_ERROR
, "\"%s\" [%s] has unknown \"%s\".",
917 secfile_name(file
), jsection
, name
);
924 /**************************************************************************
925 Look up a value comparable to activity_count (road_time, etc).
926 item_name describes the thing which has the time property, if non-NULL,
927 for any error message.
928 Returns FALSE if not found in secfile, but TRUE even if validation failed.
929 Sets *ok to FALSE if validation failed, leaves it alone otherwise.
930 **************************************************************************/
931 static bool lookup_time(const struct section_file
*secfile
, int *turns
,
932 const char *sec_name
, const char *property_name
,
933 const char *filename
, const char *item_name
,
936 /* Assumes that PACKET_UNIT_INFO.activity_count in packets.def is UINT16 */
937 const int max_turns
= 65535 / ACTIVITY_FACTOR
;
939 if (!secfile_lookup_int(secfile
, turns
, "%s.%s", sec_name
, property_name
)) {
943 if (*turns
> max_turns
) {
944 ruleset_error(LOG_ERROR
,
945 "\"%s\": \"%s\": \"%s\" value %d too large (max %d)",
946 filename
, item_name
? item_name
: sec_name
,
947 property_name
, *turns
, max_turns
);
951 return TRUE
; /* we found _something */
954 /**************************************************************************
955 Load "name" and (optionally) "rule_name" into a struct name_translation.
956 **************************************************************************/
957 static bool ruleset_load_names(struct name_translation
*pname
,
959 struct section_file
*file
,
960 const char *sec_name
)
962 const char *name
= secfile_lookup_str(file
, "%s.name", sec_name
);
963 const char *rule_name
= secfile_lookup_str(file
, "%s.rule_name", sec_name
);
966 ruleset_error(LOG_ERROR
,
967 "\"%s\" [%s]: no \"name\" specified.",
968 secfile_name(file
), sec_name
);
972 names_set(pname
, domain
, name
, rule_name
);
977 /**************************************************************************
978 Load trait values to array.
979 **************************************************************************/
980 static void ruleset_load_traits(struct trait_limits
*out
,
981 struct section_file
*file
,
982 const char *secname
, const char *field_prefix
)
986 /* FIXME: Use specenum trait names without duplicating them here.
987 * Just needs to take care of case. */
988 const char *trait_names
[] = {
995 for (tr
= trait_begin(); tr
!= trait_end() && trait_names
[tr
] != NULL
; tr
= trait_next(tr
)) {
996 out
[tr
].min
= secfile_lookup_int_default(file
, -1, "%s.%s%s_min",
1000 out
[tr
].max
= secfile_lookup_int_default(file
, -1, "%s.%s%s_max",
1004 out
[tr
].fixed
= secfile_lookup_int_default(file
, -1, "%s.%s%s_default",
1010 fc_assert(tr
== trait_end()); /* number of trait_names correct */
1013 /**************************************************************************
1014 Load names from game.ruleset so other rulesets can refer to objects
1016 **************************************************************************/
1017 static bool load_game_names(struct section_file
*file
,
1018 struct rscompat_info
*compat
)
1020 struct section_list
*sec
;
1022 const char *filename
= secfile_name(file
);
1025 /* section: datafile */
1026 compat
->ver_game
= rscompat_check_capabilities(file
, filename
, compat
);
1027 if (compat
->ver_game
<= 0) {
1031 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
1032 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
1034 sec
= secfile_sections_by_name_prefix(file
, ACHIEVEMENT_SECTION_PREFIX
);
1035 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
1036 if (nval
> MAX_ACHIEVEMENT_TYPES
) {
1037 int num
= nval
; /* No "size_t" to printf */
1039 ruleset_error(LOG_ERROR
, "\"%s\": Too many achievement types (%d, max %d)",
1040 filename
, num
, MAX_ACHIEVEMENT_TYPES
);
1043 game
.control
.num_achievement_types
= nval
;
1047 achievements_iterate(pach
) {
1048 const char *sec_name
= section_name(section_list_get(sec
, achievement_index(pach
)));
1050 if (!ruleset_load_names(&pach
->name
, NULL
, file
, sec_name
)) {
1051 ruleset_error(LOG_ERROR
, "\"%s\": Cannot load achievement names",
1056 } achievements_iterate_end
;
1059 section_list_destroy(sec
);
1061 if (compat
->ver_game
>= 10) {
1063 sec
= secfile_sections_by_name_prefix(file
, GOODS_SECTION_PREFIX
);
1065 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
1066 if (nval
> MAX_GOODS_TYPES
) {
1067 int num
= nval
; /* No "size_t" to printf */
1069 ruleset_error(LOG_ERROR
,
1070 "\"%s\": Too many goods types (%d, max %d)",
1071 filename
, num
, MAX_GOODS_TYPES
);
1072 section_list_destroy(sec
);
1074 } else if (nval
< 1) {
1075 ruleset_error(LOG_ERROR
, "\"%s\": At least one goods type needed",
1077 section_list_destroy(sec
);
1080 game
.control
.num_goods_types
= nval
;
1084 goods_type_iterate(pgood
) {
1085 const char *sec_name
1086 = section_name(section_list_get(sec
, goods_index(pgood
)));
1088 if (!ruleset_load_names(&pgood
->name
, NULL
, file
, sec_name
)) {
1089 ruleset_error(LOG_ERROR
, "\"%s\": Cannot load goods names",
1094 } goods_type_iterate_end
;
1103 /**************************************************************************
1104 Load names of technologies so other rulesets can refer to techs with
1106 **************************************************************************/
1107 static bool load_tech_names(struct section_file
*file
,
1108 struct rscompat_info
*compat
)
1110 struct section_list
*sec
= NULL
;
1111 /* Number of techs in the ruleset (means without A_NONE). */
1114 const char *filename
= secfile_name(file
);
1118 compat
->ver_techs
= rscompat_check_capabilities(file
, filename
, compat
);
1119 if (compat
->ver_techs
<= 0) {
1123 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
1124 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
1126 /* User tech flag names */
1127 for (i
= 0; (flag
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.name", i
)) ;
1129 const char *helptxt
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.helptxt",
1131 if (tech_flag_id_by_name(flag
, fc_strcasecmp
) != tech_flag_id_invalid()) {
1132 ruleset_error(LOG_ERROR
, "\"%s\": Duplicate tech flag name '%s'",
1137 if (i
> MAX_NUM_USER_TECH_FLAGS
) {
1138 ruleset_error(LOG_ERROR
, "\"%s\": Too many user tech flags!",
1144 set_user_tech_flag_name(TECH_USER_1
+ i
, flag
, helptxt
);
1150 for (; i
< MAX_NUM_USER_TECH_FLAGS
; i
++) {
1151 set_user_tech_flag_name(TECH_USER_1
+ i
, NULL
, NULL
);
1155 sec
= secfile_sections_by_name_prefix(file
, TECH_CLASS_SECTION_PREFIX
);
1157 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
1158 if (nval
> MAX_NUM_TECH_CLASSES
) {
1159 int num
= nval
; /* No "size_t" to printf */
1161 ruleset_error(LOG_ERROR
,
1162 "\"%s\": Too many tech classes (%d, max %d)",
1163 filename
, num
, MAX_NUM_TECH_CLASSES
);
1164 section_list_destroy(sec
);
1167 game
.control
.num_tech_classes
= nval
;
1171 tech_class_iterate(ptclass
) {
1172 const char *sec_name
1173 = section_name(section_list_get(sec
, tech_class_index(ptclass
)));
1175 if (!ruleset_load_names(&ptclass
->name
, NULL
, file
, sec_name
)) {
1176 ruleset_error(LOG_ERROR
, "\"%s\": Cannot load tech class names",
1181 } tech_class_iterate_end
;
1187 sec
= secfile_sections_by_name_prefix(file
, ADVANCE_SECTION_PREFIX
);
1188 if (NULL
== sec
|| 0 == (num_techs
= section_list_size(sec
))) {
1189 ruleset_error(LOG_ERROR
, "\"%s\": No Advances?!?", filename
);
1192 log_verbose("%d advances (including possibly unused)", num_techs
);
1193 if (num_techs
+ A_FIRST
> A_LAST
) {
1194 ruleset_error(LOG_ERROR
, "\"%s\": Too many advances (%d, max %d)",
1195 filename
, num_techs
, A_LAST
- A_FIRST
);
1202 game
.control
.num_tech_types
= num_techs
+ A_FIRST
; /* includes A_NONE */
1205 advance_iterate(A_FIRST
, a
) {
1206 if (!ruleset_load_names(&a
->name
, NULL
, file
, section_name(section_list_get(sec
, i
)))) {
1211 } advance_iterate_end
;
1213 section_list_destroy(sec
);
1218 /**************************************************************************
1219 Load technologies related ruleset data
1220 **************************************************************************/
1221 static bool load_ruleset_techs(struct section_file
*file
,
1222 struct rscompat_info
*compat
)
1224 struct section_list
*sec
;
1228 struct advance
*a_none
= advance_by_number(A_NONE
);
1229 const char *filename
= secfile_name(file
);
1232 sec
= secfile_sections_by_name_prefix(file
, TECH_CLASS_SECTION_PREFIX
);
1235 tech_class_iterate(ptclass
) {
1236 const char *sec_name
= section_name(section_list_get(sec
, i
));
1238 ptclass
->cost_pct
= secfile_lookup_int_default(file
, 100, "%s.%s",
1239 sec_name
, "cost_pct");
1242 } tech_class_iterate_end
;
1244 sec
= secfile_sections_by_name_prefix(file
, ADVANCE_SECTION_PREFIX
);
1247 advance_iterate(A_FIRST
, a
) {
1248 const char *sec_name
= section_name(section_list_get(sec
, i
));
1251 struct requirement_vector
*research_reqs
;
1253 if (!lookup_tech(file
, &a
->require
[AR_ONE
], sec_name
, "req1",
1254 filename
, rule_name_get(&a
->name
))
1255 || !lookup_tech(file
, &a
->require
[AR_TWO
], sec_name
, "req2",
1256 filename
, rule_name_get(&a
->name
))
1257 || !lookup_tech(file
, &a
->require
[AR_ROOT
], sec_name
, "root_req",
1258 filename
, rule_name_get(&a
->name
))) {
1263 if ((A_NEVER
== a
->require
[AR_ONE
] && A_NEVER
!= a
->require
[AR_TWO
])
1264 || (A_NEVER
!= a
->require
[AR_ONE
] && A_NEVER
== a
->require
[AR_TWO
])) {
1265 ruleset_error(LOG_ERROR
, "\"%s\" [%s] \"%s\": \"Never\" with non-\"Never\".",
1266 filename
, sec_name
, rule_name_get(&a
->name
));
1270 if (a_none
== a
->require
[AR_ONE
] && a_none
!= a
->require
[AR_TWO
]) {
1271 ruleset_error(LOG_ERROR
, "\"%s\" [%s] \"%s\": should have \"None\" second.",
1272 filename
, sec_name
, rule_name_get(&a
->name
));
1277 if (game
.control
.num_tech_classes
== 0) {
1280 const char *classname
;
1282 classname
= lookup_string(file
, sec_name
, "class");
1283 if (classname
!= NULL
) {
1284 classname
= Q_(classname
);
1285 a
->tclass
= tech_class_by_rule_name(classname
);
1286 if (a
->tclass
== NULL
) {
1287 ruleset_error(LOG_ERROR
, "\"%s\" [%s] \"%s\": Uknown tech class \"%s\".",
1288 filename
, sec_name
, rule_name_get(&a
->name
), classname
);
1293 a
->tclass
= NULL
; /* Default */
1297 research_reqs
= lookup_req_list(file
, compat
, sec_name
, "research_reqs",
1298 rule_name_get(&a
->name
));
1299 if (research_reqs
== NULL
) {
1304 requirement_vector_copy(&a
->research_reqs
, research_reqs
);
1306 BV_CLR_ALL(a
->flags
);
1308 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", sec_name
);
1309 for (j
= 0; j
< nval
; j
++) {
1311 if (strcmp(sval
, "") == 0) {
1314 ival
= tech_flag_id_by_name(sval
, fc_strcasecmp
);
1315 if (!tech_flag_id_is_valid(ival
)) {
1316 ruleset_error(LOG_ERROR
, "\"%s\" [%s] \"%s\": bad flag name \"%s\".",
1317 filename
, sec_name
, rule_name_get(&a
->name
), sval
);
1321 BV_SET(a
->flags
, ival
);
1330 sz_strlcpy(a
->graphic_str
,
1331 secfile_lookup_str_default(file
, "-", "%s.graphic", sec_name
));
1332 sz_strlcpy(a
->graphic_alt
,
1333 secfile_lookup_str_default(file
, "-",
1334 "%s.graphic_alt", sec_name
));
1336 a
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
1337 a
->bonus_message
= lookup_string(file
, sec_name
, "bonus_message");
1338 a
->cost
= secfile_lookup_int_default(file
, -1, "%s.%s",
1343 } advance_iterate_end
;
1345 /* Propagate a root tech up into the tech tree. Thus if a technology
1346 * X has Y has a root tech, then any technology requiring X also has
1347 * Y as a root tech. */
1351 advance_iterate(A_FIRST
, a
) {
1352 if (valid_advance(a
)
1353 && A_NEVER
!= a
->require
[AR_ROOT
]) {
1354 bool out_of_order
= FALSE
;
1356 /* Now find any tech depending on this technology and update its
1358 advance_iterate(A_FIRST
, b
) {
1359 if (valid_advance(b
)
1360 && A_NEVER
== b
->require
[AR_ROOT
]
1361 && (a
== b
->require
[AR_ONE
] || a
== b
->require
[AR_TWO
])) {
1362 b
->require
[AR_ROOT
] = a
->require
[AR_ROOT
];
1364 out_of_order
= TRUE
;
1367 } advance_iterate_end
;
1370 /* HACK: If we just changed the root_tech of a lower-numbered
1371 * technology, we need to go back so that we can propagate the
1372 * root_tech up to that technology's parents... */
1376 } advance_iterate_end
;
1378 /* Now rename A_NEVER to A_NONE for consistency */
1379 advance_iterate(A_NONE
, a
) {
1380 if (A_NEVER
== a
->require
[AR_ROOT
]) {
1381 a
->require
[AR_ROOT
] = a_none
;
1383 } advance_iterate_end
;
1385 /* Some more consistency checking:
1386 Non-removed techs depending on removed techs is too
1387 broken to fix by default, so die.
1389 advance_iterate(A_FIRST
, a
) {
1390 if (valid_advance(a
)) {
1391 /* We check for recursive tech loops later,
1392 * in build_required_techs_helper. */
1393 if (!valid_advance(a
->require
[AR_ONE
])) {
1394 ruleset_error(LOG_ERROR
,
1395 "\"%s\" tech \"%s\": req1 leads to removed tech.",
1397 advance_rule_name(a
));
1401 if (!valid_advance(a
->require
[AR_TWO
])) {
1402 ruleset_error(LOG_ERROR
,
1403 "\"%s\" tech \"%s\": req2 leads to removed tech.",
1405 advance_rule_name(a
));
1410 } advance_iterate_end
;
1413 section_list_destroy(sec
);
1415 secfile_check_unused(file
);
1421 /**************************************************************************
1422 Load names of units so other rulesets can refer to units with
1424 **************************************************************************/
1425 static bool load_unit_names(struct section_file
*file
,
1426 struct rscompat_info
*compat
)
1428 struct section_list
*sec
= NULL
;
1431 const char *filename
= secfile_name(file
);
1435 compat
->ver_units
= rscompat_check_capabilities(file
, filename
, compat
);
1436 if (compat
->ver_units
<= 0) {
1440 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
1441 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
1443 /* User unit flag names */
1444 for (i
= 0; (flag
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.name", i
)) ;
1446 const char *helptxt
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.helptxt",
1449 if (unit_type_flag_id_by_name(rscompat_utype_flag_name_3_1(compat
, flag
),
1451 != unit_type_flag_id_invalid()) {
1452 ruleset_error(LOG_ERROR
, "\"%s\": Duplicate unit flag name '%s'",
1457 if (i
> MAX_NUM_USER_UNIT_FLAGS
) {
1458 ruleset_error(LOG_ERROR
, "\"%s\": Too many user unit type flags!",
1464 set_user_unit_type_flag_name(UTYF_USER_FLAG_1
+ i
, flag
, helptxt
);
1468 /* Blank the remaining unit type user flags. */
1469 for (; i
< MAX_NUM_USER_UNIT_FLAGS
; i
++) {
1470 set_user_unit_type_flag_name(UTYF_USER_FLAG_1
+ i
, NULL
, NULL
);
1475 /* User unit class flag names */
1477 (flag
= secfile_lookup_str_default(file
, NULL
,
1478 "control.class_flags%d.name",
1481 const char *helptxt
= secfile_lookup_str_default(file
, NULL
,
1482 "control.class_flags%d.helptxt", i
);
1484 if (unit_class_flag_id_by_name(flag
, fc_strcasecmp
)
1485 != unit_class_flag_id_invalid()) {
1486 ruleset_error(LOG_ERROR
, "\"%s\": Duplicate unit class flag name "
1492 if (i
> MAX_NUM_USER_UCLASS_FLAGS
) {
1493 ruleset_error(LOG_ERROR
, "\"%s\": Too many user unit class flags!",
1499 set_user_unit_class_flag_name(UCF_USER_FLAG_1
+ i
, flag
, helptxt
);
1504 /* Blank the remaining unit class user flags. */
1505 for (; i
< MAX_NUM_USER_UCLASS_FLAGS
; i
++) {
1506 set_user_unit_class_flag_name(UCF_USER_FLAG_1
+ i
, NULL
, NULL
);
1512 sec
= secfile_sections_by_name_prefix(file
, UNIT_CLASS_SECTION_PREFIX
);
1513 if (NULL
== sec
|| 0 == (nval
= section_list_size(sec
))) {
1514 ruleset_error(LOG_ERROR
, "\"%s\": No unit classes?!?", filename
);
1517 log_verbose("%d unit classes", nval
);
1518 if (nval
> UCL_LAST
) {
1519 ruleset_error(LOG_ERROR
, "\"%s\": Too many unit classes (%d, max %d)",
1520 filename
, nval
, UCL_LAST
);
1527 game
.control
.num_unit_classes
= nval
;
1529 unit_class_iterate(punitclass
) {
1530 const int pci
= uclass_index(punitclass
);
1532 if (!ruleset_load_names(&punitclass
->name
, NULL
, file
,
1533 section_name(section_list_get(sec
, pci
)))) {
1537 } unit_class_iterate_end
;
1539 section_list_destroy(sec
);
1544 sec
= secfile_sections_by_name_prefix(file
, UNIT_SECTION_PREFIX
);
1545 if (NULL
== sec
|| 0 == (nval
= section_list_size(sec
))) {
1546 ruleset_error(LOG_ERROR
, "\"%s\": No unit types?!?", filename
);
1549 log_verbose("%d unit types (including possibly unused)", nval
);
1550 if (nval
> U_LAST
) {
1551 ruleset_error(LOG_ERROR
, "\"%s\": Too many unit types (%d, max %d)",
1552 filename
, nval
, U_LAST
);
1559 game
.control
.num_unit_types
= nval
;
1561 unit_type_iterate(punittype
) {
1562 const int utypei
= utype_index(punittype
);
1563 if (!ruleset_load_names(&punittype
->name
, NULL
, file
,
1564 section_name(section_list_get(sec
, utypei
)))) {
1568 } unit_type_iterate_end
;
1570 section_list_destroy(sec
);
1575 /**************************************************************************
1576 Load veteran levels.
1577 **************************************************************************/
1578 static bool load_ruleset_veteran(struct section_file
*file
,
1580 struct veteran_system
**vsystem
, char *err
,
1583 const char **vlist_name
;
1584 int *vlist_power
, *vlist_raise
, *vlist_wraise
, *vlist_move
;
1585 size_t count_name
, count_power
, count_raise
, count_wraise
, count_move
;
1589 /* The pointer should be uninitialised. */
1590 if (*vsystem
!= NULL
) {
1591 fc_snprintf(err
, err_len
, "Veteran system is defined?!");
1596 vlist_name
= secfile_lookup_str_vec(file
, &count_name
,
1597 "%s.veteran_names", path
);
1598 vlist_power
= secfile_lookup_int_vec(file
, &count_power
,
1599 "%s.veteran_power_fact", path
);
1600 vlist_raise
= secfile_lookup_int_vec(file
, &count_raise
,
1601 "%s.veteran_raise_chance", path
);
1602 vlist_wraise
= secfile_lookup_int_vec(file
, &count_wraise
,
1603 "%s.veteran_work_raise_chance",
1605 vlist_move
= secfile_lookup_int_vec(file
, &count_move
,
1606 "%s.veteran_move_bonus", path
);
1608 if (count_name
> MAX_VET_LEVELS
) {
1610 fc_snprintf(err
, err_len
, "\"%s\": Too many veteran levels (section "
1611 "'%s': %lu, max %d)", secfile_name(file
), path
,
1612 (long unsigned)count_name
, MAX_VET_LEVELS
);
1613 } else if (count_name
!= count_power
1614 || count_name
!= count_raise
1615 || count_name
!= count_wraise
1616 || count_name
!= count_move
) {
1618 fc_snprintf(err
, err_len
, "\"%s\": Different lengths for the veteran "
1619 "settings in section '%s'", secfile_name(file
),
1621 } else if (count_name
== 0) {
1622 /* Nothing defined. */
1625 /* Generate the veteran system. */
1626 *vsystem
= veteran_system_new((int)count_name
);
1628 #define rs_sanity_veteran(_path, _entry, _i, _condition, _action) \
1630 log_error("Invalid veteran definition '%s.%s[%d]'!", \
1631 _path, _entry, _i); \
1632 log_debug("Failed check: '%s'. Update value: '%s'.", \
1633 #_condition, #_action); \
1636 for (i
= 0; i
< count_name
; i
++) {
1637 /* Some sanity checks. */
1638 rs_sanity_veteran(path
, "veteran_power_fact", i
,
1639 (vlist_power
[i
] < 0), vlist_power
[i
] = 0);
1640 rs_sanity_veteran(path
, "veteran_raise_chance", i
,
1641 (vlist_raise
[i
] < 0), vlist_raise
[i
] = 0);
1642 rs_sanity_veteran(path
, "veteran_work_raise_chance", i
,
1643 (vlist_wraise
[i
] < 0), vlist_wraise
[i
] = 0);
1644 rs_sanity_veteran(path
, "veteran_move_bonus", i
,
1645 (vlist_move
[i
] < 0), vlist_move
[i
] = 0);
1648 rs_sanity_veteran(path
, "veteran_power_fact", i
,
1649 (vlist_power
[i
] != 100), vlist_power
[i
] = 100);
1650 } else if (i
== count_name
- 1) {
1652 rs_sanity_veteran(path
, "veteran_power_fact", i
,
1653 (vlist_power
[i
] < vlist_power
[i
- 1]),
1654 vlist_power
[i
] = vlist_power
[i
- 1]);
1655 rs_sanity_veteran(path
, "veteran_raise_chance", i
,
1656 (vlist_raise
[i
] != 0), vlist_raise
[i
] = 0);
1657 rs_sanity_veteran(path
, "veteran_work_raise_chance", i
,
1658 (vlist_wraise
[i
] != 0), vlist_wraise
[i
] = 0);
1660 /* All elements inbetween. */
1661 rs_sanity_veteran(path
, "veteran_power_fact", i
,
1662 (vlist_power
[i
] < vlist_power
[i
- 1]),
1663 vlist_power
[i
] = vlist_power
[i
- 1]);
1664 rs_sanity_veteran(path
, "veteran_raise_chance", i
,
1665 (vlist_raise
[i
] > 100), vlist_raise
[i
] = 100);
1666 rs_sanity_veteran(path
, "veteran_work_raise_chance", i
,
1667 (vlist_wraise
[i
] > 100), vlist_wraise
[i
] = 100);
1670 veteran_system_definition(*vsystem
, i
, vlist_name
[i
], vlist_power
[i
],
1671 vlist_move
[i
], vlist_raise
[i
],
1674 #undef rs_sanity_veteran
1696 /**************************************************************************
1697 Load units related ruleset data.
1698 **************************************************************************/
1699 static bool load_ruleset_units(struct section_file
*file
,
1700 struct rscompat_info
*compat
)
1704 struct section_list
*sec
, *csec
;
1705 const char *sval
, **slist
;
1706 const char *filename
= secfile_name(file
);
1707 char msg
[MAX_LEN_MSG
];
1710 if (!load_ruleset_veteran(file
, "veteran_system", &game
.veteran
, msg
,
1711 sizeof(msg
)) || game
.veteran
== NULL
) {
1712 ruleset_error(LOG_ERROR
, "Error loading the default veteran system: %s",
1717 sec
= secfile_sections_by_name_prefix(file
, UNIT_SECTION_PREFIX
);
1718 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
1720 csec
= secfile_sections_by_name_prefix(file
, UNIT_CLASS_SECTION_PREFIX
);
1721 nval
= (NULL
!= csec
? section_list_size(csec
) : 0);
1724 unit_class_iterate(uc
) {
1725 int i
= uclass_index(uc
);
1726 const char *hut_str
;
1727 const char *sec_name
= section_name(section_list_get(csec
, i
));
1729 if (secfile_lookup_int(file
, &uc
->min_speed
, "%s.min_speed", sec_name
)) {
1730 uc
->min_speed
*= SINGLE_MOVE
;
1732 ruleset_error(LOG_ERROR
, "%s", secfile_error());
1736 if (!secfile_lookup_int(file
, &uc
->hp_loss_pct
,
1737 "%s.hp_loss_pct", sec_name
)) {
1738 ruleset_error(LOG_ERROR
, "%s", secfile_error());
1743 uc
->non_native_def_pct
= secfile_lookup_int_default(file
, 100,
1744 "%s.non_native_def_pct",
1747 hut_str
= secfile_lookup_str_default(file
, "Normal", "%s.hut_behavior", sec_name
);
1748 if (fc_strcasecmp(hut_str
, "Normal") == 0) {
1749 uc
->hut_behavior
= HUT_NORMAL
;
1750 } else if (fc_strcasecmp(hut_str
, "Nothing") == 0) {
1751 uc
->hut_behavior
= HUT_NOTHING
;
1752 } else if (fc_strcasecmp(hut_str
, "Frighten") == 0) {
1753 uc
->hut_behavior
= HUT_FRIGHTEN
;
1755 ruleset_error(LOG_ERROR
,
1756 "\"%s\" unit_class \"%s\":"
1757 " Illegal hut behavior \"%s\".",
1759 uclass_rule_name(uc
),
1765 BV_CLR_ALL(uc
->flags
);
1766 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", sec_name
);
1767 for (j
= 0; j
< nval
; j
++) {
1769 if (strcmp(sval
, "") == 0) {
1772 ival
= unit_class_flag_id_by_name(sval
, fc_strcasecmp
);
1773 if (!unit_class_flag_id_is_valid(ival
)) {
1775 ival
= unit_type_flag_id_by_name(rscompat_utype_flag_name_3_1(compat
, sval
),
1777 if (unit_type_flag_id_is_valid(ival
)) {
1778 ruleset_error(LOG_ERROR
,
1779 "\"%s\" unit_class \"%s\": unit_type flag \"%s\"!",
1780 filename
, uclass_rule_name(uc
), sval
);
1782 ruleset_error(LOG_ERROR
,
1783 "\"%s\" unit_class \"%s\": bad flag name \"%s\".",
1784 filename
, uclass_rule_name(uc
), sval
);
1788 BV_SET(uc
->flags
, ival
);
1793 uc
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
1798 } unit_class_iterate_end
;
1802 /* Tech and Gov requirements; per unit veteran system */
1803 unit_type_iterate(u
) {
1804 const int i
= utype_index(u
);
1805 const struct section
*psection
= section_list_get(sec
, i
);
1806 const char *sec_name
= section_name(psection
);
1808 if (!lookup_tech(file
, &u
->require_advance
, sec_name
,
1809 "tech_req", filename
,
1810 rule_name_get(&u
->name
))) {
1814 if (NULL
!= section_entry_by_name(psection
, "gov_req")) {
1815 char tmp
[200] = "\0";
1816 fc_strlcat(tmp
, section_name(psection
), sizeof(tmp
));
1817 fc_strlcat(tmp
, ".gov_req", sizeof(tmp
));
1818 u
->need_government
= lookup_government(file
, tmp
, filename
, NULL
);
1819 if (u
->need_government
== NULL
) {
1824 u
->need_government
= NULL
; /* no requirement */
1827 if (!load_ruleset_veteran(file
, sec_name
, &u
->veteran
,
1828 msg
, sizeof(msg
))) {
1829 ruleset_error(LOG_ERROR
, "Error loading the veteran system: %s",
1835 if (!lookup_unit_type(file
, sec_name
, "obsolete_by",
1836 &u
->obsoleted_by
, filename
,
1837 rule_name_get(&u
->name
))
1838 || !lookup_unit_type(file
, sec_name
, "convert_to",
1839 &u
->converted_to
, filename
,
1840 rule_name_get(&u
->name
))) {
1844 u
->convert_time
= 1; /* default */
1845 lookup_time(file
, &u
->convert_time
, sec_name
, "convert_time",
1846 filename
, rule_name_get(&u
->name
), &ok
);
1847 } unit_type_iterate_end
;
1852 unit_type_iterate(u
) {
1853 const int i
= utype_index(u
);
1854 struct unit_class
*pclass
;
1855 const char *sec_name
= section_name(section_list_get(sec
, i
));
1858 if (!lookup_building(file
, sec_name
, "impr_req",
1859 &u
->need_improvement
, filename
,
1860 rule_name_get(&u
->name
))) {
1865 sval
= secfile_lookup_str(file
, "%s.class", sec_name
);
1866 pclass
= unit_class_by_rule_name(sval
);
1868 ruleset_error(LOG_ERROR
,
1869 "\"%s\" unit_type \"%s\":"
1870 " bad class \"%s\".",
1879 sz_strlcpy(u
->sound_move
,
1880 secfile_lookup_str_default(file
, "-", "%s.sound_move",
1882 sz_strlcpy(u
->sound_move_alt
,
1883 secfile_lookup_str_default(file
, "-", "%s.sound_move_alt",
1885 sz_strlcpy(u
->sound_fight
,
1886 secfile_lookup_str_default(file
, "-", "%s.sound_fight",
1888 sz_strlcpy(u
->sound_fight_alt
,
1889 secfile_lookup_str_default(file
, "-", "%s.sound_fight_alt",
1892 if ((string
= secfile_lookup_str(file
, "%s.graphic", sec_name
))) {
1893 sz_strlcpy(u
->graphic_str
, string
);
1895 ruleset_error(LOG_ERROR
, "%s", secfile_error());
1899 sz_strlcpy(u
->graphic_alt
,
1900 secfile_lookup_str_default(file
, "-", "%s.graphic_alt",
1903 if (!secfile_lookup_int(file
, &u
->build_cost
,
1904 "%s.build_cost", sec_name
)
1905 || !secfile_lookup_int(file
, &u
->pop_cost
,
1906 "%s.pop_cost", sec_name
)
1907 || !secfile_lookup_int(file
, &u
->attack_strength
,
1908 "%s.attack", sec_name
)
1909 || !secfile_lookup_int(file
, &u
->defense_strength
,
1910 "%s.defense", sec_name
)
1911 || !secfile_lookup_int(file
, &u
->move_rate
,
1912 "%s.move_rate", sec_name
)
1913 || !secfile_lookup_int(file
, &u
->vision_radius_sq
,
1914 "%s.vision_radius_sq", sec_name
)
1915 || !secfile_lookup_int(file
, &u
->transport_capacity
,
1916 "%s.transport_cap", sec_name
)
1917 || !secfile_lookup_int(file
, &u
->hp
,
1918 "%s.hitpoints", sec_name
)
1919 || !secfile_lookup_int(file
, &u
->firepower
,
1920 "%s.firepower", sec_name
)
1921 || !secfile_lookup_int(file
, &u
->fuel
,
1922 "%s.fuel", sec_name
)
1923 || !secfile_lookup_int(file
, &u
->happy_cost
,
1924 "%s.uk_happy", sec_name
)) {
1925 ruleset_error(LOG_ERROR
, "%s", secfile_error());
1929 u
->move_rate
*= SINGLE_MOVE
;
1931 if (u
->firepower
<= 0) {
1932 ruleset_error(LOG_ERROR
,
1933 "\"%s\" unit_type \"%s\":"
1935 " but must be at least 1. "
1936 " If you want no attack ability,"
1937 " set the unit's attack strength to 0.",
1945 lookup_cbonus_list(compat
, u
->bonuses
, file
, sec_name
, "bonuses");
1947 output_type_iterate(o
) {
1948 u
->upkeep
[o
] = secfile_lookup_int_default(file
, 0, "%s.uk_%s",
1950 get_output_identifier(o
));
1951 } output_type_iterate_end
;
1953 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.cargo", sec_name
);
1954 BV_CLR_ALL(u
->cargo
);
1955 for (j
= 0; j
< nval
; j
++) {
1956 struct unit_class
*uclass
= unit_class_by_rule_name(slist
[j
]);
1959 ruleset_error(LOG_ERROR
,
1960 "\"%s\" unit_type \"%s\":"
1961 "has unknown unit class %s as cargo.",
1969 BV_SET(u
->cargo
, uclass_index(uclass
));
1977 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.targets", sec_name
);
1978 BV_CLR_ALL(u
->targets
);
1979 for (j
= 0; j
< nval
; j
++) {
1980 struct unit_class
*uclass
= unit_class_by_rule_name(slist
[j
]);
1983 ruleset_error(LOG_ERROR
,
1984 "\"%s\" unit_type \"%s\":"
1985 "has unknown unit class %s as target.",
1993 BV_SET(u
->targets
, uclass_index(uclass
));
2001 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.embarks", sec_name
);
2002 BV_CLR_ALL(u
->embarks
);
2003 for (j
= 0; j
< nval
; j
++) {
2004 struct unit_class
*uclass
= unit_class_by_rule_name(slist
[j
]);
2007 ruleset_error(LOG_ERROR
,
2008 "\"%s\" unit_type \"%s\":"
2009 "has unknown unit class %s as embarkable.",
2017 BV_SET(u
->embarks
, uclass_index(uclass
));
2025 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.disembarks", sec_name
);
2026 BV_CLR_ALL(u
->disembarks
);
2027 for (j
= 0; j
< nval
; j
++) {
2028 struct unit_class
*uclass
= unit_class_by_rule_name(slist
[j
]);
2031 ruleset_error(LOG_ERROR
,
2032 "\"%s\" unit_type \"%s\":"
2033 "has unknown unit class %s as disembarkable.",
2041 BV_SET(u
->disembarks
, uclass_index(uclass
));
2049 /* Set also all classes that are never unreachable as targets,
2050 * embarks, and disembarks. */
2051 unit_class_iterate(preachable
) {
2052 if (!uclass_has_flag(preachable
, UCF_UNREACHABLE
)) {
2053 BV_SET(u
->targets
, uclass_index(preachable
));
2054 BV_SET(u
->embarks
, uclass_index(preachable
));
2055 BV_SET(u
->disembarks
, uclass_index(preachable
));
2057 } unit_class_iterate_end
;
2059 u
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
2061 u
->paratroopers_range
= secfile_lookup_int_default(file
,
2062 0, "%s.paratroopers_range", sec_name
);
2063 u
->paratroopers_mr_req
= SINGLE_MOVE
* secfile_lookup_int_default(file
,
2064 0, "%s.paratroopers_mr_req", sec_name
);
2065 u
->paratroopers_mr_sub
= SINGLE_MOVE
* secfile_lookup_int_default(file
,
2066 0, "%s.paratroopers_mr_sub", sec_name
);
2067 u
->bombard_rate
= secfile_lookup_int_default(file
, 0,
2068 "%s.bombard_rate", sec_name
);
2069 u
->city_slots
= secfile_lookup_int_default(file
, 0,
2070 "%s.city_slots", sec_name
);
2071 u
->city_size
= secfile_lookup_int_default(file
, 1,
2072 "%s.city_size", sec_name
);
2073 } unit_type_iterate_end
;
2078 unit_type_iterate(u
) {
2079 const int i
= utype_index(u
);
2081 BV_CLR_ALL(u
->flags
);
2082 fc_assert(!utype_has_flag(u
, UTYF_LAST_USER_FLAG
- 1));
2084 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags",
2085 section_name(section_list_get(sec
, i
)));
2086 for (j
= 0; j
< nval
; j
++) {
2088 if (0 == strcmp(sval
, "")) {
2091 ival
= unit_type_flag_id_by_name(rscompat_utype_flag_name_3_1(compat
, sval
),
2093 if (!unit_type_flag_id_is_valid(ival
)) {
2095 ival
= unit_class_flag_id_by_name(sval
, fc_strcasecmp
);
2096 if (unit_class_flag_id_is_valid(ival
)) {
2097 ruleset_error(LOG_ERROR
, "\"%s\" unit_type \"%s\": unit_class flag!",
2098 filename
, utype_rule_name(u
));
2100 ruleset_error(LOG_ERROR
,
2101 "\"%s\" unit_type \"%s\": bad flag name \"%s\".",
2102 filename
, utype_rule_name(u
), sval
);
2106 BV_SET(u
->flags
, ival
);
2108 fc_assert(utype_has_flag(u
, ival
));
2115 } unit_type_iterate_end
;
2120 unit_type_iterate(u
) {
2121 const int i
= utype_index(u
);
2123 BV_CLR_ALL(u
->roles
);
2125 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.roles",
2126 section_name(section_list_get(sec
, i
)));
2127 for (j
= 0; j
< nval
; j
++) {
2129 if (strcmp(sval
, "") == 0) {
2132 ival
= unit_role_id_by_name(sval
, fc_strcasecmp
);
2133 if (!unit_role_id_is_valid(ival
)) {
2134 ruleset_error(LOG_ERROR
, "\"%s\" unit_type \"%s\": bad role name \"%s\".",
2135 filename
, utype_rule_name(u
), sval
);
2139 BV_SET(u
->roles
, ival
- L_FIRST
);
2141 fc_assert(utype_has_role(u
, ival
));
2144 } unit_type_iterate_end
;
2148 /* Some more consistency checking: */
2149 unit_type_iterate(u
) {
2150 if (!valid_advance(u
->require_advance
)) {
2151 ruleset_error(LOG_ERROR
, "\"%s\" unit_type \"%s\": depends on removed tech \"%s\".",
2152 filename
, utype_rule_name(u
),
2153 advance_rule_name(u
->require_advance
));
2154 u
->require_advance
= A_NEVER
;
2159 if (utype_has_flag(u
, UTYF_SETTLERS
)
2160 && u
->city_size
<= 0) {
2161 ruleset_error(LOG_ERROR
, "\"%s\": Unit %s would build size %d cities",
2162 filename
, utype_rule_name(u
), u
->city_size
);
2167 } unit_type_iterate_end
;
2170 section_list_destroy(csec
);
2171 section_list_destroy(sec
);
2174 secfile_check_unused(file
);
2180 /**************************************************************************
2181 Load names of buildings so other rulesets can refer to buildings with
2183 **************************************************************************/
2184 static bool load_building_names(struct section_file
*file
,
2185 struct rscompat_info
*compat
)
2187 struct section_list
*sec
;
2189 const char *filename
= secfile_name(file
);
2192 compat
->ver_buildings
= rscompat_check_capabilities(file
, filename
,
2194 if (compat
->ver_buildings
<= 0) {
2198 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
2199 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
2202 sec
= secfile_sections_by_name_prefix(file
, BUILDING_SECTION_PREFIX
);
2203 if (NULL
== sec
|| 0 == (nval
= section_list_size(sec
))) {
2204 ruleset_error(LOG_ERROR
, "\"%s\": No improvements?!?", filename
);
2207 log_verbose("%d improvement types (including possibly unused)", nval
);
2208 if (nval
> B_LAST
) {
2209 ruleset_error(LOG_ERROR
, "\"%s\": Too many improvements (%d, max %d)",
2210 filename
, nval
, B_LAST
);
2216 game
.control
.num_impr_types
= nval
;
2218 for (i
= 0; i
< nval
; i
++) {
2219 struct impr_type
*b
= improvement_by_number(i
);
2221 if (!ruleset_load_names(&b
->name
, NULL
, file
, section_name(section_list_get(sec
, i
)))) {
2228 section_list_destroy(sec
);
2233 /**************************************************************************
2234 Load buildings related ruleset data
2235 **************************************************************************/
2236 static bool load_ruleset_buildings(struct section_file
*file
,
2237 struct rscompat_info
*compat
)
2239 struct section_list
*sec
;
2242 const char *filename
= secfile_name(file
);
2245 sec
= secfile_sections_by_name_prefix(file
, BUILDING_SECTION_PREFIX
);
2246 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
2248 for (i
= 0; i
< nval
&& ok
; i
++) {
2249 struct impr_type
*b
= improvement_by_number(i
);
2250 const char *sec_name
= section_name(section_list_get(sec
, i
));
2251 struct requirement_vector
*reqs
=
2252 lookup_req_list(file
, compat
, sec_name
, "reqs",
2253 improvement_rule_name(b
));
2259 const char *sval
, **slist
;
2263 item
= secfile_lookup_str(file
, "%s.genus", sec_name
);
2264 b
->genus
= impr_genus_id_by_name(item
, fc_strcasecmp
);
2265 if (!impr_genus_id_is_valid(b
->genus
)) {
2266 ruleset_error(LOG_ERROR
, "\"%s\" improvement \"%s\": couldn't match "
2267 "genus \"%s\".", filename
,
2268 improvement_rule_name(b
), item
);
2273 slist
= secfile_lookup_str_vec(file
, &nflags
, "%s.flags", sec_name
);
2274 BV_CLR_ALL(b
->flags
);
2276 for (j
= 0; j
< nflags
; j
++) {
2278 if (strcmp(sval
,"") == 0) {
2281 ival
= impr_flag_id_by_name(sval
, fc_strcasecmp
);
2282 if (!impr_flag_id_is_valid(ival
)) {
2283 ruleset_error(LOG_ERROR
,
2284 "\"%s\" improvement \"%s\": bad flag name \"%s\".",
2285 filename
, improvement_rule_name(b
), sval
);
2289 BV_SET(b
->flags
, ival
);
2298 requirement_vector_copy(&b
->reqs
, reqs
);
2301 struct requirement_vector
*obs_reqs
=
2302 lookup_req_list(file
, compat
, sec_name
, "obsolete_by",
2303 improvement_rule_name(b
));
2305 if (obs_reqs
== NULL
) {
2309 requirement_vector_copy(&b
->obsolete_by
, obs_reqs
);
2313 if (!secfile_lookup_int(file
, &b
->build_cost
,
2314 "%s.build_cost", sec_name
)
2315 || !secfile_lookup_int(file
, &b
->upkeep
,
2316 "%s.upkeep", sec_name
)
2317 || !secfile_lookup_int(file
, &b
->sabotage
,
2318 "%s.sabotage", sec_name
)) {
2319 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2324 sz_strlcpy(b
->graphic_str
,
2325 secfile_lookup_str_default(file
, "-",
2326 "%s.graphic", sec_name
));
2327 sz_strlcpy(b
->graphic_alt
,
2328 secfile_lookup_str_default(file
, "-",
2329 "%s.graphic_alt", sec_name
));
2331 sz_strlcpy(b
->soundtag
,
2332 secfile_lookup_str_default(file
, "-",
2333 "%s.sound", sec_name
));
2334 sz_strlcpy(b
->soundtag_alt
,
2335 secfile_lookup_str_default(file
, "-",
2336 "%s.sound_alt", sec_name
));
2337 b
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
2341 section_list_destroy(sec
);
2343 secfile_check_unused(file
);
2349 /**************************************************************************
2350 Load names of terrain types so other rulesets can refer to terrains with
2352 **************************************************************************/
2353 static bool load_terrain_names(struct section_file
*file
,
2354 struct rscompat_info
*compat
)
2357 struct section_list
*sec
= NULL
;
2360 const char *filename
= secfile_name(file
);
2363 compat
->ver_terrain
= rscompat_check_capabilities(file
, filename
,
2365 if (compat
->ver_terrain
<= 0) {
2369 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
2370 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
2372 /* User terrain flag names */
2373 for (i
= 0; (flag
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.name", i
)) ;
2375 const char *helptxt
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.helptxt",
2378 if (terrain_flag_id_by_name(flag
, fc_strcasecmp
)
2379 != terrain_flag_id_invalid()) {
2380 ruleset_error(LOG_ERROR
, "\"%s\": Duplicate terrain flag name '%s'",
2385 if (i
> MAX_NUM_USER_TER_FLAGS
) {
2386 ruleset_error(LOG_ERROR
, "\"%s\": Too many user terrain flags!",
2392 set_user_terrain_flag_name(TER_USER_1
+ i
, flag
, helptxt
);
2396 /* Blank the remaining terrain user flag slots. */
2397 for (; i
< MAX_NUM_USER_TER_FLAGS
; i
++) {
2398 set_user_terrain_flag_name(TER_USER_1
+ i
, NULL
, NULL
);
2402 /* User extra flag names */
2404 (flag
= secfile_lookup_str_default(file
, NULL
,
2405 "control.extra_flags%d.name",
2408 const char *helptxt
= secfile_lookup_str_default(file
, NULL
,
2409 "control.extra_flags%d.helptxt", i
);
2411 if (extra_flag_id_by_name(flag
, fc_strcasecmp
)
2412 != extra_flag_id_invalid()) {
2413 ruleset_error(LOG_ERROR
, "\"%s\": Duplicate extra flag name '%s'",
2418 if (i
> MAX_NUM_USER_EXTRA_FLAGS
) {
2419 ruleset_error(LOG_ERROR
, "\"%s\": Too many user extra flags!",
2425 set_user_extra_flag_name(EF_USER_FLAG_1
+ i
, flag
, helptxt
);
2429 /* Blank the remaining extra user flag slots. */
2430 for (; i
< MAX_NUM_USER_EXTRA_FLAGS
; i
++) {
2431 set_user_extra_flag_name(EF_USER_FLAG_1
+ i
, NULL
, NULL
);
2436 sec
= secfile_sections_by_name_prefix(file
, TERRAIN_SECTION_PREFIX
);
2437 if (NULL
== sec
|| 0 == (nval
= section_list_size(sec
))) {
2438 ruleset_error(LOG_ERROR
, "\"%s\": ruleset doesn't have any terrains.",
2442 if (nval
> MAX_NUM_TERRAINS
) {
2443 ruleset_error(LOG_ERROR
, "\"%s\": Too many terrains (%d, max %d)",
2444 filename
, nval
, MAX_NUM_TERRAINS
);
2451 game
.control
.terrain_count
= nval
;
2453 /* avoid re-reading files */
2454 if (terrain_sections
) {
2455 free(terrain_sections
);
2457 terrain_sections
= fc_calloc(nval
, MAX_SECTION_LABEL
);
2459 terrain_type_iterate(pterrain
) {
2460 const int terri
= terrain_index(pterrain
);
2461 const char *sec_name
= section_name(section_list_get(sec
, terri
));
2463 if (!ruleset_load_names(&pterrain
->name
, NULL
, file
, sec_name
)) {
2468 if (0 == strcmp(rule_name_get(&pterrain
->name
), "unused")) {
2469 name_set(&pterrain
->name
, NULL
, "");
2472 section_strlcpy(&terrain_sections
[terri
* MAX_SECTION_LABEL
], sec_name
);
2473 } terrain_type_iterate_end
;
2476 section_list_destroy(sec
);
2482 sec
= secfile_sections_by_name_prefix(file
, EXTRA_SECTION_PREFIX
);
2483 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
2484 if (nval
> MAX_EXTRA_TYPES
) {
2485 ruleset_error(LOG_ERROR
, "\"%s\": Too many extra types (%d, max %d)",
2486 filename
, nval
, MAX_EXTRA_TYPES
);
2494 game
.control
.num_extra_types
= nval
;
2496 if (extra_sections
) {
2497 free(extra_sections
);
2499 extra_sections
= fc_calloc(nval
, MAX_SECTION_LABEL
);
2502 for (idx
= 0; idx
< nval
; idx
++) {
2503 const char *sec_name
= section_name(section_list_get(sec
, idx
));
2504 struct extra_type
*pextra
= extra_by_number(idx
);
2506 if (!ruleset_load_names(&pextra
->name
, NULL
, file
, sec_name
)) {
2510 section_strlcpy(&extra_sections
[idx
* MAX_SECTION_LABEL
], sec_name
);
2515 section_list_destroy(sec
);
2521 sec
= secfile_sections_by_name_prefix(file
, BASE_SECTION_PREFIX
);
2522 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
2523 if (nval
> MAX_BASE_TYPES
) {
2524 ruleset_error(LOG_ERROR
, "\"%s\": Too many base types (%d, max %d)",
2525 filename
, nval
, MAX_BASE_TYPES
);
2529 game
.control
.num_base_types
= nval
;
2535 if (base_sections
) {
2536 free(base_sections
);
2538 base_sections
= fc_calloc(nval
, MAX_SECTION_LABEL
);
2540 /* Cannot use base_type_iterate() before bases are added to
2541 * EC_BASE caused_by list. Have to get them by extra_type_by_rule_name() */
2542 for (idx
= 0; idx
< nval
; idx
++) {
2543 const char *sec_name
= section_name(section_list_get(sec
, idx
));
2544 const char *base_name
= secfile_lookup_str(file
, "%s.extra", sec_name
);
2546 if (base_name
!= NULL
) {
2547 struct extra_type
*pextra
= extra_type_by_rule_name(base_name
);
2549 if (pextra
!= NULL
) {
2550 base_type_init(pextra
, idx
);
2551 section_strlcpy(&base_sections
[idx
* MAX_SECTION_LABEL
], sec_name
);
2553 ruleset_error(LOG_ERROR
,
2554 "No extra definition matching base definition \"%s\"",
2559 ruleset_error(LOG_ERROR
,
2560 "Base section \"%s\" does not associate base with any extra",
2567 section_list_destroy(sec
);
2573 sec
= secfile_sections_by_name_prefix(file
, ROAD_SECTION_PREFIX
);
2574 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
2575 if (nval
> MAX_ROAD_TYPES
) {
2576 ruleset_error(LOG_ERROR
, "\"%s\": Too many road types (%d, max %d)",
2577 filename
, nval
, MAX_ROAD_TYPES
);
2581 game
.control
.num_road_types
= nval
;
2587 if (road_sections
) {
2588 free(road_sections
);
2590 road_sections
= fc_calloc(nval
, MAX_SECTION_LABEL
);
2592 /* Cannot use extra_type_by_cause_iterate(EC_ROAD) before roads are added to
2593 * EC_ROAD caused_by list. Have to get them by extra_type_by_rule_name() */
2594 for (idx
= 0; idx
< nval
; idx
++) {
2595 const char *sec_name
= section_name(section_list_get(sec
, idx
));
2596 const char *road_name
= secfile_lookup_str(file
, "%s.extra", sec_name
);
2598 if (road_name
!= NULL
) {
2599 struct extra_type
*pextra
= extra_type_by_rule_name(road_name
);
2601 if (pextra
!= NULL
) {
2602 road_type_init(pextra
, idx
);
2603 section_strlcpy(&road_sections
[idx
* MAX_SECTION_LABEL
], sec_name
);
2605 ruleset_error(LOG_ERROR
,
2606 "No extra definition matching road definition \"%s\"",
2611 ruleset_error(LOG_ERROR
,
2612 "Road section \"%s\" does not associate road with any extra",
2619 section_list_destroy(sec
);
2622 /* resource names */
2625 sec
= secfile_sections_by_name_prefix(file
, RESOURCE_SECTION_PREFIX
);
2626 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
2627 if (nval
> MAX_RESOURCE_TYPES
) {
2628 ruleset_error(LOG_ERROR
, "\"%s\": Too many resource types (%d, max %d)",
2629 filename
, nval
, MAX_RESOURCE_TYPES
);
2633 game
.control
.num_resource_types
= nval
;
2639 if (resource_sections
) {
2640 free(resource_sections
);
2642 resource_sections
= fc_calloc(nval
, MAX_SECTION_LABEL
);
2644 /* Cannot use resource_type_iterate() before resource are added to
2645 * EC_RESOURCE caused_by list. Have to get them by extra_type_by_rule_name() */
2646 for (idx
= 0; idx
< nval
; idx
++) {
2647 const char *sec_name
= section_name(section_list_get(sec
, idx
));
2648 const char *resource_name
;
2649 struct extra_type
*pextra
= NULL
;
2651 resource_name
= secfile_lookup_str_default(file
, NULL
, "%s.extra", sec_name
);
2653 if (resource_name
!= NULL
) {
2654 pextra
= extra_type_by_rule_name(resource_name
);
2656 if (pextra
!= NULL
) {
2657 resource_type_init(pextra
);
2658 section_strlcpy(&resource_sections
[idx
* MAX_SECTION_LABEL
], sec_name
);
2660 ruleset_error(LOG_ERROR
,
2661 "No extra definition matching resource definition \"%s\"",
2666 ruleset_error(LOG_ERROR
,
2667 "Resource section %s does not list extra this resource belongs to.",
2674 section_list_destroy(sec
);
2679 /**************************************************************************
2680 Load terrain types related ruleset data
2681 **************************************************************************/
2682 static bool load_ruleset_terrain(struct section_file
*file
,
2683 struct rscompat_info
*compat
)
2687 bool compat_road
= FALSE
;
2688 bool compat_rail
= FALSE
;
2689 bool compat_river
= FALSE
;
2691 const char *filename
= secfile_name(file
);
2697 terrain_control
.ocean_reclaim_requirement_pct
2698 = secfile_lookup_int_default(file
, 101,
2699 "parameters.ocean_reclaim_requirement");
2700 terrain_control
.land_channel_requirement_pct
2701 = secfile_lookup_int_default(file
, 101,
2702 "parameters.land_channel_requirement");
2703 terrain_control
.terrain_thaw_requirement_pct
2704 = secfile_lookup_int_default(file
, 101,
2705 "parameters.thaw_requirement");
2706 terrain_control
.terrain_freeze_requirement_pct
2707 = secfile_lookup_int_default(file
, 101,
2708 "parameters.freeze_requirement");
2709 terrain_control
.lake_max_size
2710 = secfile_lookup_int_default(file
, 0,
2711 "parameters.lake_max_size");
2712 terrain_control
.min_start_native_area
2713 = secfile_lookup_int_default(file
, 0,
2714 "parameters.min_start_native_area");
2715 terrain_control
.move_fragments
2716 = secfile_lookup_int_default(file
, 3,
2717 "parameters.move_fragments");
2718 if (terrain_control
.move_fragments
< 1) {
2719 ruleset_error(LOG_ERROR
, "\"%s\": move_fragments must be at least 1",
2723 init_move_fragments();
2724 terrain_control
.igter_cost
2725 = secfile_lookup_int_default(file
, 1,
2726 "parameters.igter_cost");
2727 if (terrain_control
.igter_cost
< 1) {
2728 ruleset_error(LOG_ERROR
, "\"%s\": igter_cost must be at least 1",
2732 terrain_control
.pythagorean_diagonal
2733 = secfile_lookup_bool_default(file
, RS_DEFAULT_PYTHAGOREAN_DIAGONAL
,
2734 "parameters.pythagorean_diagonal");
2736 wld
.map
.server
.ocean_resources
2737 = secfile_lookup_bool_default(file
, FALSE
,
2738 "parameters.ocean_resources");
2740 text
= secfile_lookup_str_default(file
,
2741 N_("?gui_type:Build Type A Base"),
2742 "extraui.ui_name_base_fortress");
2743 sz_strlcpy(terrain_control
.gui_type_base0
, text
);
2745 text
= secfile_lookup_str_default(file
,
2746 N_("?gui_type:Build Type B Base"),
2747 "extraui.ui_name_base_airbase");
2748 sz_strlcpy(terrain_control
.gui_type_base1
, text
);
2751 /* terrain details */
2753 terrain_type_iterate(pterrain
) {
2755 const int i
= terrain_index(pterrain
);
2756 const char *tsection
= &terrain_sections
[i
* MAX_SECTION_LABEL
];
2759 sz_strlcpy(pterrain
->graphic_str
,
2760 secfile_lookup_str(file
,"%s.graphic", tsection
));
2761 sz_strlcpy(pterrain
->graphic_alt
,
2762 secfile_lookup_str(file
,"%s.graphic_alt", tsection
));
2764 pterrain
->identifier
2765 = secfile_lookup_str(file
, "%s.identifier", tsection
)[0];
2766 if ('\0' == pterrain
->identifier
) {
2767 ruleset_error(LOG_ERROR
, "\"%s\" [%s] identifier missing value.",
2768 filename
, tsection
);
2772 if (TERRAIN_UNKNOWN_IDENTIFIER
== pterrain
->identifier
) {
2773 ruleset_error(LOG_ERROR
,
2774 "\"%s\" [%s] cannot use '%c' as an identifier;"
2775 " it is reserved for unknown terrain.",
2776 filename
, tsection
, pterrain
->identifier
);
2780 for (j
= T_FIRST
; j
< i
; j
++) {
2781 if (pterrain
->identifier
== terrain_by_number(j
)->identifier
) {
2782 ruleset_error(LOG_ERROR
,
2783 "\"%s\" [%s] has the same identifier as [%s].",
2786 &terrain_sections
[j
* MAX_SECTION_LABEL
]);
2796 cstr
= secfile_lookup_str(file
, "%s.class", tsection
);
2797 pterrain
->tclass
= terrain_class_by_name(cstr
, fc_strcasecmp
);
2798 if (!terrain_class_is_valid(pterrain
->tclass
)) {
2799 ruleset_error(LOG_ERROR
, "\"%s\": [%s] unknown class \"%s\"",
2800 filename
, tsection
, cstr
);
2805 if (!secfile_lookup_int(file
, &pterrain
->movement_cost
,
2806 "%s.movement_cost", tsection
)
2807 || !secfile_lookup_int(file
, &pterrain
->defense_bonus
,
2808 "%s.defense_bonus", tsection
)) {
2809 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2814 output_type_iterate(o
) {
2816 = secfile_lookup_int_default(file
, 0, "%s.%s", tsection
,
2817 get_output_identifier(o
));
2818 } output_type_iterate_end
;
2820 res
= secfile_lookup_str_vec(file
, &nval
, "%s.resources", tsection
);
2821 pterrain
->resources
= fc_calloc(nval
+ 1, sizeof(*pterrain
->resources
));
2822 for (j
= 0; j
< nval
; j
++) {
2823 pterrain
->resources
[j
] = lookup_resource(filename
, res
[j
], tsection
);
2824 if (pterrain
->resources
[j
] == NULL
) {
2829 pterrain
->resources
[nval
] = NULL
;
2837 output_type_iterate(o
) {
2838 pterrain
->road_output_incr_pct
[o
]
2839 = secfile_lookup_int_default(file
, 0, "%s.road_%s_incr_pct",
2840 tsection
, get_output_identifier(o
));
2841 } output_type_iterate_end
;
2843 if (!lookup_time(file
, &pterrain
->base_time
, tsection
, "base_time",
2844 filename
, NULL
, &ok
)
2845 || !lookup_time(file
, &pterrain
->road_time
, tsection
, "road_time",
2846 filename
, NULL
, &ok
)) {
2847 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2852 if (!lookup_terrain(file
, "irrigation_result", filename
, pterrain
,
2853 &pterrain
->irrigation_result
)) {
2857 if (!secfile_lookup_int(file
, &pterrain
->irrigation_food_incr
,
2858 "%s.irrigation_food_incr", tsection
)
2859 || !lookup_time(file
, &pterrain
->irrigation_time
,
2860 tsection
, "irrigation_time", filename
, NULL
, &ok
)) {
2861 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2866 if (!lookup_terrain(file
, "mining_result", filename
, pterrain
,
2867 &pterrain
->mining_result
)) {
2871 if (!secfile_lookup_int(file
, &pterrain
->mining_shield_incr
,
2872 "%s.mining_shield_incr", tsection
)
2873 || !lookup_time(file
, &pterrain
->mining_time
,
2874 tsection
, "mining_time", filename
, NULL
, &ok
)) {
2875 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2880 if (!lookup_unit_type(file
, tsection
, "animal",
2881 &pterrain
->animal
, filename
,
2882 rule_name_get(&pterrain
->name
))) {
2887 if (!lookup_terrain(file
, "transform_result", filename
, pterrain
,
2888 &pterrain
->transform_result
)) {
2892 if (!lookup_time(file
, &pterrain
->transform_time
,
2893 tsection
, "transform_time", filename
, NULL
, &ok
)) {
2894 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2898 pterrain
->pillage_time
= 1; /* default */
2899 lookup_time(file
, &pterrain
->pillage_time
,
2900 tsection
, "pillage_time", filename
, NULL
, &ok
);
2901 pterrain
->clean_pollution_time
= 3; /* default */
2902 lookup_time(file
, &pterrain
->clean_pollution_time
,
2903 tsection
, "clean_pollution_time", filename
, NULL
, &ok
);
2904 pterrain
->clean_fallout_time
= 3; /* default */
2905 lookup_time(file
, &pterrain
->clean_fallout_time
,
2906 tsection
, "clean_fallout_time", filename
, NULL
, &ok
);
2908 if (!lookup_terrain(file
, "warmer_wetter_result", filename
, pterrain
,
2909 &pterrain
->warmer_wetter_result
)
2910 || !lookup_terrain(file
, "warmer_drier_result", filename
, pterrain
,
2911 &pterrain
->warmer_drier_result
)
2912 || !lookup_terrain(file
, "cooler_wetter_result", filename
, pterrain
,
2913 &pterrain
->cooler_wetter_result
)
2914 || !lookup_terrain(file
, "cooler_drier_result", filename
, pterrain
,
2915 &pterrain
->cooler_drier_result
)) {
2920 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", tsection
);
2921 BV_CLR_ALL(pterrain
->flags
);
2922 for (j
= 0; j
< nval
; j
++) {
2923 const char *sval
= slist
[j
];
2924 enum terrain_flag_id flag
2925 = terrain_flag_id_by_name(sval
, fc_strcasecmp
);
2927 if (!terrain_flag_id_is_valid(flag
)) {
2928 ruleset_error(LOG_ERROR
, "\"%s\" [%s] has unknown flag \"%s\".",
2929 filename
, tsection
, sval
);
2933 BV_SET(pterrain
->flags
, flag
);
2943 enum mapgen_terrain_property mtp
;
2944 for (mtp
= mapgen_terrain_property_begin();
2945 mtp
!= mapgen_terrain_property_end();
2946 mtp
= mapgen_terrain_property_next(mtp
)) {
2947 pterrain
->property
[mtp
]
2948 = secfile_lookup_int_default(file
, 0, "%s.property_%s", tsection
,
2949 mapgen_terrain_property_name(mtp
));
2953 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.native_to", tsection
);
2954 BV_CLR_ALL(pterrain
->native_to
);
2955 for (j
= 0; j
< nval
; j
++) {
2956 struct unit_class
*class = unit_class_by_rule_name(slist
[j
]);
2959 ruleset_error(LOG_ERROR
,
2960 "\"%s\" [%s] is native to unknown unit class \"%s\".",
2961 filename
, tsection
, slist
[j
]);
2965 BV_SET(pterrain
->native_to
, uclass_index(class));
2974 /* get terrain color */
2976 fc_assert_ret_val(pterrain
->rgb
== NULL
, FALSE
);
2977 if (!rgbcolor_load(file
, &pterrain
->rgb
, "%s.color", tsection
)) {
2978 ruleset_error(LOG_ERROR
, "Missing terrain color definition: %s",
2985 pterrain
->helptext
= lookup_strvec(file
, tsection
, "helptext");
2986 } terrain_type_iterate_end
;
2991 extra_type_iterate(pextra
) {
2992 BV_CLR_ALL(pextra
->conflicts
);
2993 } extra_type_iterate_end
;
2995 extra_type_iterate(pextra
) {
2996 if (!compat
->compat_mode
|| compat
->ver_terrain
>= 10 || pextra
->category
!= ECAT_RESOURCE
) {
2997 const char *section
= &extra_sections
[extra_index(pextra
) * MAX_SECTION_LABEL
];
2999 struct requirement_vector
*reqs
;
3000 const char *catname
;
3002 enum extra_cause cause
;
3003 enum extra_rmcause rmcause
;
3004 const char *eus_name
;
3005 const char *vis_req_name
;
3006 const struct advance
*vis_req
;
3008 catname
= secfile_lookup_str(file
, "%s.category", section
);
3009 if (catname
== NULL
) {
3010 ruleset_error(LOG_ERROR
, "\"%s\" extra \"%s\" has no category.",
3012 extra_rule_name(pextra
));
3016 pextra
->category
= extra_category_by_name(catname
, fc_strcasecmp
);
3017 if (!extra_category_is_valid(pextra
->category
)) {
3018 ruleset_error(LOG_ERROR
,
3019 "\"%s\" extra \"%s\" has invalid category \"%s\".",
3020 filename
, extra_rule_name(pextra
), catname
);
3025 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.causes", section
);
3027 for (cj
= 0; cj
< nval
; cj
++) {
3028 const char *sval
= slist
[cj
];
3029 cause
= extra_cause_by_name(sval
, fc_strcasecmp
);
3031 if (!extra_cause_is_valid(cause
)) {
3032 ruleset_error(LOG_ERROR
, "\"%s\" extra \"%s\": unknown cause \"%s\".",
3034 extra_rule_name(pextra
),
3039 pextra
->causes
|= (1 << cause
);
3040 extra_to_caused_by_list(pextra
, cause
);
3044 extra_to_category_list(pextra
, pextra
->category
);
3046 if (pextra
->causes
== 0) {
3047 /* Extras that do not have any causes added to EC_NONE list */
3048 extra_to_caused_by_list(pextra
, EC_NONE
);
3051 if (!is_extra_caused_by(pextra
, EC_BASE
)
3052 && !is_extra_caused_by(pextra
, EC_ROAD
)
3053 && !is_extra_caused_by(pextra
, EC_RESOURCE
)) {
3054 /* Not a base, road, nor resource, so special */
3055 pextra
->data
.special_idx
= extra_type_list_size(extra_type_list_by_cause(EC_SPECIAL
));
3056 extra_to_caused_by_list(pextra
, EC_SPECIAL
);
3061 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.rmcauses", section
);
3062 pextra
->rmcauses
= 0;
3063 for (j
= 0; j
< nval
; j
++) {
3064 const char *sval
= slist
[j
];
3065 rmcause
= extra_rmcause_by_name(sval
, fc_strcasecmp
);
3067 if (!extra_rmcause_is_valid(rmcause
)) {
3068 ruleset_error(LOG_ERROR
, "\"%s\" extra \"%s\": unknown rmcause \"%s\".",
3070 extra_rule_name(pextra
),
3075 pextra
->rmcauses
|= (1 << rmcause
);
3076 extra_to_removed_by_list(pextra
, rmcause
);
3082 sz_strlcpy(pextra
->activity_gfx
,
3083 secfile_lookup_str_default(file
, "-",
3084 "%s.activity_gfx", section
));
3085 sz_strlcpy(pextra
->act_gfx_alt
,
3086 secfile_lookup_str_default(file
, "-",
3087 "%s.act_gfx_alt", section
));
3088 sz_strlcpy(pextra
->act_gfx_alt2
,
3089 secfile_lookup_str_default(file
, "-",
3090 "%s.act_gfx_alt2", section
));
3091 sz_strlcpy(pextra
->rmact_gfx
,
3092 secfile_lookup_str_default(file
, "-",
3093 "%s.rmact_gfx", section
));
3094 sz_strlcpy(pextra
->rmact_gfx_alt
,
3095 secfile_lookup_str_default(file
, "-",
3096 "%s.rmact_gfx_alt", section
));
3097 sz_strlcpy(pextra
->graphic_str
,
3098 secfile_lookup_str_default(file
, "-", "%s.graphic", section
));
3099 sz_strlcpy(pextra
->graphic_alt
,
3100 secfile_lookup_str_default(file
, "-",
3101 "%s.graphic_alt", section
));
3103 reqs
= lookup_req_list(file
, compat
, section
, "reqs", extra_rule_name(pextra
));
3108 requirement_vector_copy(&pextra
->reqs
, reqs
);
3110 reqs
= lookup_req_list(file
, compat
, section
, "rmreqs", extra_rule_name(pextra
));
3115 requirement_vector_copy(&pextra
->rmreqs
, reqs
);
3117 reqs
= lookup_req_list(file
, compat
, section
, "appearance_reqs", extra_rule_name(pextra
));
3122 requirement_vector_copy(&pextra
->appearance_reqs
, reqs
);
3124 reqs
= lookup_req_list(file
, compat
, section
, "disappearance_reqs", extra_rule_name(pextra
));
3129 requirement_vector_copy(&pextra
->disappearance_reqs
, reqs
);
3131 pextra
->buildable
= secfile_lookup_bool_default(file
,
3132 is_extra_caused_by_worker_action(pextra
),
3133 "%s.buildable", section
);
3135 pextra
->build_time
= 0; /* default */
3136 lookup_time(file
, &pextra
->build_time
, section
, "build_time",
3137 filename
, extra_rule_name(pextra
), &ok
);
3138 pextra
->build_time_factor
= secfile_lookup_int_default(file
, 1,
3139 "%s.build_time_factor", section
);
3140 pextra
->removal_time
= 0; /* default */
3141 lookup_time(file
, &pextra
->removal_time
, section
, "removal_time",
3142 filename
, extra_rule_name(pextra
), &ok
);
3143 pextra
->removal_time_factor
= secfile_lookup_int_default(file
, 1,
3144 "%s.removal_time_factor", section
);
3146 pextra
->defense_bonus
= secfile_lookup_int_default(file
, 0,
3149 if (pextra
->defense_bonus
!= 0) {
3150 if (extra_has_flag(pextra
, EF_NATURAL_DEFENSE
)) {
3151 extra_to_caused_by_list(pextra
, EC_NATURAL_DEFENSIVE
);
3153 extra_to_caused_by_list(pextra
, EC_DEFENSIVE
);
3157 eus_name
= secfile_lookup_str_default(file
, "Normal", "%s.unit_seen", section
);
3158 pextra
->eus
= extra_unit_seen_type_by_name(eus_name
, fc_strcasecmp
);
3159 if (!extra_unit_seen_type_is_valid(pextra
->eus
)) {
3160 ruleset_error(LOG_ERROR
,
3161 "\"%s\" extra \"%s\" has illegal unit_seen value \"%s\".",
3162 filename
, extra_rule_name(pextra
),
3167 if (pextra
->eus
== EUS_HIDDEN
) {
3168 extra_type_list_append(extra_type_list_of_unit_hiders(), pextra
);
3171 pextra
->appearance_chance
= secfile_lookup_int_default(file
, RS_DEFAULT_EXTRA_APPEARANCE
,
3172 "%s.appearance_chance",
3174 pextra
->disappearance_chance
= secfile_lookup_int_default(file
,
3175 RS_DEFAULT_EXTRA_DISAPPEARANCE
,
3176 "%s.disappearance_chance",
3179 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.native_to", section
);
3180 BV_CLR_ALL(pextra
->native_to
);
3181 for (j
= 0; j
< nval
; j
++) {
3182 struct unit_class
*uclass
= unit_class_by_rule_name(slist
[j
]);
3184 if (uclass
== NULL
) {
3185 ruleset_error(LOG_ERROR
,
3186 "\"%s\" extra \"%s\" is native to unknown unit class \"%s\".",
3188 extra_rule_name(pextra
),
3193 BV_SET(pextra
->native_to
, uclass_index(uclass
));
3202 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", section
);
3203 BV_CLR_ALL(pextra
->flags
);
3204 for (j
= 0; j
< nval
; j
++) {
3205 const char *sval
= slist
[j
];
3206 enum extra_flag_id flag
= extra_flag_id_by_name(sval
, fc_strcasecmp
);
3208 if (!extra_flag_id_is_valid(flag
)) {
3209 ruleset_error(LOG_ERROR
, "\"%s\" extra \"%s\": unknown flag \"%s\".",
3211 extra_rule_name(pextra
),
3216 BV_SET(pextra
->flags
, flag
);
3225 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.conflicts", section
);
3226 for (j
= 0; j
< nval
; j
++) {
3227 const char *sval
= slist
[j
];
3228 struct extra_type
*pextra2
= extra_type_by_rule_name(sval
);
3230 if (pextra2
== NULL
) {
3231 ruleset_error(LOG_ERROR
, "\"%s\" extra \"%s\": unknown conflict extra \"%s\".",
3233 extra_rule_name(pextra
),
3238 BV_SET(pextra
->conflicts
, extra_index(pextra2
));
3239 BV_SET(pextra2
->conflicts
, extra_index(pextra
));
3249 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.hidden_by", section
);
3250 BV_CLR_ALL(pextra
->hidden_by
);
3251 for (j
= 0; j
< nval
; j
++) {
3252 const char *sval
= slist
[j
];
3253 const struct extra_type
*top
= extra_type_by_rule_name(sval
);
3256 ruleset_error(LOG_ERROR
, "\"%s\" extra \"%s\" hidden by unknown extra \"%s\".",
3258 extra_rule_name(pextra
),
3263 BV_SET(pextra
->hidden_by
, extra_index(top
));
3272 vis_req_name
= secfile_lookup_str_default(file
, "None",
3273 "%s.visibility_req", section
);
3274 vis_req
= advance_by_rule_name(vis_req_name
);
3276 if (vis_req
== NULL
) {
3277 ruleset_error(LOG_ERROR
, "\%s\" %s: unkniwn visibility_req %s.",
3278 filename
, section
, vis_req_name
);
3283 pextra
->visibility_req
= advance_number(vis_req
);
3285 pextra
->helptext
= lookup_strvec(file
, section
, "helptext");
3287 } extra_type_iterate_end
;
3292 /* resource details */
3294 extra_type_by_cause_iterate(EC_RESOURCE
, presource
) {
3295 char identifier
[MAX_LEN_NAME
];
3296 const char *rsection
= &resource_sections
[i
* MAX_SECTION_LABEL
];
3298 output_type_iterate (o
) {
3299 presource
->data
.resource
->output
[o
] =
3300 secfile_lookup_int_default(file
, 0, "%s.%s", rsection
,
3301 get_output_identifier(o
));
3302 } output_type_iterate_end
;
3304 sz_strlcpy(identifier
,
3305 secfile_lookup_str(file
,"%s.identifier", rsection
));
3306 presource
->data
.resource
->id_old_save
= identifier
[0];
3307 if (RESOURCE_NULL_IDENTIFIER
== presource
->data
.resource
->id_old_save
) {
3308 ruleset_error(LOG_ERROR
, "\"%s\" [%s] identifier missing value.",
3309 filename
, rsection
);
3313 if (RESOURCE_NONE_IDENTIFIER
== presource
->data
.resource
->id_old_save
) {
3314 ruleset_error(LOG_ERROR
,
3315 "\"%s\" [%s] cannot use '%c' as an identifier;"
3317 filename
, rsection
, presource
->data
.resource
->id_old_save
);
3327 } extra_type_by_cause_iterate_end
;
3331 /* This can't be part of previous loop as we don't want random data from previous
3332 * ruleset to play havoc on us when we have only some resource identifiers loaded
3333 * from the new ruleset. */
3334 extra_type_by_cause_iterate(EC_RESOURCE
, pres
) {
3335 extra_type_by_cause_iterate(EC_RESOURCE
, pres2
) {
3336 if (pres
->data
.resource
->id_old_save
== pres2
->data
.resource
->id_old_save
3338 ruleset_error(LOG_ERROR
,
3339 "\"%s\" [%s] has the same identifier as [%s].",
3341 extra_rule_name(pres
),
3342 extra_rule_name(pres2
));
3346 } extra_type_by_cause_iterate_end
;
3351 } extra_type_by_cause_iterate_end
;
3356 extra_type_by_cause_iterate(EC_BASE
, pextra
) {
3357 struct base_type
*pbase
= extra_base_get(pextra
);
3358 const char *section
= &base_sections
[base_number(pbase
) * MAX_SECTION_LABEL
];
3361 const char *gui_str
;
3363 gui_str
= secfile_lookup_str(file
,"%s.gui_type", section
);
3364 pbase
->gui_type
= base_gui_type_by_name(gui_str
, fc_strcasecmp
);
3365 if (!base_gui_type_is_valid(pbase
->gui_type
)) {
3366 ruleset_error(LOG_ERROR
, "\"%s\" base \"%s\": unknown gui_type \"%s\".",
3368 extra_rule_name(pextra
),
3374 pbase
->border_sq
= secfile_lookup_int_default(file
, -1, "%s.border_sq",
3376 pbase
->vision_main_sq
= secfile_lookup_int_default(file
, -1,
3377 "%s.vision_main_sq",
3379 pbase
->vision_invis_sq
= secfile_lookup_int_default(file
, -1,
3380 "%s.vision_invis_sq",
3383 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", section
);
3384 BV_CLR_ALL(pbase
->flags
);
3385 for (bj
= 0; bj
< nval
; bj
++) {
3386 const char *sval
= slist
[bj
];
3387 enum base_flag_id flag
= base_flag_id_by_name(sval
, fc_strcasecmp
);
3389 if (!base_flag_id_is_valid(flag
)) {
3390 ruleset_error(LOG_ERROR
, "\"%s\" base \"%s\": unknown flag \"%s\".",
3392 extra_rule_name(pextra
),
3396 } else if ((!compat
->compat_mode
|| compat
->ver_terrain
>= 10)
3397 && base_flag_is_retired(flag
)) {
3398 ruleset_error(LOG_ERROR
, "\"%s\" base \"%s\": retired flag "
3399 "\"%s\". Please update the ruleset.",
3401 extra_rule_name(pextra
),
3405 BV_SET(pbase
->flags
, flag
);
3415 if (territory_claiming_base(pbase
)) {
3416 extra_type_by_cause_iterate(EC_BASE
, pextra2
) {
3417 struct base_type
*pbase2
;
3419 if (pextra
== pextra2
) {
3420 /* End of the fully initialized bases iteration. */
3424 pbase2
= extra_base_get(pextra2
);
3425 if (territory_claiming_base(pbase2
)) {
3426 BV_SET(pextra
->conflicts
, extra_index(pextra2
));
3427 BV_SET(pextra2
->conflicts
, extra_index(pextra
));
3429 } extra_type_by_cause_iterate_end
;
3431 } extra_type_by_cause_iterate_end
;
3435 extra_type_by_cause_iterate(EC_ROAD
, pextra
) {
3436 struct road_type
*proad
= extra_road_get(pextra
);
3437 const char *section
= &road_sections
[road_number(proad
) * MAX_SECTION_LABEL
];
3439 const char *special
;
3440 const char *modestr
;
3441 struct requirement_vector
*reqs
;
3443 reqs
= lookup_req_list(file
, compat
, section
, "first_reqs", extra_rule_name(pextra
));
3448 requirement_vector_copy(&proad
->first_reqs
, reqs
);
3450 if (!secfile_lookup_int(file
, &proad
->move_cost
,
3451 "%s.move_cost", section
)) {
3452 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
3457 modestr
= secfile_lookup_str_default(file
, "FastAlways", "%s.move_mode",
3459 proad
->move_mode
= road_move_mode_by_name(modestr
, fc_strcasecmp
);
3460 if (!road_move_mode_is_valid(proad
->move_mode
)) {
3461 ruleset_error(LOG_ERROR
, "Illegal move_mode \"%s\" for road \"%s\"",
3462 modestr
, extra_rule_name(pextra
));
3467 output_type_iterate(o
) {
3468 proad
->tile_incr_const
[o
] =
3469 secfile_lookup_int_default(file
, 0, "%s.%s_incr_const",
3470 section
, get_output_identifier(o
));
3471 proad
->tile_incr
[o
] =
3472 secfile_lookup_int_default(file
, 0, "%s.%s_incr",
3473 section
, get_output_identifier(o
));
3474 proad
->tile_bonus
[o
] =
3475 secfile_lookup_int_default(file
, 0, "%s.%s_bonus",
3476 section
, get_output_identifier(o
));
3477 } output_type_iterate_end
;
3479 special
= secfile_lookup_str_default(file
, "None", "%s.compat_special", section
);
3480 if (!fc_strcasecmp(special
, "Road")) {
3482 ruleset_error(LOG_ERROR
, "Multiple roads marked as compatibility \"Road\"");
3486 proad
->compat
= ROCO_ROAD
;
3487 } else if (!fc_strcasecmp(special
, "Railroad")) {
3489 ruleset_error(LOG_ERROR
, "Multiple roads marked as compatibility \"Railroad\"");
3493 proad
->compat
= ROCO_RAILROAD
;
3494 } else if (!fc_strcasecmp(special
, "River")) {
3496 ruleset_error(LOG_ERROR
, "Multiple roads marked as compatibility \"River\"");
3499 compat_river
= TRUE
;
3500 proad
->compat
= ROCO_RIVER
;
3501 } else if (!fc_strcasecmp(special
, "None")) {
3502 proad
->compat
= ROCO_NONE
;
3504 ruleset_error(LOG_ERROR
, "Illegal compatibility special \"%s\" for road %s",
3505 special
, extra_rule_name(pextra
));
3513 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.integrates", section
);
3514 BV_CLR_ALL(proad
->integrates
);
3515 for (j
= 0; j
< nval
; j
++) {
3516 const char *sval
= slist
[j
];
3517 struct extra_type
*textra
= extra_type_by_rule_name(sval
);
3518 struct road_type
*top
= NULL
;
3520 if (textra
!= NULL
) {
3521 top
= extra_road_get(textra
);
3525 ruleset_error(LOG_ERROR
, "\"%s\" road \"%s\" integrates with unknown road \"%s\".",
3527 extra_rule_name(pextra
),
3532 BV_SET(proad
->integrates
, road_number(top
));
3541 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", section
);
3542 BV_CLR_ALL(proad
->flags
);
3543 for (j
= 0; j
< nval
; j
++) {
3544 const char *sval
= slist
[j
];
3545 enum road_flag_id flag
= road_flag_id_by_name(sval
, fc_strcasecmp
);
3547 if (!road_flag_id_is_valid(flag
)) {
3548 ruleset_error(LOG_ERROR
, "\"%s\" road \"%s\": unknown flag \"%s\".",
3550 extra_rule_name(pextra
),
3555 BV_SET(proad
->flags
, flag
);
3563 } extra_type_by_cause_iterate_end
;
3567 secfile_check_unused(file
);
3573 /**************************************************************************
3574 Load names of governments so other rulesets can refer to governments with
3575 their name. Also load multiplier names/count from governments.ruleset.
3576 **************************************************************************/
3577 static bool load_government_names(struct section_file
*file
,
3578 struct rscompat_info
*compat
)
3581 struct section_list
*sec
;
3582 const char *filename
= secfile_name(file
);
3585 compat
->ver_governments
= rscompat_check_capabilities(file
, filename
,
3587 if (compat
->ver_governments
<= 0) {
3591 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
3592 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
3594 sec
= secfile_sections_by_name_prefix(file
, GOVERNMENT_SECTION_PREFIX
);
3595 if (NULL
== sec
|| 0 == (nval
= section_list_size(sec
))) {
3596 ruleset_error(LOG_ERROR
, "\"%s\": No governments?!?", filename
);
3598 } else if (nval
> G_LAST
) {
3599 ruleset_error(LOG_ERROR
, "\"%s\": Too many governments (%d, max %d)",
3600 filename
, nval
, G_LAST
);
3605 governments_alloc(nval
);
3607 /* Government names are needed early so that get_government_by_name will
3609 governments_iterate(gov
) {
3610 const char *sec_name
=
3611 section_name(section_list_get(sec
, government_index(gov
)));
3613 if (!ruleset_load_names(&gov
->name
, NULL
, file
, sec_name
)) {
3617 } governments_iterate_end
;
3620 section_list_destroy(sec
);
3623 sec
= secfile_sections_by_name_prefix(file
, MULTIPLIER_SECTION_PREFIX
);
3624 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
3626 if (nval
> MAX_NUM_MULTIPLIERS
) {
3627 ruleset_error(LOG_ERROR
, "\"%s\": Too many multipliers (%d, max %d)",
3628 filename
, nval
, MAX_NUM_MULTIPLIERS
);
3632 game
.control
.num_multipliers
= nval
;
3636 multipliers_iterate(pmul
) {
3637 const char *sec_name
=
3638 section_name(section_list_get(sec
, multiplier_index(pmul
)));
3640 if (!ruleset_load_names(&pmul
->name
, NULL
, file
, sec_name
)) {
3641 ruleset_error(LOG_ERROR
, "\"%s\": Cannot load multiplier names",
3646 } multipliers_iterate_end
;
3650 section_list_destroy(sec
);
3655 /**************************************************************************
3656 This loads information from given governments.ruleset
3657 **************************************************************************/
3658 static bool load_ruleset_governments(struct section_file
*file
,
3659 struct rscompat_info
*compat
)
3661 struct section_list
*sec
;
3662 const char *filename
= secfile_name(file
);
3665 sec
= secfile_sections_by_name_prefix(file
, GOVERNMENT_SECTION_PREFIX
);
3667 game
.government_during_revolution
3668 = lookup_government(file
, "governments.during_revolution", filename
, NULL
);
3669 if (game
.government_during_revolution
== NULL
) {
3674 game
.info
.government_during_revolution_id
=
3675 government_number(game
.government_during_revolution
);
3678 governments_iterate(g
) {
3679 const int i
= government_index(g
);
3680 const char *sec_name
= section_name(section_list_get(sec
, i
));
3681 struct requirement_vector
*reqs
=
3682 lookup_req_list(file
, compat
, sec_name
, "reqs", government_rule_name(g
));
3689 if (NULL
!= secfile_entry_lookup(file
, "%s.ai_better", sec_name
)) {
3692 fc_snprintf(entry
, sizeof(entry
), "%s.ai_better", sec_name
);
3693 g
->ai
.better
= lookup_government(file
, entry
, filename
, NULL
);
3694 if (g
->ai
.better
== NULL
) {
3699 g
->ai
.better
= NULL
;
3701 requirement_vector_copy(&g
->reqs
, reqs
);
3703 sz_strlcpy(g
->graphic_str
,
3704 secfile_lookup_str(file
, "%s.graphic", sec_name
));
3705 sz_strlcpy(g
->graphic_alt
,
3706 secfile_lookup_str(file
, "%s.graphic_alt", sec_name
));
3708 g
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
3709 } governments_iterate_end
;
3715 governments_iterate(g
) {
3716 const char *sec_name
=
3717 section_name(section_list_get(sec
, government_index(g
)));
3718 const char *male
, *female
;
3720 if (!(male
= secfile_lookup_str(file
, "%s.ruler_male_title", sec_name
))
3721 || !(female
= secfile_lookup_str(file
, "%s.ruler_female_title",
3723 ruleset_error(LOG_ERROR
, "Lack of default ruler titles for "
3724 "government \"%s\" (nb %d): %s",
3725 government_rule_name(g
), government_number(g
),
3729 } else if (NULL
== government_ruler_title_new(g
, NULL
, male
, female
)) {
3730 ruleset_error(LOG_ERROR
, "Lack of default ruler titles for "
3731 "government \"%s\" (nb %d).",
3732 government_rule_name(g
), government_number(g
));
3736 } governments_iterate_end
;
3739 section_list_destroy(sec
);
3742 sec
= secfile_sections_by_name_prefix(file
, MULTIPLIER_SECTION_PREFIX
);
3743 multipliers_iterate(pmul
) {
3744 int id
= multiplier_index(pmul
);
3745 const char *sec_name
= section_name(section_list_get(sec
, id
));
3747 if (!secfile_lookup_int(file
, &pmul
->start
, "%s.start", sec_name
)) {
3748 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
3752 if (!secfile_lookup_int(file
, &pmul
->stop
, "%s.stop", sec_name
)) {
3753 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
3757 if (pmul
->stop
<= pmul
->start
) {
3758 ruleset_error(LOG_ERROR
, "Multiplier \"%s\" stop (%d) must be greater "
3759 "than start (%d)", multiplier_rule_name(pmul
),
3760 pmul
->stop
, pmul
->start
);
3764 if (!secfile_lookup_int(file
, &pmul
->step
, "%s.step", sec_name
)) {
3765 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
3769 if (((pmul
->stop
- pmul
->start
) % pmul
->step
) != 0) {
3770 ruleset_error(LOG_ERROR
, "Multiplier \"%s\" step (%d) does not fit "
3771 "exactly into interval start-stop (%d to %d)",
3772 multiplier_rule_name(pmul
), pmul
->step
,
3773 pmul
->start
, pmul
->stop
);
3777 if (!secfile_lookup_int(file
, &pmul
->def
, "%s.default", sec_name
)) {
3778 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
3782 if (pmul
->def
< pmul
->start
|| pmul
->def
> pmul
->stop
) {
3783 ruleset_error(LOG_ERROR
, "Multiplier \"%s\" default (%d) not within "
3784 "legal range (%d to %d)", multiplier_rule_name(pmul
),
3785 pmul
->def
, pmul
->start
, pmul
->stop
);
3789 if (((pmul
->def
- pmul
->start
) % pmul
->step
) != 0) {
3790 ruleset_error(LOG_ERROR
, "Multiplier \"%s\" default (%d) not legal "
3791 "with respect to step size %d",
3792 multiplier_rule_name(pmul
), pmul
->def
, pmul
->step
);
3796 pmul
->offset
= secfile_lookup_int_default(file
, 0,
3797 "%s.offset", sec_name
);
3798 pmul
->factor
= secfile_lookup_int_default(file
, 100,
3799 "%s.factor", sec_name
);
3800 if (pmul
->factor
== 0) {
3801 ruleset_error(LOG_ERROR
, "Multiplier \"%s\" scaling factor must "
3802 "not be zero", multiplier_rule_name(pmul
));
3807 pmul
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
3808 } multipliers_iterate_end
;
3809 section_list_destroy(sec
);
3813 secfile_check_unused(file
);
3819 /**************************************************************************
3820 Send information in packet_ruleset_control (numbers of units etc, and
3821 other miscellany) to specified connections.
3823 The client assumes that exactly one ruleset control packet is sent as
3824 a part of each ruleset send. So after sending this packet we have to
3825 resend every other part of the rulesets (and none of them should be
3826 is-info in the network code!). The client frees ruleset data when
3827 receiving this packet and then re-initializes as it receives the
3828 individual ruleset packets. See packhand.c.
3829 **************************************************************************/
3830 static void send_ruleset_control(struct conn_list
*dest
)
3832 int desc_left
= game
.control
.desc_length
;
3835 lsend_packet_ruleset_control(dest
, &(game
.control
));
3837 if (game
.ruleset_summary
!= NULL
) {
3838 struct packet_ruleset_summary summary
;
3840 strncpy(summary
.text
, game
.ruleset_summary
, MAX_LEN_CONTENT
);
3842 lsend_packet_ruleset_summary(dest
, &summary
);
3845 while (desc_left
> 0) {
3846 struct packet_ruleset_description_part part
;
3847 int this_len
= desc_left
;
3849 if (this_len
> MAX_LEN_CONTENT
- 21) {
3850 this_len
= MAX_LEN_CONTENT
- 1;
3853 part
.text
[this_len
] = '\0';
3855 strncpy(part
.text
, &game
.ruleset_description
[idx
], this_len
);
3857 desc_left
-= this_len
;
3859 lsend_packet_ruleset_description_part(dest
, &part
);
3863 /****************************************************************************
3864 Check for duplicate leader names in nation.
3865 If no duplicates return NULL; if yes return pointer to name which is
3867 ****************************************************************************/
3868 static const char *check_leader_names(struct nation_type
*pnation
)
3870 nation_leader_list_iterate(nation_leaders(pnation
), pleader
) {
3871 const char *name
= nation_leader_name(pleader
);
3873 nation_leader_list_iterate(nation_leaders(pnation
), prev_leader
) {
3874 if (prev_leader
== pleader
) {
3876 } else if (0 == fc_strcasecmp(name
, nation_leader_name(prev_leader
))) {
3879 } nation_leader_list_iterate_end
;
3880 } nation_leader_list_iterate_end
;
3884 /**************************************************************************
3885 Load names of nations so other rulesets can refer to nations with
3887 **************************************************************************/
3888 static bool load_nation_names(struct section_file
*file
,
3889 struct rscompat_info
*compat
)
3891 struct section_list
*sec
;
3894 const char *filename
= secfile_name(file
);
3896 compat
->ver_nations
= rscompat_check_capabilities(file
, filename
,
3898 if (compat
->ver_nations
<= 0) {
3902 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
3903 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
3905 sec
= secfile_sections_by_name_prefix(file
, NATION_SECTION_PREFIX
);
3907 ruleset_error(LOG_ERROR
, "No available nations in this ruleset!");
3909 } else if (section_list_size(sec
) > MAX_NUM_NATIONS
) {
3910 ruleset_error(LOG_ERROR
, "Too many nations (max %d, we have %d)!",
3911 MAX_NUM_NATIONS
, section_list_size(sec
));
3914 game
.control
.nation_count
= section_list_size(sec
);
3915 nations_alloc(game
.control
.nation_count
);
3917 nations_iterate(pl
) {
3918 const int i
= nation_index(pl
);
3919 const char *sec_name
= section_name(section_list_get(sec
, i
));
3920 const char *domain
= secfile_lookup_str_default(file
, NULL
,
3921 "%s.translation_domain", sec_name
);
3922 const char *noun_plural
= secfile_lookup_str(file
,
3923 "%s.plural", sec_name
);
3926 if (domain
== NULL
) {
3927 domain
= "freeciv-nations";
3930 if (!strcmp("freeciv", domain
)) {
3931 pl
->translation_domain
= NULL
;
3932 } else if (!strcmp("freeciv-nations", domain
)) {
3933 pl
->translation_domain
= fc_malloc(strlen(domain
) + 1);
3934 strcpy(pl
->translation_domain
, domain
);
3936 ruleset_error(LOG_ERROR
, "Unsupported translation domain \"%s\" for %s",
3942 if (!ruleset_load_names(&pl
->adjective
, domain
, file
, sec_name
)) {
3946 name_set(&pl
->noun_plural
, domain
, noun_plural
);
3948 /* Check if nation name is already defined. */
3949 for (j
= 0; j
< i
&& ok
; j
++) {
3950 struct nation_type
*n2
= nation_by_number(j
);
3952 /* Compare strings after stripping off qualifiers -- we don't want
3953 * two nations to end up with identical adjectives displayed to users.
3954 * (This check only catches English, not localisations, of course.) */
3955 if (0 == strcmp(Qn_(untranslated_name(&n2
->adjective
)),
3956 Qn_(untranslated_name(&pl
->adjective
)))) {
3957 ruleset_error(LOG_ERROR
,
3958 "Two nations defined with the same adjective \"%s\": "
3959 "in section \'%s\' and section \'%s\'",
3960 Qn_(untranslated_name(&pl
->adjective
)),
3961 section_name(section_list_get(sec
, j
)), sec_name
);
3963 } else if (!strcmp(rule_name_get(&n2
->adjective
),
3964 rule_name_get(&pl
->adjective
))) {
3965 /* We cannot have the same rule name, as the game needs them to be
3967 ruleset_error(LOG_ERROR
,
3968 "Two nations defined with the same rule_name \"%s\": "
3969 "in section \'%s\' and section \'%s\'",
3970 rule_name_get(&pl
->adjective
),
3971 section_name(section_list_get(sec
, j
)), sec_name
);
3973 } else if (0 == strcmp(Qn_(untranslated_name(&n2
->noun_plural
)),
3974 Qn_(untranslated_name(&pl
->noun_plural
)))) {
3975 /* We don't want identical English plural names either. */
3976 ruleset_error(LOG_ERROR
,
3977 "Two nations defined with the same plural name \"%s\": "
3978 "in section \'%s\' and section \'%s\'",
3979 Qn_(untranslated_name(&pl
->noun_plural
)),
3980 section_name(section_list_get(sec
, j
)), sec_name
);
3987 } nations_iterate_end
;
3990 section_list_destroy(sec
);
3993 sec
= secfile_sections_by_name_prefix(file
, NATION_GROUP_SECTION_PREFIX
);
3995 section_list_iterate(sec
, psection
) {
3996 struct nation_group
*pgroup
;
3999 name
= secfile_lookup_str(file
, "%s.name", section_name(psection
));
4001 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
4005 pgroup
= nation_group_new(name
);
4006 if (pgroup
== NULL
) {
4010 } section_list_iterate_end
;
4011 section_list_destroy(sec
);
4019 /**************************************************************************
4020 Check if a string is in a vector (case-insensitively).
4021 **************************************************************************/
4022 static bool is_on_allowed_list(const char *name
, const char **list
, size_t len
)
4026 for (i
= 0; i
< len
; i
++) {
4027 if (!fc_strcasecmp(name
, list
[i
])) {
4034 /****************************************************************************
4035 This function loads a city name list from a section file. The file and
4036 two section names (which will be concatenated) are passed in.
4037 ****************************************************************************/
4038 static bool load_city_name_list(struct section_file
*file
,
4039 struct nation_type
*pnation
,
4040 const char *secfile_str1
,
4041 const char *secfile_str2
,
4042 const char **allowed_terrains
,
4047 const char **cities
= secfile_lookup_str_vec(file
, &dim
, "%s.%s",
4048 secfile_str1
, secfile_str2
);
4050 /* Each string will be of the form "<cityname> (<label>, <label>, ...)".
4051 * The cityname is just the name for this city, while each "label" matches
4052 * a terrain type for the city (or "river"), with a preceeding ! to negate
4053 * it. The parentheses are optional (but necessary to have the settings,
4054 * of course). Our job is now to parse it. */
4055 for (j
= 0; j
< dim
; j
++) {
4056 size_t len
= strlen(cities
[j
]);
4057 char city_name
[len
+ 1], *p
, *next
, *end
;
4058 struct nation_city
*pncity
;
4060 sz_strlcpy(city_name
, cities
[j
]);
4062 /* Now we wish to determine values for all of the city labels. A value
4063 * of NCP_NONE means no preference (which is necessary so that the use
4064 * of this is optional); NCP_DISLIKE means the label is negated and
4065 * NCP_LIKE means it's labelled. Mostly the parsing just involves
4066 * a lot of ugly string handling... */
4067 if ((p
= strchr(city_name
, '('))) {
4070 if (!(end
= strchr(p
, ')'))) {
4071 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city name \"%s\" "
4072 "unmatched parenthesis.", secfile_name(file
),
4073 secfile_str1
, secfile_str2
, cities
[j
]);
4076 for (*end
++ = '\0'; '\0' != *end
; end
++) {
4077 if (!fc_isspace(*end
)) {
4078 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city name \"%s\" "
4079 "contains characters after last parenthesis.",
4080 secfile_name(file
), secfile_str1
, secfile_str2
,
4089 /* Build the nation_city. */
4090 remove_leading_trailing_spaces(city_name
);
4091 if (check_cityname(city_name
)) {
4092 /* The ruleset contains a name that is too long. This shouldn't
4093 * happen - if it does, the author should get immediate feedback. */
4094 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city name \"%s\" "
4095 "is too long.", secfile_name(file
),
4096 secfile_str1
, secfile_str2
, city_name
);
4098 city_name
[MAX_LEN_CITYNAME
- 1] = '\0';
4100 pncity
= nation_city_new(pnation
, city_name
);
4103 /* Handle the labels one at a time. */
4105 enum nation_city_preference prefer
;
4107 if ((next
= strchr(p
, ','))) {
4110 remove_leading_trailing_spaces(p
);
4112 /* The ! is used to mark a negative, which is recorded with
4113 * NCP_DISLIKE. Otherwise we use a NCP_LIKE.
4117 prefer
= NCP_DISLIKE
;
4122 if (0 == fc_strcasecmp(p
, "river")) {
4123 if (game
.server
.ruledit
.allowed_terrains
!= NULL
4124 && !is_on_allowed_list(p
,
4125 game
.server
.ruledit
.allowed_terrains
, atcount
)) {
4126 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city \"%s\" "
4127 "has terrain hint \"%s\" not in allowed_terrains.",
4128 secfile_name(file
), secfile_str1
, secfile_str2
,
4132 nation_city_set_river_preference(pncity
, prefer
);
4135 const struct terrain
*pterrain
= terrain_by_rule_name(p
);
4137 if (NULL
== pterrain
) {
4138 /* Try with removing frequent trailing 's'. */
4139 size_t l
= strlen(p
);
4141 if (0 < l
&& 's' == fc_tolower(p
[l
- 1])) {
4144 pterrain
= terrain_by_rule_name(p
);
4147 /* Nationset may have been devised with a specific set of terrains
4148 * in mind which don't quite match this ruleset, in which case we
4149 * (a) quietly ignore any hints mentioned that don't happen to be in
4150 * the current ruleset, (b) enforce that terrains mentioned by nations
4151 * must be on the list */
4152 if (pterrain
!= NULL
&& game
.server
.ruledit
.allowed_terrains
!= NULL
) {
4153 if (!is_on_allowed_list(p
,
4154 game
.server
.ruledit
.allowed_terrains
, atcount
)) {
4155 /* Terrain exists, but not intended for these nations */
4156 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city \"%s\" "
4157 "has terrain hint \"%s\" not in allowed_terrains.",
4158 secfile_name(file
), secfile_str1
, secfile_str2
,
4163 } else if (!pterrain
) {
4164 /* Terrain doesn't exist; only complain if it's not on any list */
4165 if (game
.server
.ruledit
.allowed_terrains
== NULL
4166 || !is_on_allowed_list(p
,
4167 game
.server
.ruledit
.allowed_terrains
, atcount
)) {
4168 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city \"%s\" "
4169 "has unknown terrain hint \"%s\".",
4170 secfile_name(file
), secfile_str1
, secfile_str2
,
4176 if (NULL
!= pterrain
) {
4177 nation_city_set_terrain_preference(pncity
, pterrain
, prefer
);
4181 p
= next
? next
+ 1 : NULL
;
4182 } while (NULL
!= p
&& '\0' != *p
);
4186 if (NULL
!= cities
) {
4193 /**************************************************************************
4194 Load nations.ruleset file
4195 **************************************************************************/
4196 static bool load_ruleset_nations(struct section_file
*file
,
4197 struct rscompat_info
*compat
)
4199 struct government
*gov
;
4202 char temp_name
[MAX_LEN_NAME
];
4204 const char *name
, *bad_leader
;
4207 const char *filename
= secfile_name(file
);
4208 struct section_list
*sec
;
4212 name
= secfile_lookup_str_default(file
, NULL
, "ruledit.nationlist");
4214 game
.server
.ruledit
.nationlist
= fc_strdup(name
);
4216 vec
= secfile_lookup_str_vec(file
, &game
.server
.ruledit
.embedded_nations_count
,
4217 "ruledit.embedded_nations");
4220 /* Copy to persistent vector */
4221 game
.server
.ruledit
.embedded_nations
4222 = fc_malloc(game
.server
.ruledit
.embedded_nations_count
* sizeof(char *));
4224 for (j
= 0; j
< game
.server
.ruledit
.embedded_nations_count
; j
++) {
4225 game
.server
.ruledit
.embedded_nations
[j
] = fc_strdup(vec
[j
]);
4231 game
.default_government
= NULL
;
4233 ruleset_load_traits(game
.server
.default_traits
, file
, "default_traits", "");
4234 for (tr
= trait_begin(); tr
!= trait_end(); tr
= trait_next(tr
)) {
4235 if (game
.server
.default_traits
[tr
].min
< 0) {
4236 game
.server
.default_traits
[tr
].min
= TRAIT_DEFAULT_VALUE
;
4238 if (game
.server
.default_traits
[tr
].max
< 0) {
4239 game
.server
.default_traits
[tr
].max
= TRAIT_DEFAULT_VALUE
;
4241 if (game
.server
.default_traits
[tr
].fixed
< 0) {
4242 int diff
= game
.server
.default_traits
[tr
].max
- game
.server
.default_traits
[tr
].min
;
4244 /* TODO: Should sometimes round the a / 2 = x.5 results up */
4245 game
.server
.default_traits
[tr
].fixed
= diff
/ 2 + game
.server
.default_traits
[tr
].min
;
4247 if (game
.server
.default_traits
[tr
].max
< game
.server
.default_traits
[tr
].min
) {
4248 ruleset_error(LOG_ERROR
, "Default values for trait %s not sane.",
4256 vec
= secfile_lookup_str_vec(file
, &game
.server
.ruledit
.ag_count
,
4257 "compatibility.allowed_govs");
4259 /* Copy to persistent vector */
4260 game
.server
.ruledit
.nc_agovs
4261 = fc_malloc(game
.server
.ruledit
.ag_count
* sizeof(char *));
4262 game
.server
.ruledit
.allowed_govs
=
4263 (const char **)game
.server
.ruledit
.nc_agovs
;
4265 for (j
= 0; j
< game
.server
.ruledit
.ag_count
; j
++) {
4266 game
.server
.ruledit
.allowed_govs
[j
] = fc_strdup(vec
[j
]);
4272 vec
= secfile_lookup_str_vec(file
, &game
.server
.ruledit
.at_count
,
4273 "compatibility.allowed_terrains");
4275 /* Copy to persistent vector */
4276 game
.server
.ruledit
.nc_aterrs
4277 = fc_malloc(game
.server
.ruledit
.at_count
* sizeof(char *));
4278 game
.server
.ruledit
.allowed_terrains
=
4279 (const char **)game
.server
.ruledit
.nc_aterrs
;
4281 for (j
= 0; j
< game
.server
.ruledit
.at_count
; j
++) {
4282 game
.server
.ruledit
.allowed_terrains
[j
] = fc_strdup(vec
[j
]);
4288 vec
= secfile_lookup_str_vec(file
, &game
.server
.ruledit
.as_count
,
4289 "compatibility.allowed_styles");
4291 /* Copy to persistent vector */
4292 game
.server
.ruledit
.nc_astyles
4293 = fc_malloc(game
.server
.ruledit
.as_count
* sizeof(char *));
4294 game
.server
.ruledit
.allowed_styles
=
4295 (const char **)game
.server
.ruledit
.nc_astyles
;
4297 for (j
= 0; j
< game
.server
.ruledit
.as_count
; j
++) {
4298 game
.server
.ruledit
.allowed_styles
[j
] = fc_strdup(vec
[j
]);
4304 sval
= secfile_lookup_str_default(file
, NULL
,
4305 "compatibility.default_government");
4306 /* We deliberately don't check this against allowed_govs. It's only
4307 * specified once so not vulnerable to typos, and may usefully be set in
4308 * a specific ruleset to a gov not explicitly known by the nation set. */
4310 game
.default_government
= government_by_rule_name(sval
);
4311 if (game
.default_government
== NULL
) {
4312 ruleset_error(LOG_ERROR
,
4313 "Tried to set unknown government type \"%s\" as default_government!",
4317 game
.info
.default_government_id
4318 = government_number(game
.default_government
);
4324 sec
= secfile_sections_by_name_prefix(file
, NATION_SET_SECTION_PREFIX
);
4326 section_list_iterate(sec
, psection
) {
4327 const char *set_name
, *set_rule_name
, *set_description
;
4329 set_name
= secfile_lookup_str(file
, "%s.name", section_name(psection
));
4331 secfile_lookup_str(file
, "%s.rule_name", section_name(psection
));
4332 set_description
= secfile_lookup_str_default(file
, "", "%s.description",
4333 section_name(psection
));
4334 if (NULL
== set_name
|| NULL
== set_rule_name
) {
4335 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
4339 if (nation_set_new(set_name
, set_rule_name
, set_description
) == NULL
) {
4343 } section_list_iterate_end
;
4344 section_list_destroy(sec
);
4347 ruleset_error(LOG_ERROR
,
4348 "At least one nation set [" NATION_SET_SECTION_PREFIX
"_*] "
4349 "must be defined.");
4355 /* Default set that every nation is a member of. */
4356 sval
= secfile_lookup_str_default(file
, NULL
,
4357 "compatibility.default_nationset");
4359 const struct nation_set
*pset
= nation_set_by_rule_name(sval
);
4361 default_set
= nation_set_number(pset
);
4363 ruleset_error(LOG_ERROR
,
4364 "Unknown default_nationset \"%s\".", sval
);
4367 } else if (nation_set_count() == 1) {
4368 /* If there's only one set defined, every nation is implicitly a
4369 * member of that set. */
4372 /* No default nation set; every nation must explicitly specify at
4373 * least one set to be a member of. */
4379 sec
= secfile_sections_by_name_prefix(file
, NATION_GROUP_SECTION_PREFIX
);
4381 section_list_iterate(sec
, psection
) {
4382 struct nation_group
*pgroup
;
4385 name
= secfile_lookup_str(file
, "%s.name", section_name(psection
));
4386 pgroup
= nation_group_by_rule_name(name
);
4387 if (pgroup
== NULL
) {
4392 hidden
= secfile_lookup_bool_default(file
, FALSE
, "%s.hidden",
4393 section_name(psection
));
4394 nation_group_set_hidden(pgroup
, hidden
);
4396 if (!secfile_lookup_int(file
, &j
, "%s.match", section_name(psection
))) {
4397 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
4401 nation_group_set_match(pgroup
, j
);
4402 } section_list_iterate_end
;
4403 section_list_destroy(sec
);
4409 sec
= secfile_sections_by_name_prefix(file
, NATION_SECTION_PREFIX
);
4410 nations_iterate(pnation
) {
4411 struct nation_type
*pconflict
;
4412 const int i
= nation_index(pnation
);
4413 char tmp
[200] = "\0";
4414 const char *barb_type
;
4415 const char *sec_name
= section_name(section_list_get(sec
, i
));
4418 /* Nation sets and groups. */
4419 if (default_set
>= 0) {
4420 nation_set_list_append(pnation
->sets
,
4421 nation_set_by_number(default_set
));
4423 vec
= secfile_lookup_str_vec(file
, &dim
, "%s.groups", sec_name
);
4424 for (j
= 0; j
< dim
; j
++) {
4425 struct nation_set
*pset
= nation_set_by_rule_name(vec
[j
]);
4426 struct nation_group
*pgroup
= nation_group_by_rule_name(vec
[j
]);
4428 fc_assert(pset
== NULL
|| pgroup
== NULL
);
4431 nation_set_list_append(pnation
->sets
, pset
);
4432 } else if (NULL
!= pgroup
) {
4433 nation_group_list_append(pnation
->groups
, pgroup
);
4435 /* For nation authors, this would probably be considered an error.
4436 * But it can happen normally. The civ1 compatibility ruleset only
4437 * uses the nations that were in civ1, so not all of the links will
4439 log_verbose("Nation %s: Unknown set/group \"%s\".",
4440 nation_rule_name(pnation
), vec
[j
]);
4446 if (nation_set_list_size(pnation
->sets
) < 1) {
4447 ruleset_error(LOG_ERROR
,
4448 "Nation %s is not a member of any nation set",
4449 nation_rule_name(pnation
));
4454 /* Nation conflicts. */
4455 vec
= secfile_lookup_str_vec(file
, &dim
, "%s.conflicts_with", sec_name
);
4456 for (j
= 0; j
< dim
; j
++) {
4457 pconflict
= nation_by_rule_name(vec
[j
]);
4459 if (pnation
== pconflict
) {
4460 ruleset_error(LOG_ERROR
, "Nation %s conflicts with itself",
4461 nation_rule_name(pnation
));
4464 } else if (NULL
!= pconflict
) {
4465 nation_list_append(pnation
->server
.conflicts_with
, pconflict
);
4467 /* For nation authors, this would probably be considered an error.
4468 * But it can happen normally. The civ1 compatibility ruleset only
4469 * uses the nations that were in civ1, so not all of the links will
4471 log_verbose("Nation %s: conflicts_with nation \"%s\" is unknown.",
4472 nation_rule_name(pnation
), vec
[j
]);
4482 /* Nation leaders. */
4483 for (j
= 0; j
< MAX_NUM_LEADERS
; j
++) {
4485 bool is_male
= FALSE
;
4487 name
= secfile_lookup_str(file
, "%s.leaders%d.name", sec_name
, j
);
4489 /* No more to read. */
4493 if (check_name(name
)) {
4494 /* The ruleset contains a name that is too long. This shouldn't
4495 * happen - if it does, the author should get immediate feedback */
4496 sz_strlcpy(temp_name
, name
);
4497 ruleset_error(LOG_ERROR
, "Nation %s: leader name \"%s\" "
4499 nation_rule_name(pnation
), name
);
4504 sex
= secfile_lookup_str(file
, "%s.leaders%d.sex", sec_name
, j
);
4506 ruleset_error(LOG_ERROR
, "Nation %s: leader \"%s\": %s.",
4507 nation_rule_name(pnation
), name
, secfile_error());
4510 } else if (0 == fc_strcasecmp("Male", sex
)) {
4512 } else if (0 != fc_strcasecmp("Female", sex
)) {
4513 ruleset_error(LOG_ERROR
, "Nation %s: leader \"%s\" has unsupported "
4514 "sex variant \"%s\".",
4515 nation_rule_name(pnation
), name
, sex
);
4519 (void) nation_leader_new(pnation
, name
, is_male
);
4525 /* Check the number of leaders. */
4526 if (MAX_NUM_LEADERS
== j
) {
4527 /* Too much leaders, get the real number defined in the ruleset. */
4528 while (NULL
!= secfile_entry_lookup(file
, "%s.leaders%d.name",
4532 ruleset_error(LOG_ERROR
, "Nation %s: Too many leaders; max is %d",
4533 nation_rule_name(pnation
), MAX_NUM_LEADERS
);
4536 } else if (0 == j
) {
4537 ruleset_error(LOG_ERROR
,
4538 "Nation %s: no leaders; at least one is required.",
4539 nation_rule_name(pnation
));
4544 /* Check if leader name is not already defined in this nation. */
4545 if ((bad_leader
= check_leader_names(pnation
))) {
4546 ruleset_error(LOG_ERROR
,
4547 "Nation %s: leader \"%s\" defined more than once.",
4548 nation_rule_name(pnation
), bad_leader
);
4553 /* Nation player color preference, if any */
4554 fc_assert_ret_val(pnation
->server
.rgb
== NULL
, FALSE
);
4555 (void) rgbcolor_load(file
, &pnation
->server
.rgb
, "%s.color", sec_name
);
4557 /* Load nation traits */
4558 ruleset_load_traits(pnation
->server
.traits
, file
, sec_name
, "trait_");
4559 for (tr
= trait_begin(); tr
!= trait_end(); tr
= trait_next(tr
)) {
4560 bool server_traits_used
= TRUE
;
4562 if (pnation
->server
.traits
[tr
].min
< 0) {
4563 pnation
->server
.traits
[tr
].min
= game
.server
.default_traits
[tr
].min
;
4565 server_traits_used
= FALSE
;
4567 if (pnation
->server
.traits
[tr
].max
< 0) {
4568 pnation
->server
.traits
[tr
].max
= game
.server
.default_traits
[tr
].max
;
4570 server_traits_used
= FALSE
;
4572 if (pnation
->server
.traits
[tr
].fixed
< 0) {
4573 if (server_traits_used
) {
4574 pnation
->server
.traits
[tr
].fixed
= game
.server
.default_traits
[tr
].fixed
;
4576 int diff
= pnation
->server
.traits
[tr
].max
- pnation
->server
.traits
[tr
].min
;
4578 /* TODO: Should sometimes round the a / 2 = x.5 results up */
4579 pnation
->server
.traits
[tr
].fixed
= diff
/ 2 + pnation
->server
.traits
[tr
].min
;
4582 if (pnation
->server
.traits
[tr
].max
< pnation
->server
.traits
[tr
].min
) {
4583 ruleset_error(LOG_ERROR
, "%s values for trait %s not sane.",
4584 nation_rule_name(pnation
), trait_name(tr
));
4594 pnation
->is_playable
=
4595 secfile_lookup_bool_default(file
, TRUE
, "%s.is_playable", sec_name
);
4597 /* Check barbarian type. Default is "None" meaning not a barbarian */
4598 barb_type
= secfile_lookup_str_default(file
, "None",
4599 "%s.barbarian_type", sec_name
);
4600 pnation
->barb_type
= barbarian_type_by_name(barb_type
, fc_strcasecmp
);
4601 if (!barbarian_type_is_valid(pnation
->barb_type
)) {
4602 ruleset_error(LOG_ERROR
,
4603 "Nation %s, barbarian_type is invalid (\"%s\")",
4604 nation_rule_name(pnation
), barb_type
);
4609 if (pnation
->barb_type
!= NOT_A_BARBARIAN
4610 && pnation
->is_playable
) {
4611 /* We can't allow players to use barbarian nations, barbarians
4612 * may run out of nations */
4613 ruleset_error(LOG_ERROR
,
4614 "Nation %s marked both barbarian and playable.",
4615 nation_rule_name(pnation
));
4621 sz_strlcpy(pnation
->flag_graphic_str
,
4622 secfile_lookup_str_default(file
, "-", "%s.flag", sec_name
));
4623 sz_strlcpy(pnation
->flag_graphic_alt
,
4624 secfile_lookup_str_default(file
, "-",
4625 "%s.flag_alt", sec_name
));
4629 const char *male
, *female
;
4631 name
= secfile_lookup_str_default(file
, NULL
,
4632 "%s.ruler_titles%d.government",
4635 /* End of the list of ruler titles. */
4639 /* NB: even if the government doesn't exist, we load the entries for
4640 * the ruler titles to avoid warnings about unused entries. */
4641 male
= secfile_lookup_str(file
, "%s.ruler_titles%d.male_title",
4643 female
= secfile_lookup_str(file
, "%s.ruler_titles%d.female_title",
4645 gov
= government_by_rule_name(name
);
4647 /* Nationset may have been devised with a specific set of govs in
4648 * mind which don't quite match this ruleset, in which case we
4649 * (a) quietly ignore any govs mentioned that don't happen to be in
4650 * the current ruleset, (b) enforce that govs mentioned by nations
4651 * must be on the list */
4652 if (gov
!= NULL
&& game
.server
.ruledit
.allowed_govs
!= NULL
) {
4653 if (!is_on_allowed_list(name
,
4654 game
.server
.ruledit
.allowed_govs
,
4655 game
.server
.ruledit
.ag_count
)) {
4656 /* Gov exists, but not intended for these nations */
4658 ruleset_error(LOG_ERROR
,
4659 "Nation %s: government \"%s\" not in allowed_govs.",
4660 nation_rule_name(pnation
), name
);
4665 /* Gov doesn't exist; only complain if it's not on any list */
4666 if (game
.server
.ruledit
.allowed_govs
== NULL
4667 || !is_on_allowed_list(name
,
4668 game
.server
.ruledit
.allowed_govs
,
4669 game
.server
.ruledit
.ag_count
)) {
4670 ruleset_error(LOG_ERROR
, "Nation %s: government \"%s\" not found.",
4671 nation_rule_name(pnation
), name
);
4676 if (NULL
!= male
&& NULL
!= female
) {
4678 (void) government_ruler_title_new(gov
, pnation
, male
, female
);
4681 ruleset_error(LOG_ERROR
, "%s", secfile_error());
4691 name
= secfile_lookup_str(file
, "%s.style", sec_name
);
4693 ruleset_error(LOG_ERROR
, "%s", secfile_error());
4697 pnation
->style
= style_by_rule_name(name
);
4698 if (pnation
->style
== NULL
) {
4699 if (game
.server
.ruledit
.allowed_styles
== NULL
4700 || !is_on_allowed_list(name
,
4701 game
.server
.ruledit
.allowed_styles
,
4702 game
.server
.ruledit
.as_count
)) {
4703 ruleset_error(LOG_ERROR
, "Nation %s: Illegal style \"%s\"",
4704 nation_rule_name(pnation
), name
);
4708 log_verbose("Nation %s: style \"%s\" not supported in this "
4709 "ruleset; using default.",
4710 nation_rule_name(pnation
), name
);
4711 pnation
->style
= style_by_number(0);
4715 /* Civilwar nations */
4716 vec
= secfile_lookup_str_vec(file
, &dim
,
4717 "%s.civilwar_nations", sec_name
);
4718 for (j
= 0; j
< dim
; j
++) {
4719 pconflict
= nation_by_rule_name(vec
[j
]);
4721 /* No test for duplicate nations is performed. If there is a duplicate
4722 * entry it will just cause that nation to have an increased
4723 * probability of being chosen. */
4724 if (pconflict
== pnation
) {
4725 ruleset_error(LOG_ERROR
, "Nation %s is its own civil war nation",
4726 nation_rule_name(pnation
));
4729 } else if (NULL
!= pconflict
) {
4730 nation_list_append(pnation
->server
.civilwar_nations
, pconflict
);
4731 nation_list_append(pconflict
->server
.parent_nations
, pnation
);
4733 /* For nation authors, this would probably be considered an error.
4734 * But it can happen normally. The civ1 compatability ruleset only
4735 * uses the nations that were in civ1, so not all of the links will
4737 log_verbose("Nation %s: civil war nation \"%s\" is unknown.",
4738 nation_rule_name(pnation
), vec
[j
]);
4748 /* Load nation specific initial items */
4749 if (!lookup_tech_list(file
, sec_name
, "init_techs",
4750 pnation
->init_techs
, filename
)) {
4754 if (!lookup_building_list(file
, sec_name
, "init_buildings",
4755 pnation
->init_buildings
, filename
)) {
4759 if (!lookup_unit_list(file
, sec_name
, "init_units",
4760 pnation
->init_units
, filename
)) {
4764 fc_strlcat(tmp
, sec_name
, 200);
4765 fc_strlcat(tmp
, ".init_government", 200);
4766 if (secfile_entry_by_path(file
, tmp
)) {
4767 pnation
->init_government
= lookup_government(file
, tmp
, filename
,
4769 /* If specified, init_government has to be in this specific ruleset,
4770 * not just allowed_govs */
4771 if (pnation
->init_government
== NULL
) {
4775 /* ...but if a list of govs has been specified, enforce that this
4776 * nation's init_government is on the list. */
4777 if (game
.server
.ruledit
.allowed_govs
!= NULL
4778 && !is_on_allowed_list(government_rule_name(pnation
->init_government
),
4779 game
.server
.ruledit
.allowed_govs
,
4780 game
.server
.ruledit
.ag_count
)) {
4781 ruleset_error(LOG_ERROR
,
4782 "Nation %s: init_government \"%s\" not allowed.",
4783 nation_rule_name(pnation
),
4784 government_rule_name(pnation
->init_government
));
4790 /* Read default city names. */
4791 if (!load_city_name_list(file
, pnation
, sec_name
, "cities",
4792 game
.server
.ruledit
.allowed_terrains
,
4793 game
.server
.ruledit
.at_count
)) {
4798 legend
= secfile_lookup_str_default(file
, "", "%s.legend", sec_name
);
4799 pnation
->legend
= fc_strdup(legend
);
4800 if (check_strlen(pnation
->legend
, MAX_LEN_MSG
, NULL
)) {
4801 ruleset_error(LOG_ERROR
,
4802 "Nation %s: legend \"%s\" is too long.",
4803 nation_rule_name(pnation
),
4809 pnation
->player
= NULL
;
4810 } nations_iterate_end
;
4811 section_list_destroy(sec
);
4815 /* Clean up on aborted load */
4818 section_list_destroy(sec
);
4822 secfile_check_unused(file
);
4826 /* Update cached number of playable nations in the current set */
4827 count_playable_nations();
4829 /* Sanity checks on all sets */
4830 nation_sets_iterate(pset
) {
4831 int num_playable
= 0, barb_land_count
= 0, barb_sea_count
= 0, barb_both_count
= 0;
4833 nations_iterate(pnation
) {
4834 if (nation_is_in_set(pnation
, pset
)) {
4835 switch (nation_barbarian_type(pnation
)) {
4836 case NOT_A_BARBARIAN
:
4837 if (is_nation_playable(pnation
)) {
4841 case LAND_BARBARIAN
:
4847 case ANIMAL_BARBARIAN
:
4848 /* Animals are optional */
4850 case LAND_AND_SEA_BARBARIAN
:
4854 fc_assert_ret_val(FALSE
, FALSE
);
4857 } nations_iterate_end
;
4858 if (num_playable
< 1) {
4859 ruleset_error(LOG_ERROR
,
4860 "Nation set \"%s\" has no playable nations. "
4861 "At least one required!", nation_set_rule_name(pset
));
4865 if (barb_land_count
== 0 && barb_both_count
== 0) {
4866 ruleset_error(LOG_ERROR
,
4867 "No land barbarian nation defined in set \"%s\". "
4868 "At least one required!", nation_set_rule_name(pset
));
4872 if (barb_sea_count
== 0 && barb_both_count
== 0) {
4873 ruleset_error(LOG_ERROR
,
4874 "No sea barbarian nation defined in set \"%s\". "
4875 "At least one required!", nation_set_rule_name(pset
));
4879 } nation_sets_iterate_end
;
4885 /**************************************************************************
4886 Load names of nation styles so other rulesets can refer to styles with
4888 **************************************************************************/
4889 static bool load_style_names(struct section_file
*file
,
4890 struct rscompat_info
*compat
)
4893 struct section_list
*sec
;
4894 const char *filename
= secfile_name(file
);
4896 compat
->ver_styles
= rscompat_check_capabilities(file
, filename
, compat
);
4897 if (compat
->ver_styles
<= 0) {
4901 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
4902 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
4904 sec
= secfile_sections_by_name_prefix(file
, STYLE_SECTION_PREFIX
);
4906 ruleset_error(LOG_ERROR
, "No available nation styles in this ruleset!");
4909 game
.control
.num_styles
= section_list_size(sec
);
4911 styles_alloc(game
.control
.num_styles
);
4913 styles_iterate(ps
) {
4914 const int i
= style_index(ps
);
4915 const char *sec_name
= section_name(section_list_get(sec
, i
));
4917 ruleset_load_names(&ps
->name
, NULL
, file
, sec_name
);
4918 } styles_iterate_end
;
4921 section_list_destroy(sec
);
4924 /* The citystyle sections: */
4927 sec
= secfile_sections_by_name_prefix(file
, CITYSTYLE_SECTION_PREFIX
);
4929 city_styles_alloc(section_list_size(sec
));
4930 section_list_iterate(sec
, style
) {
4931 if (!ruleset_load_names(&city_styles
[i
].name
, NULL
, file
, section_name(style
))) {
4936 } section_list_iterate_end
;
4938 section_list_destroy(sec
);
4940 city_styles_alloc(0);
4947 /**************************************************************************
4948 Load styles.ruleset file
4949 **************************************************************************/
4950 static bool load_ruleset_styles(struct section_file
*file
,
4951 struct rscompat_info
*compat
)
4953 struct section_list
*sec
;
4957 /* City Styles ... */
4959 sec
= secfile_sections_by_name_prefix(file
, CITYSTYLE_SECTION_PREFIX
);
4962 for (i
= 0; i
< game
.control
.styles_count
; i
++) {
4963 struct requirement_vector
*reqs
;
4964 const char *sec_name
= section_name(section_list_get(sec
, i
));
4966 sz_strlcpy(city_styles
[i
].graphic
,
4967 secfile_lookup_str(file
, "%s.graphic", sec_name
));
4968 sz_strlcpy(city_styles
[i
].graphic_alt
,
4969 secfile_lookup_str(file
, "%s.graphic_alt", sec_name
));
4970 sz_strlcpy(city_styles
[i
].citizens_graphic
,
4971 secfile_lookup_str_default(file
, "-",
4972 "%s.citizens_graphic", sec_name
));
4973 sz_strlcpy(city_styles
[i
].citizens_graphic_alt
,
4974 secfile_lookup_str_default(file
, "generic",
4975 "%s.citizens_graphic_alt", sec_name
));
4977 reqs
= lookup_req_list(file
, compat
, sec_name
, "reqs", city_style_rule_name(i
));
4982 requirement_vector_copy(&city_styles
[i
].reqs
, reqs
);
4985 section_list_destroy(sec
);
4988 sec
= secfile_sections_by_name_prefix(file
, MUSICSTYLE_SECTION_PREFIX
);
4993 game
.control
.num_music_styles
= section_list_size(sec
);
4994 music_styles_alloc(game
.control
.num_music_styles
);
4997 section_list_iterate(sec
, psection
) {
4998 struct requirement_vector
*reqs
;
4999 struct music_style
*pmus
= music_style_by_number(musi
);
5000 const char *sec_name
= section_name(psection
);
5002 sz_strlcpy(pmus
->music_peaceful
,
5003 secfile_lookup_str_default(file
, "-",
5004 "%s.music_peaceful", sec_name
));
5005 sz_strlcpy(pmus
->music_combat
,
5006 secfile_lookup_str_default(file
, "-",
5007 "%s.music_combat", sec_name
));
5009 reqs
= lookup_req_list(file
, compat
, sec_name
, "reqs", "Music Style");
5014 requirement_vector_copy(&pmus
->reqs
, reqs
);
5017 } section_list_iterate_end
;
5020 section_list_destroy(sec
);
5026 /**************************************************************************
5027 Load a list of unit type flags that must be absent from the actor unit
5028 if an action auto performer should be triggered into an action auto
5030 **************************************************************************/
5031 static bool load_action_auto_uflag_block(struct section_file
*file
,
5032 struct action_auto_perf
*auto_perf
,
5033 const char *uflags_path
,
5034 const char *filename
)
5036 /* Add each listed protected unit type flag as a !present
5038 if (secfile_entry_lookup(file
, "%s", uflags_path
)) {
5039 enum unit_type_flag_id
*protecor_flag
;
5044 secfile_lookup_enum_vec(file
, &psize
, unit_type_flag_id
,
5047 if (!protecor_flag
) {
5048 /* Entity exists but couldn't read it. */
5049 ruleset_error(LOG_ERROR
,
5050 "\"%s\": %s: bad unit type flag list.",
5051 filename
, uflags_path
);
5056 for (i
= 0; i
< psize
; i
++) {
5057 requirement_vector_append(&auto_perf
->reqs
,
5058 req_from_values(VUT_UTFLAG
,
5064 free(protecor_flag
);
5070 /**************************************************************************
5071 Load the list of actions an action auto performer should try. The
5072 actions will be tried in the given order.
5073 **************************************************************************/
5074 static bool load_action_auto_actions(struct section_file
*file
,
5075 struct action_auto_perf
*auto_perf
,
5076 const char *actions_path
,
5077 const char *filename
)
5079 /* Read the alternative actions. */
5080 if (secfile_entry_lookup(file
, "%s", actions_path
)) {
5081 enum gen_action
*unit_acts
;
5085 unit_acts
= secfile_lookup_enum_vec(file
, &asize
, gen_action
,
5086 "%s", actions_path
);
5089 /* Entity exists but couldn't read it. */
5090 ruleset_error(LOG_ERROR
,
5091 "\"%s\": %s: bad action list",
5092 filename
, actions_path
);
5097 for (i
= 0; i
< asize
; i
++) {
5098 auto_perf
->alternatives
[i
] = unit_acts
[i
];
5107 /**************************************************************************
5108 Load missing unit upkeep ruleset settings as action auto performers.
5109 **************************************************************************/
5110 static bool load_muuk_as_action_auto(struct section_file
*file
,
5111 struct action_auto_perf
*auto_perf
,
5113 const char *filename
)
5115 char uflags_path
[100];
5116 char action_path
[100];
5118 fc_snprintf(uflags_path
, sizeof(uflags_path
),
5119 "missing_unit_upkeep.%s_protected", item
);
5120 fc_snprintf(action_path
, sizeof(action_path
),
5121 "missing_unit_upkeep.%s_unit_act", item
);
5123 return (load_action_auto_uflag_block(file
, auto_perf
, uflags_path
,
5125 && load_action_auto_actions(file
, auto_perf
, action_path
,
5129 /**************************************************************************
5130 Load cities.ruleset file
5131 **************************************************************************/
5132 static bool load_ruleset_cities(struct section_file
*file
,
5133 struct rscompat_info
*compat
)
5135 const char *filename
= secfile_name(file
);
5137 struct section_list
*sec
;
5140 compat
->ver_cities
= rscompat_check_capabilities(file
, filename
, compat
);
5141 if (compat
->ver_cities
<= 0) {
5145 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
5146 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
5148 /* Specialist options */
5149 sec
= secfile_sections_by_name_prefix(file
, SPECIALIST_SECTION_PREFIX
);
5150 if (section_list_size(sec
) >= SP_MAX
) {
5151 ruleset_error(LOG_ERROR
, "\"%s\": Too many specialists (%d, max %d).",
5152 filename
, section_list_size(sec
), SP_MAX
);
5159 game
.control
.num_specialist_types
= section_list_size(sec
);
5161 section_list_iterate(sec
, psection
) {
5162 struct specialist
*s
= specialist_by_number(i
);
5163 struct requirement_vector
*reqs
;
5164 const char *sec_name
= section_name(psection
);
5166 if (!ruleset_load_names(&s
->name
, NULL
, file
, sec_name
)) {
5171 item
= secfile_lookup_str_default(file
, untranslated_name(&s
->name
),
5172 "%s.short_name", sec_name
);
5173 name_set(&s
->abbreviation
, NULL
, item
);
5175 sz_strlcpy(s
->graphic_alt
,
5176 secfile_lookup_str_default(file
, "-",
5177 "%s.graphic_alt", sec_name
));
5179 reqs
= lookup_req_list(file
, compat
, sec_name
, "reqs", specialist_rule_name(s
));
5184 requirement_vector_copy(&s
->reqs
, reqs
);
5186 s
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
5188 if (requirement_vector_size(&s
->reqs
) == 0 && DEFAULT_SPECIALIST
== -1) {
5189 DEFAULT_SPECIALIST
= i
;
5192 } section_list_iterate_end
;
5195 if (ok
&& DEFAULT_SPECIALIST
== -1) {
5196 ruleset_error(LOG_ERROR
,
5197 "\"%s\": must give a min_size of 0 for at least one "
5198 "specialist type.", filename
);
5201 section_list_destroy(sec
);
5205 /* City Parameters */
5207 game
.info
.celebratesize
=
5208 secfile_lookup_int_default(file
, GAME_DEFAULT_CELEBRATESIZE
,
5209 "parameters.celebrate_size_limit");
5210 game
.info
.add_to_size_limit
=
5211 secfile_lookup_int_default(file
, GAME_DEFAULT_ADDTOSIZE
, "parameters.add_to_size_limit");
5212 game
.info
.angrycitizen
=
5213 secfile_lookup_bool_default(file
, GAME_DEFAULT_ANGRYCITIZEN
,
5214 "parameters.angry_citizens");
5216 game
.info
.changable_tax
=
5217 secfile_lookup_bool_default(file
, GAME_DEFAULT_CHANGABLE_TAX
, "parameters.changable_tax");
5218 game
.info
.forced_science
=
5219 secfile_lookup_int_default(file
, 0, "parameters.forced_science");
5220 game
.info
.forced_luxury
=
5221 secfile_lookup_int_default(file
, 100, "parameters.forced_luxury");
5222 game
.info
.forced_gold
=
5223 secfile_lookup_int_default(file
, 0, "parameters.forced_gold");
5224 if (game
.info
.forced_science
+ game
.info
.forced_luxury
5225 + game
.info
.forced_gold
!= 100) {
5226 ruleset_error(LOG_ERROR
,
5227 "\"%s\": Forced taxes do not add up in ruleset!",
5234 /* civ1 & 2 didn't reveal tiles */
5235 game
.server
.vision_reveal_tiles
=
5236 secfile_lookup_bool_default(file
, GAME_DEFAULT_VISION_REVEAL_TILES
,
5237 "parameters.vision_reveal_tiles");
5239 game
.info
.pop_report_zeroes
=
5240 secfile_lookup_int_default(file
, 1, "parameters.pop_report_zeroes");
5242 /* Citizens configuration. */
5243 game
.info
.citizen_nationality
=
5244 secfile_lookup_bool_default(file
, GAME_DEFAULT_NATIONALITY
,
5245 "citizen.nationality");
5246 game
.info
.citizen_convert_speed
=
5247 secfile_lookup_int_default(file
, GAME_DEFAULT_CONVERT_SPEED
,
5248 "citizen.convert_speed");
5249 game
.info
.citizen_partisans_pct
=
5250 secfile_lookup_int_default(file
, 0, "citizen.partisans_pct");
5254 /* Missing unit upkeep. */
5255 struct action_auto_perf
*auto_perf
;
5257 /* Can't pay food upkeep! */
5258 auto_perf
= action_auto_perf_slot_number(ACTION_AUTO_UPKEEP_FOOD
);
5259 auto_perf
->cause
= AAPC_UNIT_UPKEEP
;
5261 /* This is about food upkeep. */
5262 requirement_vector_append(&auto_perf
->reqs
,
5263 req_from_str("OutputType", "Local",
5267 /* Internally represented as an action auto performer rule. */
5268 if (!load_muuk_as_action_auto(file
, auto_perf
, "food", filename
)) {
5272 game
.info
.muuk_food_wipe
=
5273 secfile_lookup_bool_default(file
, RS_DEFAULT_MUUK_FOOD_WIPE
,
5274 "missing_unit_upkeep.food_wipe");
5276 /* Can't pay gold upkeep! */
5277 auto_perf
= action_auto_perf_slot_number(ACTION_AUTO_UPKEEP_GOLD
);
5278 auto_perf
->cause
= AAPC_UNIT_UPKEEP
;
5280 /* This is about gold upkeep. */
5281 requirement_vector_append(&auto_perf
->reqs
,
5282 req_from_str("OutputType", "Local",
5286 /* Internally represented as an action auto performer rule. */
5287 if (!load_muuk_as_action_auto(file
, auto_perf
, "gold", filename
)) {
5291 game
.info
.muuk_gold_wipe
=
5292 secfile_lookup_bool_default(file
, RS_DEFAULT_MUUK_GOLD_WIPE
,
5293 "missing_unit_upkeep.gold_wipe");
5295 /* Can't pay shield upkeep! */
5296 auto_perf
= action_auto_perf_slot_number(ACTION_AUTO_UPKEEP_SHIELD
);
5297 auto_perf
->cause
= AAPC_UNIT_UPKEEP
;
5299 /* This is about shield 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
, "shield", filename
)) {
5310 game
.info
.muuk_shield_wipe
=
5311 secfile_lookup_bool_default(file
, RS_DEFAULT_MUUK_SHIELD_WIPE
,
5312 "missing_unit_upkeep.shield_wipe");
5316 secfile_check_unused(file
);
5322 /**************************************************************************
5323 Load effects.ruleset file
5324 **************************************************************************/
5325 static bool load_ruleset_effects(struct section_file
*file
,
5326 struct rscompat_info
*compat
)
5328 struct section_list
*sec
;
5330 const char *filename
;
5332 bool effect_type_warned
= FALSE
;
5334 filename
= secfile_name(file
);
5336 compat
->ver_effects
= rscompat_check_capabilities(file
, filename
, compat
);
5337 if (compat
->ver_effects
<= 0) {
5340 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
5341 (void) secfile_entry_by_path(file
, "datafile.ruledit"); /* unused */
5343 /* Parse effects and add them to the effects ruleset cache. */
5344 sec
= secfile_sections_by_name_prefix(file
, EFFECT_SECTION_PREFIX
);
5345 section_list_iterate(sec
, psection
) {
5346 enum effect_type eff
;
5348 struct multiplier
*pmul
;
5349 struct effect
*peffect
;
5350 const char *sec_name
= section_name(psection
);
5351 struct requirement_vector
*reqs
;
5353 type
= secfile_lookup_str(file
, "%s.type", sec_name
);
5354 if (type
== NULL
&& compat
->compat_mode
) {
5355 /* Backward compatibility. Field used to be named "name" */
5356 type
= secfile_lookup_str(file
, "%s.name", sec_name
);
5357 if (type
!= NULL
&& !effect_type_warned
) {
5358 log_deprecation(_("Effects should have \"type\", not the same field with old name \"name\"."));
5359 effect_type_warned
= TRUE
;
5363 ruleset_error(LOG_ERROR
, "\"%s\" [%s] missing effect type.", filename
, sec_name
);
5368 eff
= effect_type_by_name(type
, fc_strcasecmp
);
5369 if (!effect_type_is_valid(eff
)) {
5370 ruleset_error(LOG_ERROR
, "\"%s\" [%s] lists unknown effect type \"%s\".",
5371 filename
, sec_name
, type
);
5376 value
= secfile_lookup_int_default(file
, 1, "%s.value", sec_name
);
5379 const char *multiplier_name
5380 = secfile_lookup_str(file
, "%s.multiplier", sec_name
);
5382 if (multiplier_name
) {
5383 pmul
= multiplier_by_rule_name(multiplier_name
);
5385 ruleset_error(LOG_ERROR
, "\"%s\" [%s] has unknown multiplier \"%s\".",
5386 filename
, sec_name
, multiplier_name
);
5395 peffect
= effect_new(eff
, value
, pmul
);
5397 reqs
= lookup_req_list(file
, compat
, sec_name
, "reqs", type
);
5403 requirement_vector_iterate(reqs
, preq
) {
5404 effect_req_append(peffect
, *preq
);
5405 } requirement_vector_iterate_end
;
5407 if (compat
->compat_mode
) {
5408 reqs
= lookup_req_list(file
, compat
, sec_name
, "nreqs", type
);
5413 requirement_vector_iterate(reqs
, preq
) {
5414 preq
->present
= !preq
->present
;
5415 effect_req_append(peffect
, *preq
);
5416 } requirement_vector_iterate_end
;
5418 } section_list_iterate_end
;
5419 section_list_destroy(sec
);
5422 secfile_check_unused(file
);
5428 /**************************************************************************
5429 Print an error message if the value is out of range.
5430 **************************************************************************/
5431 static int secfile_lookup_int_default_min_max(struct section_file
*file
,
5432 int def
, int min
, int max
,
5433 const char *path
, ...)
5434 fc__attribute((__format__ (__printf__
, 5, 6)));
5435 static int secfile_lookup_int_default_min_max(struct section_file
*file
,
5436 int def
, int min
, int max
,
5437 const char *path
, ...)
5443 va_start(args
, path
);
5444 fc_vsnprintf(fullpath
, sizeof(fullpath
), path
, args
);
5447 if (!secfile_lookup_int(file
, &ival
, "%s", fullpath
)) {
5452 ruleset_error(LOG_ERROR
,"\"%s\" should be in the interval [%d, %d] "
5453 "but is %d; using the minimal value.",
5454 fullpath
, min
, max
, ival
);
5459 ruleset_error(LOG_ERROR
,"\"%s\" should be in the interval [%d, %d] "
5460 "but is %d; using the maximal value.",
5461 fullpath
, min
, max
, ival
);
5468 /**************************************************************************
5470 **************************************************************************/
5471 static bool load_ruleset_game(struct section_file
*file
, bool act
,
5472 struct rscompat_info
*compat
)
5474 const char *sval
, **svec
;
5475 const char *filename
;
5479 const char *pref_text
;
5481 struct section_list
*sec
;
5489 filename
= secfile_name(file
);
5491 name
= secfile_lookup_str_default(file
, NULL
, "ruledit.description_file");
5493 game
.server
.ruledit
.description_file
= fc_strdup(name
);
5496 /* section: tileset */
5497 pref_text
= secfile_lookup_str_default(file
, "", "tileset.prefered");
5498 if (pref_text
[0] != '\0') {
5499 log_deprecation("Entry tileset.prefered in game.ruleset."
5500 " Use correct spelling tileset.preferred instead");
5502 pref_text
= secfile_lookup_str_default(file
, pref_text
, "tileset.preferred");
5503 if (pref_text
[0] != '\0') {
5504 /* There was tileset suggestion */
5505 sz_strlcpy(game
.control
.preferred_tileset
, pref_text
);
5507 /* No tileset suggestions */
5508 game
.control
.preferred_tileset
[0] = '\0';
5511 /* section: soundset */
5512 pref_text
= secfile_lookup_str_default(file
, "", "soundset.prefered");
5513 if (pref_text
[0] != '\0') {
5514 log_deprecation("Entry soundset.prefered in game.ruleset."
5515 " Use correct spelling soundset.preferred instead");
5517 pref_text
= secfile_lookup_str_default(file
, pref_text
, "soundset.preferred");
5518 if (pref_text
[0] != '\0') {
5519 /* There was soundset suggestion */
5520 sz_strlcpy(game
.control
.preferred_soundset
, pref_text
);
5522 /* No soundset suggestions */
5523 game
.control
.preferred_soundset
[0] = '\0';
5526 /* section: musicset */
5527 pref_text
= secfile_lookup_str_default(file
, "", "musicset.prefered");
5528 if (pref_text
[0] != '\0') {
5529 log_deprecation("Entry musicset.prefered in game.ruleset."
5530 " Use correct spelling musicset.preferred instead");
5532 pref_text
= secfile_lookup_str_default(file
, pref_text
, "musicset.preferred");
5533 if (pref_text
[0] != '\0') {
5534 /* There was musicset suggestion */
5535 sz_strlcpy(game
.control
.preferred_musicset
, pref_text
);
5537 /* No musicset suggestions */
5538 game
.control
.preferred_musicset
[0] = '\0';
5541 /* section: about */
5542 pref_text
= secfile_lookup_str(file
, "about.name");
5543 /* Ruleset/modpack name found */
5544 sz_strlcpy(game
.control
.name
, pref_text
);
5546 pref_text
= secfile_lookup_str_default(file
, "", "about.version");
5547 if (pref_text
[0] != '\0') {
5548 /* Ruleset/modpack version found */
5549 sz_strlcpy(game
.control
.version
, pref_text
);
5551 /* No version information */
5552 game
.control
.version
[0] = '\0';
5555 pref_text
= secfile_lookup_str_default(file
, "", "about.summary");
5556 if (pref_text
[0] != '\0') {
5559 /* Ruleset/modpack summary found */
5560 len
= strlen(pref_text
);
5561 game
.ruleset_summary
= fc_malloc(len
+ 1);
5562 fc_strlcpy(game
.ruleset_summary
, pref_text
, len
+ 1);
5565 if (game
.ruleset_summary
!= NULL
) {
5566 free(game
.ruleset_summary
);
5567 game
.ruleset_summary
= NULL
;
5571 pref_text
= secfile_lookup_str_default(file
, "", "about.description");
5572 if (pref_text
[0] != '\0') {
5575 /* Ruleset/modpack description found */
5576 len
= strlen(pref_text
);
5577 game
.ruleset_description
= fc_malloc(len
+ 1);
5578 fc_strlcpy(game
.ruleset_description
, pref_text
, len
+ 1);
5579 game
.control
.desc_length
= len
;
5581 /* No description */
5582 if (game
.ruleset_description
!= NULL
) {
5583 free(game
.ruleset_description
);
5584 game
.ruleset_description
= NULL
;
5586 game
.control
.desc_length
= 0;
5589 /* section: options */
5590 if (!lookup_tech_list(file
, "options", "global_init_techs",
5591 game
.rgame
.global_init_techs
, filename
)) {
5596 if (!lookup_building_list(file
, "options", "global_init_buildings",
5597 game
.rgame
.global_init_buildings
, filename
)) {
5606 game
.control
.popup_tech_help
= secfile_lookup_bool_default(file
, FALSE
,
5607 "options.popup_tech_help");
5609 /* section: civstyle */
5610 game
.info
.base_pollution
5611 = secfile_lookup_int_default(file
, RS_DEFAULT_BASE_POLLUTION
,
5612 "civstyle.base_pollution");
5614 game
.info
.gameloss_style
= GAMELOSS_STYLE_CLASSICAL
;
5616 slist
= secfile_lookup_str_vec(file
, &nval
, "civstyle.gameloss_style");
5617 for (j
= 0; j
< nval
; j
++) {
5618 enum gameloss_style style
;
5621 if (strcmp(sval
, "") == 0) {
5624 style
= gameloss_style_by_name(sval
, fc_strcasecmp
);
5625 if (!gameloss_style_is_valid(style
)) {
5626 ruleset_error(LOG_ERROR
, "\"%s\": bad value \"%s\" for gameloss_style.",
5631 game
.info
.gameloss_style
|= style
;
5638 game
.info
.happy_cost
5639 = secfile_lookup_int_def_min_max(file
,
5640 RS_DEFAULT_HAPPY_COST
,
5643 "civstyle.happy_cost");
5645 = secfile_lookup_int_default_min_max(file
,
5646 RS_DEFAULT_FOOD_COST
,
5649 "civstyle.food_cost");
5650 game
.info
.civil_war_enabled
5651 = secfile_lookup_bool_default(file
, TRUE
, "civstyle.civil_war_enabled");
5653 game
.info
.paradrop_to_transport
5654 = secfile_lookup_bool_default(file
, FALSE
,
5655 "civstyle.paradrop_to_transport");
5657 /* TODO: move to global_unit_options */
5658 game
.info
.base_bribe_cost
5659 = secfile_lookup_int_default_min_max(file
,
5660 RS_DEFAULT_BASE_BRIBE_COST
,
5661 RS_MIN_BASE_BRIBE_COST
,
5662 RS_MAX_BASE_BRIBE_COST
,
5663 "civstyle.base_bribe_cost");
5664 /* TODO: move to global_unit_options */
5665 game
.server
.ransom_gold
5666 = secfile_lookup_int_default_min_max(file
,
5667 RS_DEFAULT_RANSOM_GOLD
,
5670 "civstyle.ransom_gold");
5671 /* TODO: move to global_unit_options */
5672 game
.info
.pillage_select
5673 = secfile_lookup_bool_default(file
, RS_DEFAULT_PILLAGE_SELECT
,
5674 "civstyle.pillage_select");
5676 game
.info
.tech_steal_allow_holes
5677 = secfile_lookup_bool_default(file
, RS_DEFAULT_TECH_STEAL_HOLES
,
5678 "civstyle.tech_steal_allow_holes");
5679 game
.info
.tech_trade_allow_holes
5680 = secfile_lookup_bool_default(file
, RS_DEFAULT_TECH_TRADE_HOLES
,
5681 "civstyle.tech_trade_allow_holes");
5682 game
.info
.tech_trade_loss_allow_holes
5683 = secfile_lookup_bool_default(file
, RS_DEFAULT_TECH_TRADE_LOSS_HOLES
,
5684 "civstyle.tech_trade_loss_allow_holes");
5685 game
.info
.tech_parasite_allow_holes
5686 = secfile_lookup_bool_default(file
, RS_DEFAULT_TECH_PARASITE_HOLES
,
5687 "civstyle.tech_parasite_allow_holes");
5688 game
.info
.tech_loss_allow_holes
5689 = secfile_lookup_bool_default(file
, RS_DEFAULT_TECH_LOSS_HOLES
,
5690 "civstyle.tech_loss_allow_holes");
5692 /* TODO: move to global_unit_options */
5693 game
.server
.upgrade_veteran_loss
5694 = secfile_lookup_int_default_min_max(file
,
5695 RS_DEFAULT_UPGRADE_VETERAN_LOSS
,
5696 RS_MIN_UPGRADE_VETERAN_LOSS
,
5697 RS_MAX_UPGRADE_VETERAN_LOSS
,
5698 "civstyle.upgrade_veteran_loss");
5699 /* TODO: move to global_unit_options */
5700 game
.server
.autoupgrade_veteran_loss
5701 = secfile_lookup_int_default_min_max(file
,
5702 RS_DEFAULT_UPGRADE_VETERAN_LOSS
,
5703 RS_MIN_UPGRADE_VETERAN_LOSS
,
5704 RS_MAX_UPGRADE_VETERAN_LOSS
,
5705 "civstyle.autoupgrade_veteran_loss");
5707 game
.info
.base_tech_cost
5708 = secfile_lookup_int_default_min_max(file
,
5709 RS_DEFAULT_BASE_TECH_COST
,
5710 RS_MIN_BASE_TECH_COST
,
5711 RS_MAX_BASE_TECH_COST
,
5712 "research.base_tech_cost");
5714 food_ini
= secfile_lookup_int_vec(file
, &gni_tmp
,
5715 "civstyle.granary_food_ini");
5716 game
.info
.granary_num_inis
= (int) gni_tmp
;
5718 if (game
.info
.granary_num_inis
> MAX_GRANARY_INIS
) {
5719 ruleset_error(LOG_ERROR
,
5720 "Too many granary_food_ini entries (%d, max %d)",
5721 game
.info
.granary_num_inis
, MAX_GRANARY_INIS
);
5723 } else if (game
.info
.granary_num_inis
== 0) {
5724 log_error("No values for granary_food_ini. Using default "
5725 "value %d.", RS_DEFAULT_GRANARY_FOOD_INI
);
5726 game
.info
.granary_num_inis
= 1;
5727 game
.info
.granary_food_ini
[0] = RS_DEFAULT_GRANARY_FOOD_INI
;
5731 /* check for <= 0 entries */
5732 for (gi
= 0; gi
< game
.info
.granary_num_inis
; gi
++) {
5733 if (food_ini
[gi
] <= 0) {
5735 food_ini
[gi
] = RS_DEFAULT_GRANARY_FOOD_INI
;
5737 food_ini
[gi
] = food_ini
[gi
- 1];
5739 log_error("Bad value for granary_food_ini[%i]. Using %i.",
5742 game
.info
.granary_food_ini
[gi
] = food_ini
[gi
];
5749 game
.info
.granary_food_inc
5750 = secfile_lookup_int_default_min_max(file
,
5751 RS_DEFAULT_GRANARY_FOOD_INC
,
5752 RS_MIN_GRANARY_FOOD_INC
,
5753 RS_MAX_GRANARY_FOOD_INC
,
5754 "civstyle.granary_food_inc");
5756 output_type_iterate(o
) {
5757 game
.info
.min_city_center_output
[o
]
5758 = secfile_lookup_int_default_min_max(file
,
5759 RS_DEFAULT_CITY_CENTER_OUTPUT
,
5760 RS_MIN_CITY_CENTER_OUTPUT
,
5761 RS_MAX_CITY_CENTER_OUTPUT
,
5762 "civstyle.min_city_center_%s",
5763 get_output_identifier(o
));
5764 } output_type_iterate_end
;
5768 const char *tus_text
;
5770 game
.server
.init_vis_radius_sq
5771 = secfile_lookup_int_default_min_max(file
,
5772 RS_DEFAULT_VIS_RADIUS_SQ
,
5773 RS_MIN_VIS_RADIUS_SQ
,
5774 RS_MAX_VIS_RADIUS_SQ
,
5775 "civstyle.init_vis_radius_sq");
5777 game
.info
.init_city_radius_sq
5778 = secfile_lookup_int_default_min_max(file
,
5779 RS_DEFAULT_CITY_RADIUS_SQ
,
5780 RS_MIN_CITY_RADIUS_SQ
,
5781 RS_MAX_CITY_RADIUS_SQ
,
5782 "civstyle.init_city_radius_sq");
5784 tus_text
= secfile_lookup_str_default(file
, RS_DEFAULT_GOLD_UPKEEP_STYLE
,
5785 "civstyle.gold_upkeep_style");
5786 game
.info
.gold_upkeep_style
= gold_upkeep_style_by_name(tus_text
,
5788 if (!gold_upkeep_style_is_valid(game
.info
.gold_upkeep_style
)) {
5789 ruleset_error(LOG_ERROR
, "Unknown gold upkeep style \"%s\"",
5794 /* section: illness */
5795 game
.info
.illness_on
5796 = secfile_lookup_bool_default(file
, RS_DEFAULT_ILLNESS_ON
,
5797 "illness.illness_on");
5798 game
.info
.illness_base_factor
5799 = secfile_lookup_int_default_min_max(file
,
5800 RS_DEFAULT_ILLNESS_BASE_FACTOR
,
5801 RS_MIN_ILLNESS_BASE_FACTOR
,
5802 RS_MAX_ILLNESS_BASE_FACTOR
,
5803 "illness.illness_base_factor");
5804 game
.info
.illness_min_size
5805 = secfile_lookup_int_default_min_max(file
,
5806 RS_DEFAULT_ILLNESS_MIN_SIZE
,
5807 RS_MIN_ILLNESS_MIN_SIZE
,
5808 RS_MAX_ILLNESS_MIN_SIZE
,
5809 "illness.illness_min_size");
5810 game
.info
.illness_trade_infection
5811 = secfile_lookup_int_default_min_max(file
,
5812 RS_DEFAULT_ILLNESS_TRADE_INFECTION_PCT
,
5813 RS_MIN_ILLNESS_TRADE_INFECTION_PCT
,
5814 RS_MAX_ILLNESS_TRADE_INFECTION_PCT
,
5815 "illness.illness_trade_infection");
5816 game
.info
.illness_pollution_factor
5817 = secfile_lookup_int_default_min_max(file
,
5818 RS_DEFAULT_ILLNESS_POLLUTION_PCT
,
5819 RS_MIN_ILLNESS_POLLUTION_PCT
,
5820 RS_MAX_ILLNESS_POLLUTION_PCT
,
5821 "illness.illness_pollution_factor");
5823 /* section: incite_cost */
5824 game
.server
.base_incite_cost
5825 = secfile_lookup_int_default_min_max(file
,
5826 RS_DEFAULT_INCITE_BASE_COST
,
5827 RS_MIN_INCITE_BASE_COST
,
5828 RS_MAX_INCITE_BASE_COST
,
5829 "incite_cost.base_incite_cost");
5830 game
.server
.incite_improvement_factor
5831 = secfile_lookup_int_default_min_max(file
,
5832 RS_DEFAULT_INCITE_IMPROVEMENT_FCT
,
5833 RS_MIN_INCITE_IMPROVEMENT_FCT
,
5834 RS_MAX_INCITE_IMPROVEMENT_FCT
,
5835 "incite_cost.improvement_factor");
5836 game
.server
.incite_unit_factor
5837 = secfile_lookup_int_default_min_max(file
,
5838 RS_DEFAULT_INCITE_UNIT_FCT
,
5839 RS_MIN_INCITE_UNIT_FCT
,
5840 RS_MAX_INCITE_UNIT_FCT
,
5841 "incite_cost.unit_factor");
5842 game
.server
.incite_total_factor
5843 = secfile_lookup_int_default_min_max(file
,
5844 RS_DEFAULT_INCITE_TOTAL_FCT
,
5845 RS_MIN_INCITE_TOTAL_FCT
,
5846 RS_MAX_INCITE_TOTAL_FCT
,
5847 "incite_cost.total_factor");
5849 /* section: global_unit_options */
5850 game
.info
.slow_invasions
5851 = secfile_lookup_bool_default(file
, RS_DEFAULT_SLOW_INVASIONS
,
5852 "global_unit_options.slow_invasions");
5856 struct action_auto_perf
*auto_perf
;
5858 /* A unit moved next to this unit and the autoattack server setting
5860 auto_perf
= action_auto_perf_slot_number(ACTION_AUTO_MOVED_ADJ
);
5861 auto_perf
->cause
= AAPC_UNIT_MOVED_ADJ
;
5863 /* Auto attack happens during war. */
5864 requirement_vector_append(&auto_perf
->reqs
,
5865 req_from_values(VUT_DIPLREL
,
5867 FALSE
, TRUE
, TRUE
, DS_WAR
));
5869 /* Needs a movement point to auto attack. */
5870 requirement_vector_append(&auto_perf
->reqs
,
5871 req_from_values(VUT_MINMOVES
,
5873 FALSE
, TRUE
, TRUE
, 1));
5875 /* Internally represented as an action auto performer rule. */
5876 if (!load_action_auto_uflag_block(file
, auto_perf
,
5877 "auto_attack.will_never",
5882 /* TODO: It would be great if unit_survive_autoattack() could be made
5883 * flexible enough to also handle diplomatic actions etc. */
5884 auto_perf
->alternatives
[0] = ACTION_CAPTURE_UNITS
;
5885 auto_perf
->alternatives
[1] = ACTION_BOMBARD
;
5886 auto_perf
->alternatives
[2] = ACTION_ATTACK
;
5889 /* section: actions */
5892 int force_capture_units
, force_bombard
, force_explode_nuclear
;
5894 if (secfile_lookup_bool_default(file
, RS_DEFAULT_FORCE_TRADE_ROUTE
,
5895 "actions.force_trade_route")) {
5896 /* Forbid entering the marketplace when a trade route can be
5898 BV_SET(action_by_number(ACTION_MARKETPLACE
)->blocked_by
,
5899 ACTION_TRADE_ROUTE
);
5902 /* Forbid bombarding, exploading nuclear or attacking when it is
5903 * legal to capture units. */
5905 = secfile_lookup_bool_default(file
, RS_DEFAULT_FORCE_CAPTURE_UNITS
,
5906 "actions.force_capture_units");
5908 if (force_capture_units
) {
5909 BV_SET(action_by_number(ACTION_BOMBARD
)->blocked_by
,
5910 ACTION_CAPTURE_UNITS
);
5911 BV_SET(action_by_number(ACTION_NUKE
)->blocked_by
,
5912 ACTION_CAPTURE_UNITS
);
5913 BV_SET(action_by_number(ACTION_ATTACK
)->blocked_by
,
5914 ACTION_CAPTURE_UNITS
);
5915 BV_SET(action_by_number(ACTION_CONQUER_CITY
)->blocked_by
,
5916 ACTION_CAPTURE_UNITS
);
5919 /* Forbid exploding nuclear or attacking when it is legal to
5922 = secfile_lookup_bool_default(file
, RS_DEFAULT_FORCE_BOMBARD
,
5923 "actions.force_bombard");
5925 if (force_bombard
) {
5926 BV_SET(action_by_number(ACTION_NUKE
)->blocked_by
,
5928 BV_SET(action_by_number(ACTION_ATTACK
)->blocked_by
,
5930 BV_SET(action_by_number(ACTION_CONQUER_CITY
)->blocked_by
,
5934 /* Forbid attacking when it is legal to do explode nuclear. */
5935 force_explode_nuclear
5936 = secfile_lookup_bool_default(file
,
5937 RS_DEFAULT_FORCE_EXPLODE_NUCLEAR
,
5938 "actions.force_explode_nuclear");
5940 if (force_explode_nuclear
) {
5941 BV_SET(action_by_number(ACTION_ATTACK
)->blocked_by
,
5943 BV_SET(action_by_number(ACTION_CONQUER_CITY
)->blocked_by
,
5947 /* If the poison city action should empty the granary. */
5948 /* TODO: empty granary and reduce population should become separate
5949 * action effect flags when actions are generalized. */
5950 game
.info
.poison_empties_food_stock
5951 = secfile_lookup_bool_default(file
,
5952 RS_DEFAULT_POISON_EMPTIES_FOOD_STOCK
,
5953 "actions.poison_empties_food_stock");
5955 /* Allow setting max distance for bombardment before generalized
5958 struct entry
*pentry
;
5961 pentry
= secfile_entry_lookup(file
, "actions.bombard_max_range");
5964 max_range
= RS_DEFAULT_BOMBARD_MAX_RANGE
;
5966 switch (entry_type(pentry
)) {
5968 if (entry_int_get(pentry
, &max_range
)) {
5971 /* Fall through to error handling. */
5976 if (entry_str_get(pentry
, &custom
)
5977 && !fc_strcasecmp(custom
, RS_ACTION_NO_MAX_DISTANCE
)) {
5978 max_range
= ACTION_DISTANCE_UNLIMITED
;
5982 /* Fall through to error handling. */
5984 ruleset_error(LOG_ERROR
, "Bad actions.bombard_max_range");
5986 max_range
= RS_DEFAULT_BOMBARD_MAX_RANGE
;
5991 action_by_number(ACTION_BOMBARD
)->max_distance
= max_range
;
5994 text
= secfile_lookup_str_default(file
,
5995 /* TRANS: _Poison City (3% chance of success). */
5996 N_("%sPoison City%s"),
5997 "actions.ui_name_poison_city");
5998 sz_strlcpy(action_by_number(ACTION_SPY_POISON
)->ui_name
,
6001 text
= secfile_lookup_str_default(file
,
6002 /* TRANS: S_abotage Enemy Unit (3% chance of success). */
6003 N_("S%sabotage Enemy Unit%s"),
6004 "actions.ui_name_sabotage_unit");
6005 sz_strlcpy(action_by_number(ACTION_SPY_SABOTAGE_UNIT
)->ui_name
,
6008 text
= secfile_lookup_str_default(file
,
6009 /* TRANS: Bribe Enemy _Unit (3% chance of success). */
6010 N_("Bribe Enemy %sUnit%s"),
6011 "actions.ui_name_bribe_unit");
6012 sz_strlcpy(action_by_number(ACTION_SPY_BRIBE_UNIT
)->ui_name
,
6015 text
= secfile_lookup_str_default(file
,
6016 /* TRANS: _Sabotage City (3% chance of success). */
6017 N_("%sSabotage City%s"),
6018 "actions.ui_name_sabotage_city");
6019 sz_strlcpy(action_by_number(ACTION_SPY_SABOTAGE_CITY
)->ui_name
,
6022 text
= secfile_lookup_str_default(file
,
6023 /* TRANS: Industria_l Sabotage (3% chance of success). */
6024 N_("Industria%sl Sabotage%s"),
6025 "actions.ui_name_targeted_sabotage_city");
6027 action_by_number(ACTION_SPY_TARGETED_SABOTAGE_CITY
)->ui_name
,
6030 text
= secfile_lookup_str_default(file
,
6031 /* TRANS: Incite a Re_volt (3% chance of success). */
6032 N_("Incite a Re%svolt%s"),
6033 "actions.ui_name_incite_city");
6034 sz_strlcpy(action_by_number(ACTION_SPY_INCITE_CITY
)->ui_name
,
6037 text
= secfile_lookup_str_default(file
,
6038 /* TRANS: Establish _Embassy (100% chance of success). */
6039 N_("Establish %sEmbassy%s"),
6040 "actions.ui_name_establish_embassy");
6041 sz_strlcpy(action_by_number(ACTION_ESTABLISH_EMBASSY
)->ui_name
,
6044 text
= secfile_lookup_str_default(file
,
6045 /* TRANS: Establish _Embassy (and stay) (100% chance of success). */
6046 N_("Establish %sEmbassy (and stay)%s"),
6047 "actions.ui_name_establish_embassy_stay");
6048 sz_strlcpy(action_by_number(ACTION_ESTABLISH_EMBASSY_STAY
)->ui_name
,
6051 text
= secfile_lookup_str_default(file
,
6052 /* TRANS: Steal _Technology (3% chance of success). */
6053 N_("Steal %sTechnology%s"),
6054 "actions.ui_name_steal_tech");
6055 sz_strlcpy(action_by_number(ACTION_SPY_STEAL_TECH
)->ui_name
,
6058 text
= secfile_lookup_str_default(file
,
6059 /* TRANS: In_dustrial Espionage (3% chance of success). */
6060 N_("In%sdustrial Espionage%s"),
6061 "actions.ui_name_targeted_steal_tech");
6062 sz_strlcpy(action_by_number(ACTION_SPY_TARGETED_STEAL_TECH
)->ui_name
,
6065 text
= secfile_lookup_str_default(file
,
6066 /* TRANS: _Investigate City (100% chance of success). */
6067 N_("%sInvestigate City%s"),
6068 "actions.ui_name_investigate_city");
6069 sz_strlcpy(action_by_number(ACTION_SPY_INVESTIGATE_CITY
)->ui_name
,
6072 text
= secfile_lookup_str_default(file
,
6073 /* TRANS: _Investigate City (spends the unit) (100% chance of
6075 N_("%sInvestigate City (spends the unit)%s"),
6076 "actions.ui_name_investigate_city_spend_unit");
6077 sz_strlcpy(action_by_number(ACTION_INV_CITY_SPEND
)->ui_name
,
6080 text
= secfile_lookup_str_default(file
,
6081 /* TRANS: Steal _Gold (100% chance of success). */
6082 N_("Steal %sGold%s"),
6083 "actions.ui_name_steal_gold");
6084 sz_strlcpy(action_by_number(ACTION_SPY_STEAL_GOLD
)->ui_name
,
6087 text
= secfile_lookup_str_default(file
,
6088 /* TRANS: Steal _Maps (100% chance of success). */
6089 N_("Steal %sMaps%s"),
6090 "actions.ui_name_steal_maps");
6091 sz_strlcpy(action_by_number(ACTION_STEAL_MAPS
)->ui_name
,
6094 text
= secfile_lookup_str_default(file
,
6095 /* TRANS: Establish Trade _Route (100% chance of success). */
6096 N_("Establish Trade %sRoute%s"),
6097 "actions.ui_name_establish_trade_route");
6098 sz_strlcpy(action_by_number(ACTION_TRADE_ROUTE
)->ui_name
,
6101 text
= secfile_lookup_str_default(file
,
6102 /* TRANS: Enter _Marketplace (100% chance of success). */
6103 N_("Enter %sMarketplace%s"),
6104 "actions.ui_name_enter_marketplace");
6105 sz_strlcpy(action_by_number(ACTION_MARKETPLACE
)->ui_name
,
6108 text
= secfile_lookup_str_default(file
,
6109 /* TRANS: Help _build Wonder (100% chance of success). */
6110 N_("Help %sbuild Wonder%s"),
6111 "actions.ui_name_help_wonder");
6112 sz_strlcpy(action_by_number(ACTION_HELP_WONDER
)->ui_name
,
6115 text
= secfile_lookup_str_default(file
,
6116 /* TRANS: _Capture Units (100% chance of success). */
6117 N_("%sCapture Units%s"),
6118 "actions.ui_name_capture_units");
6119 sz_strlcpy(action_by_number(ACTION_CAPTURE_UNITS
)->ui_name
,
6122 text
= secfile_lookup_str_default(file
,
6123 /* TRANS: _Expel Unit (100% chance of success). */
6124 N_("%sExpel Unit%s"),
6125 "actions.ui_name_expel_unit");
6126 sz_strlcpy(action_by_number(ACTION_EXPEL_UNIT
)->ui_name
,
6129 text
= secfile_lookup_str_default(file
,
6130 /* TRANS: _Found City (100% chance of success). */
6131 N_("%sFound City%s"),
6132 "actions.ui_name_found_city");
6133 sz_strlcpy(action_by_number(ACTION_FOUND_CITY
)->ui_name
,
6136 text
= secfile_lookup_str_default(file
,
6137 /* TRANS: _Join City (100% chance of success). */
6138 N_("%sJoin City%s"),
6139 "actions.ui_name_join_city");
6140 sz_strlcpy(action_by_number(ACTION_JOIN_CITY
)->ui_name
,
6143 text
= secfile_lookup_str_default(file
,
6144 /* TRANS: B_ombard (100% chance of success). */
6146 "actions.ui_name_bombard");
6147 sz_strlcpy(action_by_number(ACTION_BOMBARD
)->ui_name
,
6150 text
= secfile_lookup_str_default(file
,
6151 /* TRANS: Suitcase _Nuke (100% chance of success). */
6152 N_("Suitcase %sNuke%s"),
6153 "actions.ui_name_suitcase_nuke");
6154 sz_strlcpy(action_by_number(ACTION_SPY_NUKE
)->ui_name
,
6157 text
= secfile_lookup_str_default(file
,
6158 /* TRANS: Explode _Nuclear (100% chance of success). */
6159 N_("Explode %sNuclear%s"),
6160 "actions.ui_name_explode_nuclear");
6161 sz_strlcpy(action_by_number(ACTION_NUKE
)->ui_name
,
6164 text
= secfile_lookup_str_default(file
,
6165 /* TRANS: Destroy _City (100% chance of success). */
6166 N_("Destroy %sCity%s"),
6167 "actions.ui_name_destroy_city");
6168 sz_strlcpy(action_by_number(ACTION_DESTROY_CITY
)->ui_name
,
6171 text
= secfile_lookup_str_default(file
,
6172 /* TRANS: Rec_ycle Unit (100% chance of success). */
6173 N_("Rec%sycle Unit%s"),
6174 "actions.ui_name_recycle_unit");
6175 sz_strlcpy(action_by_number(ACTION_RECYCLE_UNIT
)->ui_name
,
6178 text
= secfile_lookup_str_default(file
,
6179 /* TRANS: _You're Fired (100% chance of success). */
6180 N_("%sYou're Fired%s"),
6181 "actions.ui_name_disband_unit");
6182 sz_strlcpy(action_by_number(ACTION_DISBAND_UNIT
)->ui_name
,
6185 text
= secfile_lookup_str_default(file
,
6186 /* TRANS: Set _Home City (100% chance of success). */
6187 N_("Set %sHome City%s"),
6188 "actions.ui_name_home_city");
6189 sz_strlcpy(action_by_number(ACTION_HOME_CITY
)->ui_name
,
6192 text
= secfile_lookup_str_default(file
,
6193 /* TRANS: _Upgrade Unit (100% chance of success). */
6194 N_("%sUpgrade Unit%s"),
6195 "actions.ui_upgrade_unit");
6196 sz_strlcpy(action_by_number(ACTION_UPGRADE_UNIT
)->ui_name
,
6199 text
= secfile_lookup_str_default(file
,
6200 /* TRANS: Drop _Paratrooper (100% chance of success). */
6201 N_("Drop %sParatrooper%s"),
6202 "actions.ui_paradrop_unit");
6203 sz_strlcpy(action_by_number(ACTION_PARADROP
)->ui_name
,
6206 text
= secfile_lookup_str_default(file
,
6207 /* TRANS: _Airlift to City (100% chance of success). */
6208 N_("%sAirlift to City%s"),
6209 "actions.ui_airlift_unit");
6210 sz_strlcpy(action_by_number(ACTION_AIRLIFT
)->ui_name
,
6213 text
= secfile_lookup_str_default(file
,
6214 /* TRANS: _Attack (100% chance of success). */
6216 "actions.ui_name_attack");
6217 sz_strlcpy(action_by_number(ACTION_ATTACK
)->ui_name
,
6220 text
= secfile_lookup_str_default(file
,
6221 /* TRANS: _Conquer City (100% chance of success). */
6222 N_("%sConquer City%s"),
6223 "actions.ui_name_conquer_city");
6224 sz_strlcpy(action_by_number(ACTION_CONQUER_CITY
)->ui_name
,
6227 text
= secfile_lookup_str_default(file
,
6228 /* TRANS: Heal _Unit (3% chance of success). */
6229 N_("Heal %sUnit%s"),
6230 "actions.ui_name_heal_unit");
6231 sz_strlcpy(action_by_number(ACTION_HEAL_UNIT
)->ui_name
,
6234 /* The quiet (don't auto generate help for) property of all actions
6235 * live in a single enum vector. This avoids generic action
6237 if (secfile_entry_by_path(file
, "actions.quiet_actions")) {
6238 enum gen_action
*quiet_actions
;
6243 secfile_lookup_enum_vec(file
, &asize
, gen_action
,
6244 "actions.quiet_actions");
6246 if (!quiet_actions
) {
6247 /* Entity exists but couldn't read it. */
6248 ruleset_error(LOG_ERROR
,
6249 "\"%s\": actions.quiet_actions: bad action list",
6255 for (j
= 0; j
< asize
; j
++) {
6256 /* Don't auto generate help text for this action. */
6257 action_by_number(quiet_actions
[j
])->quiet
= TRUE
;
6260 free(quiet_actions
);
6265 sec
= secfile_sections_by_name_prefix(file
,
6266 ACTION_ENABLER_SECTION_PREFIX
);
6269 section_list_iterate(sec
, psection
) {
6270 struct action_enabler
*enabler
;
6271 const char *sec_name
= section_name(psection
);
6272 struct action
*paction
;
6273 struct requirement_vector
*actor_reqs
;
6274 struct requirement_vector
*target_reqs
;
6275 const char *action_text
;
6277 enabler
= action_enabler_new();
6279 action_text
= secfile_lookup_str(file
, "%s.action", sec_name
);
6281 if (action_text
== NULL
) {
6282 ruleset_error(LOG_ERROR
, "\"%s\" [%s] missing action to enable.",
6283 filename
, sec_name
);
6288 paction
= action_by_rule_name(action_text
);
6290 ruleset_error(LOG_ERROR
, "\"%s\" [%s] lists unknown action type \"%s\".",
6291 filename
, sec_name
, action_text
);
6296 enabler
->action
= paction
->id
;
6298 actor_reqs
= lookup_req_list(file
, compat
, sec_name
, "actor_reqs", action_text
);
6299 if (actor_reqs
== NULL
) {
6304 requirement_vector_copy(&enabler
->actor_reqs
, actor_reqs
);
6306 target_reqs
= lookup_req_list(file
, compat
, sec_name
, "target_reqs", action_text
);
6307 if (target_reqs
== NULL
) {
6312 requirement_vector_copy(&enabler
->target_reqs
, target_reqs
);
6314 action_enabler_add(enabler
);
6315 } section_list_iterate_end
;
6316 section_list_destroy(sec
);
6322 const char *tus_text
;
6324 /* section: combat_rules */
6325 game
.info
.tired_attack
6326 = secfile_lookup_bool_default(file
, RS_DEFAULT_TIRED_ATTACK
,
6327 "combat_rules.tired_attack");
6329 /* section: borders */
6330 game
.info
.border_city_radius_sq
6331 = secfile_lookup_int_default_min_max(file
,
6332 RS_DEFAULT_BORDER_RADIUS_SQ_CITY
,
6333 RS_MIN_BORDER_RADIUS_SQ_CITY
,
6334 RS_MAX_BORDER_RADIUS_SQ_CITY
,
6335 "borders.radius_sq_city");
6336 game
.info
.border_size_effect
6337 = secfile_lookup_int_default_min_max(file
,
6338 RS_DEFAULT_BORDER_SIZE_EFFECT
,
6339 RS_MIN_BORDER_SIZE_EFFECT
,
6340 RS_MAX_BORDER_SIZE_EFFECT
,
6341 "borders.size_effect");
6343 game
.info
.border_city_permanent_radius_sq
6344 = secfile_lookup_int_default_min_max(file
,
6345 RS_DEFAULT_BORDER_RADIUS_SQ_CITY_PERMANENT
,
6346 RS_MIN_BORDER_RADIUS_SQ_CITY_PERMANENT
,
6347 RS_MAX_BORDER_RADIUS_SQ_CITY_PERMANENT
,
6348 "borders.radius_sq_city_permanent");
6350 /* section: research */
6351 tus_text
= secfile_lookup_str_default(file
, RS_DEFAULT_TECH_COST_STYLE
,
6352 "research.tech_cost_style");
6353 game
.info
.tech_cost_style
= tech_cost_style_by_name(tus_text
,
6355 if (!tech_cost_style_is_valid(game
.info
.tech_cost_style
)) {
6356 ruleset_error(LOG_ERROR
, "Unknown tech cost style \"%s\"",
6361 tus_text
= secfile_lookup_str_default(file
, RS_DEFAULT_TECH_LEAKAGE
,
6362 "research.tech_leakage");
6363 game
.info
.tech_leakage
= tech_leakage_style_by_name(tus_text
,
6365 if (!tech_leakage_style_is_valid(game
.info
.tech_leakage
)) {
6366 ruleset_error(LOG_ERROR
, "Unknown tech leakage \"%s\"",
6370 if (game
.info
.tech_cost_style
== TECH_COST_CIV1CIV2
6371 && game
.info
.tech_leakage
!= TECH_LEAKAGE_NONE
) {
6372 log_error("Only tech_leakage \"%s\" supported with "
6373 "tech_cost_style \"%s\". ",
6374 tech_leakage_style_name(TECH_LEAKAGE_NONE
),
6375 tech_cost_style_name(TECH_COST_CIV1CIV2
));
6376 log_error("Switching to tech_leakage \"%s\".",
6377 tech_leakage_style_name(TECH_LEAKAGE_NONE
));
6378 game
.info
.tech_leakage
= TECH_LEAKAGE_NONE
;
6380 game
.info
.base_tech_cost
6381 = secfile_lookup_int_default_min_max(file
,
6382 RS_DEFAULT_BASE_TECH_COST
,
6383 RS_MIN_BASE_TECH_COST
,
6384 RS_MAX_BASE_TECH_COST
,
6385 "research.base_tech_cost");
6387 tus_text
= secfile_lookup_str_default(file
, RS_DEFAULT_TECH_UPKEEP_STYLE
,
6388 "research.tech_upkeep_style");
6390 game
.info
.tech_upkeep_style
= tech_upkeep_style_by_name(tus_text
, fc_strcasecmp
);
6392 if (!tech_upkeep_style_is_valid(game
.info
.tech_upkeep_style
)) {
6393 ruleset_error(LOG_ERROR
, "Unknown tech upkeep style \"%s\"",
6400 game
.info
.tech_upkeep_divider
6401 = secfile_lookup_int_default_min_max(file
,
6402 RS_DEFAULT_TECH_UPKEEP_DIVIDER
,
6403 RS_MIN_TECH_UPKEEP_DIVIDER
,
6404 RS_MAX_TECH_UPKEEP_DIVIDER
,
6405 "research.tech_upkeep_divider");
6407 sval
= secfile_lookup_str_default(file
, NULL
, "research.free_tech_method");
6409 ruleset_error(LOG_ERROR
, "No free_tech_method given");
6412 game
.info
.free_tech_method
= free_tech_method_by_name(sval
, fc_strcasecmp
);
6413 if (!free_tech_method_is_valid(game
.info
.free_tech_method
)) {
6414 ruleset_error(LOG_ERROR
, "Bad value %s for free_tech_method.", sval
);
6423 /* section: culture */
6424 game
.info
.culture_vic_points
6425 = secfile_lookup_int_default(file
, RS_DEFAULT_CULTURE_VIC_POINTS
,
6426 "culture.victory_min_points");
6427 game
.info
.culture_vic_lead
6428 = secfile_lookup_int_default(file
, RS_DEFAULT_CULTURE_VIC_LEAD
,
6429 "culture.victory_lead_pct");
6430 game
.info
.culture_migration_pml
6431 = secfile_lookup_int_default(file
, RS_DEFAULT_CULTURE_MIGRATION_PML
,
6432 "culture.migration_pml");
6434 /* section: calendar */
6435 game
.calendar
.calendar_skip_0
6436 = secfile_lookup_bool_default(file
, RS_DEFAULT_CALENDAR_SKIP_0
,
6437 "calendar.skip_year_0");
6438 game
.server
.start_year
6439 = secfile_lookup_int_default(file
, GAME_START_YEAR
,
6440 "calendar.start_year");
6441 game
.calendar
.calendar_fragments
6442 = secfile_lookup_int_default(file
, 0, "calendar.fragments");
6444 if (game
.calendar
.calendar_fragments
> MAX_CALENDAR_FRAGMENTS
) {
6445 ruleset_error(LOG_ERROR
, "Too many calendar fragments. Max is %d",
6446 MAX_CALENDAR_FRAGMENTS
);
6448 game
.calendar
.calendar_fragments
= 0;
6450 sz_strlcpy(game
.calendar
.positive_year_label
,
6451 secfile_lookup_str_default(file
,
6452 RS_DEFAULT_POS_YEAR_LABEL
,
6453 "calendar.positive_label"));
6454 sz_strlcpy(game
.calendar
.negative_year_label
,
6455 secfile_lookup_str_default(file
,
6456 RS_DEFAULT_NEG_YEAR_LABEL
,
6457 "calendar.negative_label"));
6459 for (cf
= 0; cf
< game
.calendar
.calendar_fragments
; cf
++) {
6462 fname
= secfile_lookup_str_default(file
, NULL
, "calendar.fragment_name%d", cf
);
6463 if (fname
!= NULL
) {
6464 strncpy(game
.calendar
.calendar_fragment_name
[cf
], fname
,
6465 sizeof(game
.calendar
.calendar_fragment_name
[cf
]));
6471 /* section playercolors */
6472 struct rgbcolor
*prgbcolor
= NULL
;
6473 bool color_read
= TRUE
;
6475 /* Check if the player list is defined and empty. */
6476 if (playercolor_count() != 0) {
6481 while (color_read
) {
6484 color_read
= rgbcolor_load(file
, &prgbcolor
, "playercolors.colorlist%d", i
);
6486 playercolor_add(prgbcolor
);
6492 if (playercolor_count() == 0) {
6493 ruleset_error(LOG_ERROR
, "No player colors defined!");
6498 fc_assert(game
.plr_bg_color
== NULL
);
6499 if (!rgbcolor_load(file
, &game
.plr_bg_color
, "playercolors.background")) {
6500 ruleset_error(LOG_ERROR
, "No background player color defined! (%s)",
6509 /* section: teams */
6510 svec
= secfile_lookup_str_vec(file
, &teams
, "teams.names");
6511 if (team_slot_count() < teams
) {
6512 teams
= team_slot_count();
6514 game
.server
.ruledit
.named_teams
= teams
;
6515 for (i
= 0; i
< teams
; i
++) {
6516 team_slot_set_defined_name(team_slot_by_number(i
), svec
[i
]);
6520 sec
= secfile_sections_by_name_prefix(file
, DISASTER_SECTION_PREFIX
);
6521 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
6522 if (nval
> MAX_DISASTER_TYPES
) {
6523 int num
= nval
; /* No "size_t" to printf */
6525 ruleset_error(LOG_ERROR
, "\"%s\": Too many disaster types (%d, max %d)",
6526 filename
, num
, MAX_DISASTER_TYPES
);
6527 section_list_destroy(sec
);
6530 game
.control
.num_disaster_types
= nval
;
6535 disaster_type_iterate(pdis
) {
6536 int id
= disaster_index(pdis
);
6539 struct requirement_vector
*reqs
;
6540 const char *sec_name
= section_name(section_list_get(sec
, id
));
6542 if (!ruleset_load_names(&pdis
->name
, NULL
, file
, sec_name
)) {
6543 ruleset_error(LOG_ERROR
, "\"%s\": Cannot load disaster names",
6549 reqs
= lookup_req_list(file
, compat
, sec_name
, "reqs", disaster_rule_name(pdis
));
6554 requirement_vector_copy(&pdis
->reqs
, reqs
);
6556 pdis
->frequency
= secfile_lookup_int_default(file
, GAME_DEFAULT_DISASTER_FREQ
,
6557 "%s.frequency", sec_name
);
6559 svec
= secfile_lookup_str_vec(file
, &eff_count
, "%s.effects", sec_name
);
6561 BV_CLR_ALL(pdis
->effects
);
6562 for (j
= 0; j
< eff_count
; j
++) {
6563 const char *dsval
= svec
[j
];
6564 enum disaster_effect_id effect
;
6566 effect
= disaster_effect_id_by_name(dsval
, fc_strcasecmp
);
6568 if (!disaster_effect_id_is_valid(effect
)) {
6569 ruleset_error(LOG_ERROR
,
6570 "\"%s\" disaster \"%s\": unknown effect \"%s\".",
6572 disaster_rule_name(pdis
),
6577 BV_SET(pdis
->effects
, effect
);
6586 } disaster_type_iterate_end
;
6587 section_list_destroy(sec
);
6591 sec
= secfile_sections_by_name_prefix(file
, ACHIEVEMENT_SECTION_PREFIX
);
6593 achievements_iterate(pach
) {
6594 int id
= achievement_index(pach
);
6595 const char *sec_name
= section_name(section_list_get(sec
, id
));
6596 const char *typename
;
6599 typename
= secfile_lookup_str_default(file
, NULL
, "%s.type", sec_name
);
6601 pach
->type
= achievement_type_by_name(typename
, fc_strcasecmp
);
6602 if (!achievement_type_is_valid(pach
->type
)) {
6603 ruleset_error(LOG_ERROR
, "Achievement has unknown type \"%s\".",
6604 typename
!= NULL
? typename
: "(NULL)");
6609 pach
->unique
= secfile_lookup_bool_default(file
, GAME_DEFAULT_ACH_UNIQUE
,
6610 "%s.unique", sec_name
);
6612 pach
->value
= secfile_lookup_int_default(file
, GAME_DEFAULT_ACH_VALUE
,
6613 "%s.value", sec_name
);
6614 pach
->culture
= secfile_lookup_int_default(file
, 0,
6615 "%s.culture", sec_name
);
6617 msg
= secfile_lookup_str_default(file
, NULL
, "%s.first_msg", sec_name
);
6619 ruleset_error(LOG_ERROR
, "Achievement %s has no first msg!", sec_name
);
6622 pach
->first_msg
= fc_strdup(msg
);
6627 msg
= secfile_lookup_str_default(file
, NULL
, "%s.cons_msg", sec_name
);
6629 if (!pach
->unique
) {
6630 ruleset_error(LOG_ERROR
, "Achievement %s has no msg for consecutive gainers!", sec_name
);
6634 pach
->cons_msg
= fc_strdup(msg
);
6641 } achievements_iterate_end
;
6645 for (i
= 0; (name
= secfile_lookup_str_default(file
, NULL
,
6646 "trade.settings%d.type",
6648 enum trade_route_type type
= trade_route_type_by_name(name
);
6650 if (type
== TRT_LAST
) {
6651 ruleset_error(LOG_ERROR
,
6652 "\"%s\" unknown trade route type \"%s\".",
6656 struct trade_route_settings
*set
= trade_route_settings_by_type(type
);
6657 const char *cancelling
;
6660 set
->trade_pct
= secfile_lookup_int_default(file
, 100,
6661 "trade.settings%d.pct", i
);
6662 cancelling
= secfile_lookup_str_default(file
, "Active",
6663 "trade.settings%d.cancelling", i
);
6664 set
->cancelling
= traderoute_cancelling_type_by_name(cancelling
);
6665 if (set
->cancelling
== TRI_LAST
) {
6666 ruleset_error(LOG_ERROR
,
6667 "\"%s\" unknown traderoute cancelling type \"%s\".",
6668 filename
, cancelling
);
6672 bonus
= secfile_lookup_str_default(file
, "None", "trade.settings%d.bonus", i
);
6674 set
->bonus_type
= traderoute_bonus_type_by_name(bonus
, fc_strcasecmp
);
6676 if (!traderoute_bonus_type_is_valid(set
->bonus_type
)) {
6677 ruleset_error(LOG_ERROR
,
6678 "\"%s\" unknown traderoute bonus type \"%s\".",
6687 const char *str
= secfile_lookup_str_default(file
, "Leaving", "trade.goods_selection");
6689 game
.info
.goods_selection
= goods_selection_method_by_name(str
, fc_strcasecmp
);
6691 if (!goods_selection_method_is_valid(game
.info
.goods_selection
)) {
6692 ruleset_error(LOG_ERROR
,
6693 "\"%s\" goods selection method \"%s\" unknown.",
6700 sec
= secfile_sections_by_name_prefix(file
, GOODS_SECTION_PREFIX
);
6702 goods_type_iterate(pgood
) {
6703 int id
= goods_index(pgood
);
6704 const char *sec_name
= section_name(section_list_get(sec
, id
));
6705 struct requirement_vector
*reqs
;
6709 reqs
= lookup_req_list(file
, compat
, sec_name
, "reqs", goods_rule_name(pgood
));
6714 requirement_vector_copy(&pgood
->reqs
, reqs
);
6716 pgood
->from_pct
= secfile_lookup_int_default(file
, 100,
6717 "%s.from_pct", sec_name
);
6718 pgood
->to_pct
= secfile_lookup_int_default(file
, 100,
6719 "%s.to_pct", sec_name
);
6721 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", sec_name
);
6722 BV_CLR_ALL(pgood
->flags
);
6723 for (j
= 0; j
< nval
; j
++) {
6724 enum goods_flag_id flag
;
6727 flag
= goods_flag_id_by_name(sval
, fc_strcasecmp
);
6728 if (!goods_flag_id_is_valid(flag
)) {
6729 ruleset_error(LOG_ERROR
, "\"%s\" good \"%s\": unknown flag \"%s\".",
6731 goods_rule_name(pgood
),
6736 BV_SET(pgood
->flags
, flag
);
6741 pgood
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
6742 } goods_type_iterate_end
;
6745 /* secfile_check_unused() is not here, but only after also settings section
6746 * has been loaded. */
6751 /**************************************************************************
6752 Send the units ruleset information (all individual unit classes) to the
6753 specified connections.
6754 **************************************************************************/
6755 static void send_ruleset_unit_classes(struct conn_list
*dest
)
6757 struct packet_ruleset_unit_class packet
;
6758 struct packet_ruleset_unit_class_flag fpacket
;
6761 for (i
= 0; i
< MAX_NUM_USER_UCLASS_FLAGS
; i
++) {
6762 const char *flagname
;
6763 const char *helptxt
;
6765 fpacket
.id
= i
+ UCF_USER_FLAG_1
;
6767 flagname
= unit_class_flag_id_name(i
+ UCF_USER_FLAG_1
);
6768 if (flagname
== NULL
) {
6769 fpacket
.name
[0] = '\0';
6771 sz_strlcpy(fpacket
.name
, flagname
);
6774 helptxt
= unit_class_flag_helptxt(i
+ UCF_USER_FLAG_1
);
6775 if (helptxt
== NULL
) {
6776 fpacket
.helptxt
[0] = '\0';
6778 sz_strlcpy(fpacket
.helptxt
, helptxt
);
6781 lsend_packet_ruleset_unit_class_flag(dest
, &fpacket
);
6784 unit_class_iterate(c
) {
6785 packet
.id
= uclass_number(c
);
6786 sz_strlcpy(packet
.name
, untranslated_name(&c
->name
));
6787 sz_strlcpy(packet
.rule_name
, rule_name_get(&c
->name
));
6788 packet
.min_speed
= c
->min_speed
;
6789 packet
.hp_loss_pct
= c
->hp_loss_pct
;
6790 packet
.hut_behavior
= c
->hut_behavior
;
6791 packet
.non_native_def_pct
= c
->non_native_def_pct
;
6792 packet
.flags
= c
->flags
;
6794 PACKET_STRVEC_COMPUTE(packet
.helptext
, c
->helptext
);
6796 lsend_packet_ruleset_unit_class(dest
, &packet
);
6797 } unit_class_iterate_end
;
6800 /**************************************************************************
6801 Send the units ruleset information (all individual units) to the
6802 specified connections.
6803 **************************************************************************/
6804 static void send_ruleset_units(struct conn_list
*dest
)
6806 struct packet_ruleset_unit packet
;
6807 struct packet_ruleset_unit_flag fpacket
;
6810 for (i
= 0; i
< MAX_NUM_USER_UNIT_FLAGS
; i
++) {
6811 const char *flagname
;
6812 const char *helptxt
;
6814 fpacket
.id
= i
+ UTYF_USER_FLAG_1
;
6816 flagname
= unit_type_flag_id_name(i
+ UTYF_USER_FLAG_1
);
6817 if (flagname
== NULL
) {
6818 fpacket
.name
[0] = '\0';
6820 sz_strlcpy(fpacket
.name
, flagname
);
6823 helptxt
= unit_type_flag_helptxt(i
+ UTYF_USER_FLAG_1
);
6824 if (helptxt
== NULL
) {
6825 fpacket
.helptxt
[0] = '\0';
6827 sz_strlcpy(fpacket
.helptxt
, helptxt
);
6830 lsend_packet_ruleset_unit_flag(dest
, &fpacket
);
6833 unit_type_iterate(u
) {
6834 packet
.id
= utype_number(u
);
6835 sz_strlcpy(packet
.name
, untranslated_name(&u
->name
));
6836 sz_strlcpy(packet
.rule_name
, rule_name_get(&u
->name
));
6837 sz_strlcpy(packet
.sound_move
, u
->sound_move
);
6838 sz_strlcpy(packet
.sound_move_alt
, u
->sound_move_alt
);
6839 sz_strlcpy(packet
.sound_fight
, u
->sound_fight
);
6840 sz_strlcpy(packet
.sound_fight_alt
, u
->sound_fight_alt
);
6841 sz_strlcpy(packet
.graphic_str
, u
->graphic_str
);
6842 sz_strlcpy(packet
.graphic_alt
, u
->graphic_alt
);
6843 packet
.unit_class_id
= uclass_number(utype_class(u
));
6844 packet
.build_cost
= u
->build_cost
;
6845 packet
.pop_cost
= u
->pop_cost
;
6846 packet
.attack_strength
= u
->attack_strength
;
6847 packet
.defense_strength
= u
->defense_strength
;
6848 packet
.move_rate
= u
->move_rate
;
6849 packet
.tech_requirement
= u
->require_advance
6850 ? advance_number(u
->require_advance
)
6852 packet
.impr_requirement
= u
->need_improvement
6853 ? improvement_number(u
->need_improvement
)
6854 : improvement_count();
6855 packet
.gov_requirement
= u
->need_government
6856 ? government_number(u
->need_government
)
6857 : government_count();
6858 packet
.vision_radius_sq
= u
->vision_radius_sq
;
6859 packet
.transport_capacity
= u
->transport_capacity
;
6861 packet
.firepower
= u
->firepower
;
6862 packet
.obsoleted_by
= u
->obsoleted_by
6863 ? utype_number(u
->obsoleted_by
)
6865 packet
.converted_to
= u
->converted_to
6866 ? utype_number(u
->converted_to
)
6868 packet
.convert_time
= u
->convert_time
;
6869 packet
.fuel
= u
->fuel
;
6870 packet
.flags
= u
->flags
;
6871 packet
.roles
= u
->roles
;
6872 packet
.happy_cost
= u
->happy_cost
;
6873 output_type_iterate(o
) {
6874 packet
.upkeep
[o
] = u
->upkeep
[o
];
6875 } output_type_iterate_end
;
6876 packet
.paratroopers_range
= u
->paratroopers_range
;
6877 packet
.paratroopers_mr_req
= u
->paratroopers_mr_req
;
6878 packet
.paratroopers_mr_sub
= u
->paratroopers_mr_sub
;
6879 packet
.bombard_rate
= u
->bombard_rate
;
6880 packet
.city_size
= u
->city_size
;
6881 packet
.city_slots
= u
->city_slots
;
6882 packet
.cargo
= u
->cargo
;
6883 packet
.targets
= u
->targets
;
6884 packet
.embarks
= u
->embarks
;
6885 packet
.disembarks
= u
->disembarks
;
6887 if (u
->veteran
== NULL
) {
6888 /* Use the default veteran system. */
6889 packet
.veteran_levels
= 0;
6891 /* Per unit veteran system definition. */
6892 packet
.veteran_levels
= utype_veteran_levels(u
);
6894 for (i
= 0; i
< packet
.veteran_levels
; i
++) {
6895 const struct veteran_level
*vlevel
= utype_veteran_level(u
, i
);
6897 sz_strlcpy(packet
.veteran_name
[i
], untranslated_name(&vlevel
->name
));
6898 packet
.power_fact
[i
] = vlevel
->power_fact
;
6899 packet
.move_bonus
[i
] = vlevel
->move_bonus
;
6902 PACKET_STRVEC_COMPUTE(packet
.helptext
, u
->helptext
);
6904 lsend_packet_ruleset_unit(dest
, &packet
);
6906 combat_bonus_list_iterate(u
->bonuses
, pbonus
) {
6907 struct packet_ruleset_unit_bonus bonuspacket
;
6909 bonuspacket
.unit
= packet
.id
;
6910 bonuspacket
.flag
= pbonus
->flag
;
6911 bonuspacket
.type
= pbonus
->type
;
6912 bonuspacket
.value
= pbonus
->value
;
6913 bonuspacket
.quiet
= pbonus
->quiet
;
6915 lsend_packet_ruleset_unit_bonus(dest
, &bonuspacket
);
6916 } combat_bonus_list_iterate_end
;
6917 } unit_type_iterate_end
;
6920 /**************************************************************************
6921 Send the specialists ruleset information (all individual specialist
6922 types) to the specified connections.
6923 **************************************************************************/
6924 static void send_ruleset_specialists(struct conn_list
*dest
)
6926 struct packet_ruleset_specialist packet
;
6928 specialist_type_iterate(spec_id
) {
6929 struct specialist
*s
= specialist_by_number(spec_id
);
6932 packet
.id
= spec_id
;
6933 sz_strlcpy(packet
.plural_name
, untranslated_name(&s
->name
));
6934 sz_strlcpy(packet
.rule_name
, rule_name_get(&s
->name
));
6935 sz_strlcpy(packet
.short_name
, untranslated_name(&s
->abbreviation
));
6936 sz_strlcpy(packet
.graphic_alt
, s
->graphic_alt
);
6938 requirement_vector_iterate(&s
->reqs
, preq
) {
6939 packet
.reqs
[j
++] = *preq
;
6940 } requirement_vector_iterate_end
;
6941 packet
.reqs_count
= j
;
6943 PACKET_STRVEC_COMPUTE(packet
.helptext
, s
->helptext
);
6945 lsend_packet_ruleset_specialist(dest
, &packet
);
6946 } specialist_type_iterate_end
;
6948 /**************************************************************************
6949 Send the techs class information to the specified connections.
6950 **************************************************************************/
6951 static void send_ruleset_tech_classes(struct conn_list
*dest
)
6953 struct packet_ruleset_tech_class packet
;
6955 tech_class_iterate(ptclass
) {
6956 packet
.id
= ptclass
->idx
;
6957 sz_strlcpy(packet
.name
, untranslated_name(&ptclass
->name
));
6958 sz_strlcpy(packet
.rule_name
, rule_name_get(&ptclass
->name
));
6959 packet
.cost_pct
= ptclass
->cost_pct
;
6961 lsend_packet_ruleset_tech_class(dest
, &packet
);
6962 } tech_class_iterate_end
;
6965 /**************************************************************************
6966 Send the techs ruleset information (all individual advances) to the
6967 specified connections.
6968 **************************************************************************/
6969 static void send_ruleset_techs(struct conn_list
*dest
)
6971 struct packet_ruleset_tech packet
;
6972 struct packet_ruleset_tech_flag fpacket
;
6975 for (i
= 0; i
< MAX_NUM_USER_TECH_FLAGS
; i
++) {
6976 const char *flagname
;
6977 const char *helptxt
;
6979 fpacket
.id
= i
+ TECH_USER_1
;
6981 flagname
= tech_flag_id_name_cb(i
+ TECH_USER_1
);
6982 if (flagname
== NULL
) {
6983 fpacket
.name
[0] = '\0';
6985 sz_strlcpy(fpacket
.name
, flagname
);
6988 helptxt
= tech_flag_helptxt(i
+ TECH_USER_1
);
6989 if (helptxt
== NULL
) {
6990 fpacket
.helptxt
[0] = '\0';
6992 sz_strlcpy(fpacket
.helptxt
, helptxt
);
6995 lsend_packet_ruleset_tech_flag(dest
, &fpacket
);
6998 advance_iterate(A_FIRST
, a
) {
6999 packet
.id
= advance_number(a
);
7000 packet
.removed
= !valid_advance(a
);
7001 if (a
->tclass
== NULL
) {
7004 packet
.tclass
= a
->tclass
->idx
;
7006 sz_strlcpy(packet
.name
, untranslated_name(&a
->name
));
7007 sz_strlcpy(packet
.rule_name
, rule_name_get(&a
->name
));
7008 sz_strlcpy(packet
.graphic_str
, a
->graphic_str
);
7009 sz_strlcpy(packet
.graphic_alt
, a
->graphic_alt
);
7011 /* Current size of the packet's research_reqs requirement vector. */
7014 /* The requirements req1 and req2 are needed to research a tech. Send
7015 * them in the research_reqs requirement vector. Range is set to player
7016 * since pooled research is configurable. */
7018 if ((a
->require
[AR_ONE
] != A_NEVER
)
7019 && advance_number(a
->require
[AR_ONE
]) > A_NONE
) {
7020 packet
.research_reqs
[i
++]
7021 = req_from_values(VUT_ADVANCE
, REQ_RANGE_PLAYER
,
7023 advance_number(a
->require
[AR_ONE
]));
7026 if ((a
->require
[AR_TWO
] != A_NEVER
)
7027 && advance_number(a
->require
[AR_TWO
]) > A_NONE
) {
7028 packet
.research_reqs
[i
++]
7029 = req_from_values(VUT_ADVANCE
, REQ_RANGE_PLAYER
,
7031 advance_number(a
->require
[AR_TWO
]));;
7034 /* The requirements of the tech's research_reqs also goes in the
7035 * packet's research_reqs requirement vector. */
7036 requirement_vector_iterate(&a
->research_reqs
, req
) {
7037 packet
.research_reqs
[i
++] = *req
;
7038 } requirement_vector_iterate_end
;
7040 /* The packet's research_reqs should contain req1, req2 and the
7041 * requirements of the tech's research_reqs. */
7042 packet
.research_reqs_count
= i
;
7044 packet
.root_req
= a
->require
[AR_ROOT
]
7045 ? advance_number(a
->require
[AR_ROOT
])
7048 packet
.flags
= a
->flags
;
7049 packet
.cost
= a
->cost
;
7050 packet
.num_reqs
= a
->num_reqs
;
7051 PACKET_STRVEC_COMPUTE(packet
.helptext
, a
->helptext
);
7053 lsend_packet_ruleset_tech(dest
, &packet
);
7054 } advance_iterate_end
;
7057 /**************************************************************************
7058 Send the buildings ruleset information (all individual improvements and
7059 wonders) to the specified connections.
7060 **************************************************************************/
7061 static void send_ruleset_buildings(struct conn_list
*dest
)
7063 improvement_iterate(b
) {
7064 struct packet_ruleset_building packet
;
7067 packet
.id
= improvement_number(b
);
7068 packet
.genus
= b
->genus
;
7069 sz_strlcpy(packet
.name
, untranslated_name(&b
->name
));
7070 sz_strlcpy(packet
.rule_name
, rule_name_get(&b
->name
));
7071 sz_strlcpy(packet
.graphic_str
, b
->graphic_str
);
7072 sz_strlcpy(packet
.graphic_alt
, b
->graphic_alt
);
7074 requirement_vector_iterate(&b
->reqs
, preq
) {
7075 packet
.reqs
[j
++] = *preq
;
7076 } requirement_vector_iterate_end
;
7077 packet
.reqs_count
= j
;
7079 requirement_vector_iterate(&b
->obsolete_by
, pobs
) {
7080 packet
.obs_reqs
[j
++] = *pobs
;
7081 } requirement_vector_iterate_end
;
7082 packet
.obs_count
= j
;
7083 packet
.build_cost
= b
->build_cost
;
7084 packet
.upkeep
= b
->upkeep
;
7085 packet
.sabotage
= b
->sabotage
;
7086 packet
.flags
= b
->flags
;
7087 sz_strlcpy(packet
.soundtag
, b
->soundtag
);
7088 sz_strlcpy(packet
.soundtag_alt
, b
->soundtag_alt
);
7089 PACKET_STRVEC_COMPUTE(packet
.helptext
, b
->helptext
);
7091 lsend_packet_ruleset_building(dest
, &packet
);
7092 } improvement_iterate_end
;
7095 /**************************************************************************
7096 Send the terrain ruleset information (terrain_control, and the individual
7097 terrain types) to the specified connections.
7098 **************************************************************************/
7099 static void send_ruleset_terrain(struct conn_list
*dest
)
7101 struct packet_ruleset_terrain packet
;
7102 struct packet_ruleset_terrain_flag fpacket
;
7105 lsend_packet_ruleset_terrain_control(dest
, &terrain_control
);
7107 for (i
= 0; i
< MAX_NUM_USER_TER_FLAGS
; i
++) {
7108 const char *flagname
;
7109 const char *helptxt
;
7111 fpacket
.id
= i
+ TER_USER_1
;
7113 flagname
= terrain_flag_id_name_cb(i
+ TER_USER_1
);
7114 if (flagname
== NULL
) {
7115 fpacket
.name
[0] = '\0';
7117 sz_strlcpy(fpacket
.name
, flagname
);
7120 helptxt
= terrain_flag_helptxt(i
+ TER_USER_1
);
7121 if (helptxt
== NULL
) {
7122 fpacket
.helptxt
[0] = '\0';
7124 sz_strlcpy(fpacket
.helptxt
, helptxt
);
7127 lsend_packet_ruleset_terrain_flag(dest
, &fpacket
);
7130 terrain_type_iterate(pterrain
) {
7131 struct extra_type
**r
;
7133 packet
.id
= terrain_number(pterrain
);
7134 packet
.tclass
= pterrain
->tclass
;
7135 packet
.native_to
= pterrain
->native_to
;
7137 sz_strlcpy(packet
.name
, untranslated_name(&pterrain
->name
));
7138 sz_strlcpy(packet
.rule_name
, rule_name_get(&pterrain
->name
));
7139 sz_strlcpy(packet
.graphic_str
, pterrain
->graphic_str
);
7140 sz_strlcpy(packet
.graphic_alt
, pterrain
->graphic_alt
);
7142 packet
.movement_cost
= pterrain
->movement_cost
;
7143 packet
.defense_bonus
= pterrain
->defense_bonus
;
7145 output_type_iterate(o
) {
7146 packet
.output
[o
] = pterrain
->output
[o
];
7147 } output_type_iterate_end
;
7149 packet
.num_resources
= 0;
7150 for (r
= pterrain
->resources
; *r
; r
++) {
7151 packet
.resources
[packet
.num_resources
++] = extra_number(*r
);
7154 output_type_iterate(o
) {
7155 packet
.road_output_incr_pct
[o
] = pterrain
->road_output_incr_pct
[o
];
7156 } output_type_iterate_end
;
7158 packet
.base_time
= pterrain
->base_time
;
7159 packet
.road_time
= pterrain
->road_time
;
7161 packet
.irrigation_result
= (pterrain
->irrigation_result
7162 ? terrain_number(pterrain
->irrigation_result
)
7164 packet
.irrigation_food_incr
= pterrain
->irrigation_food_incr
;
7165 packet
.irrigation_time
= pterrain
->irrigation_time
;
7167 packet
.mining_result
= (pterrain
->mining_result
7168 ? terrain_number(pterrain
->mining_result
)
7170 packet
.mining_shield_incr
= pterrain
->mining_shield_incr
;
7171 packet
.mining_time
= pterrain
->mining_time
;
7173 packet
.animal
= (pterrain
->animal
== NULL
? -1 : utype_number(pterrain
->animal
));
7174 packet
.transform_result
= (pterrain
->transform_result
7175 ? terrain_number(pterrain
->transform_result
)
7177 packet
.pillage_time
= pterrain
->pillage_time
;
7178 packet
.transform_time
= pterrain
->transform_time
;
7179 packet
.clean_pollution_time
= pterrain
->clean_pollution_time
;
7180 packet
.clean_fallout_time
= pterrain
->clean_fallout_time
;
7182 packet
.flags
= pterrain
->flags
;
7184 packet
.color_red
= pterrain
->rgb
->r
;
7185 packet
.color_green
= pterrain
->rgb
->g
;
7186 packet
.color_blue
= pterrain
->rgb
->b
;
7188 PACKET_STRVEC_COMPUTE(packet
.helptext
, pterrain
->helptext
);
7190 lsend_packet_ruleset_terrain(dest
, &packet
);
7191 } terrain_type_iterate_end
;
7194 /****************************************************************************
7195 Send the resource ruleset information to the specified connections.
7196 ****************************************************************************/
7197 static void send_ruleset_resources(struct conn_list
*dest
)
7199 struct packet_ruleset_resource packet
;
7201 extra_type_by_cause_iterate(EC_RESOURCE
, presource
) {
7202 packet
.id
= extra_index(presource
);
7204 output_type_iterate(o
) {
7205 packet
.output
[o
] = presource
->data
.resource
->output
[o
];
7206 } output_type_iterate_end
;
7208 lsend_packet_ruleset_resource(dest
, &packet
);
7209 } extra_type_by_cause_iterate_end
;
7212 /**************************************************************************
7213 Send the extra ruleset information (all individual extra types) to the
7214 specified connections.
7215 **************************************************************************/
7216 static void send_ruleset_extras(struct conn_list
*dest
)
7218 struct packet_ruleset_extra packet
;
7219 struct packet_ruleset_extra_flag fpacket
;
7222 for (i
= 0; i
< MAX_NUM_USER_EXTRA_FLAGS
; i
++) {
7223 const char *flagname
;
7224 const char *helptxt
;
7226 fpacket
.id
= i
+ EF_USER_FLAG_1
;
7228 flagname
= extra_flag_id_name(i
+ EF_USER_FLAG_1
);
7229 if (flagname
== NULL
) {
7230 fpacket
.name
[0] = '\0';
7232 sz_strlcpy(fpacket
.name
, flagname
);
7235 helptxt
= extra_flag_helptxt(i
+ EF_USER_FLAG_1
);
7236 if (helptxt
== NULL
) {
7237 fpacket
.helptxt
[0] = '\0';
7239 sz_strlcpy(fpacket
.helptxt
, helptxt
);
7242 lsend_packet_ruleset_extra_flag(dest
, &fpacket
);
7245 extra_type_iterate(e
) {
7248 packet
.id
= extra_number(e
);
7249 sz_strlcpy(packet
.name
, untranslated_name(&e
->name
));
7250 sz_strlcpy(packet
.rule_name
, rule_name_get(&e
->name
));
7252 packet
.category
= e
->category
;
7253 packet
.causes
= e
->causes
;
7254 packet
.rmcauses
= e
->rmcauses
;
7256 sz_strlcpy(packet
.activity_gfx
, e
->activity_gfx
);
7257 sz_strlcpy(packet
.act_gfx_alt
, e
->act_gfx_alt
);
7258 sz_strlcpy(packet
.act_gfx_alt2
, e
->act_gfx_alt2
);
7259 sz_strlcpy(packet
.rmact_gfx
, e
->rmact_gfx
);
7260 sz_strlcpy(packet
.rmact_gfx_alt
, e
->rmact_gfx_alt
);
7261 sz_strlcpy(packet
.graphic_str
, e
->graphic_str
);
7262 sz_strlcpy(packet
.graphic_alt
, e
->graphic_alt
);
7265 requirement_vector_iterate(&e
->reqs
, preq
) {
7266 packet
.reqs
[j
++] = *preq
;
7267 } requirement_vector_iterate_end
;
7268 packet
.reqs_count
= j
;
7271 requirement_vector_iterate(&e
->rmreqs
, preq
) {
7272 packet
.rmreqs
[j
++] = *preq
;
7273 } requirement_vector_iterate_end
;
7274 packet
.rmreqs_count
= j
;
7276 packet
.appearance_chance
= e
->appearance_chance
;
7278 requirement_vector_iterate(&e
->appearance_reqs
, preq
) {
7279 packet
.appearance_reqs
[j
++] = *preq
;
7280 } requirement_vector_iterate_end
;
7281 packet
.appearance_reqs_count
= j
;
7283 packet
.disappearance_chance
= e
->disappearance_chance
;
7285 requirement_vector_iterate(&e
->disappearance_reqs
, preq
) {
7286 packet
.disappearance_reqs
[j
++] = *preq
;
7287 } requirement_vector_iterate_end
;
7288 packet
.disappearance_reqs_count
= j
;
7290 packet
.visibility_req
= e
->visibility_req
;
7291 packet
.buildable
= e
->buildable
;
7292 packet
.build_time
= e
->build_time
;
7293 packet
.build_time_factor
= e
->build_time_factor
;
7294 packet
.removal_time
= e
->removal_time
;
7295 packet
.removal_time_factor
= e
->removal_time_factor
;
7296 packet
.defense_bonus
= e
->defense_bonus
;
7297 packet
.eus
= e
->eus
;
7299 packet
.native_to
= e
->native_to
;
7301 packet
.flags
= e
->flags
;
7302 packet
.hidden_by
= e
->hidden_by
;
7303 packet
.conflicts
= e
->conflicts
;
7305 PACKET_STRVEC_COMPUTE(packet
.helptext
, e
->helptext
);
7307 lsend_packet_ruleset_extra(dest
, &packet
);
7308 } extra_type_iterate_end
;
7311 /**************************************************************************
7312 Send the base ruleset information (all individual base types) to the
7313 specified connections.
7314 **************************************************************************/
7315 static void send_ruleset_bases(struct conn_list
*dest
)
7317 extra_type_by_cause_iterate(EC_BASE
, pextra
) {
7318 struct base_type
*b
= extra_base_get(pextra
);
7319 struct packet_ruleset_base packet
;
7321 packet
.id
= base_number(b
);
7323 packet
.gui_type
= b
->gui_type
;
7324 packet
.border_sq
= b
->border_sq
;
7325 packet
.vision_main_sq
= b
->vision_main_sq
;
7326 packet
.vision_invis_sq
= b
->vision_invis_sq
;
7328 packet
.flags
= b
->flags
;
7330 lsend_packet_ruleset_base(dest
, &packet
);
7331 } extra_type_by_cause_iterate_end
;
7334 /**************************************************************************
7335 Send the road ruleset information (all individual road types) to the
7336 specified connections.
7337 **************************************************************************/
7338 static void send_ruleset_roads(struct conn_list
*dest
)
7340 struct packet_ruleset_road packet
;
7342 extra_type_by_cause_iterate(EC_ROAD
, pextra
) {
7343 struct road_type
*r
= extra_road_get(pextra
);
7346 packet
.id
= road_number(r
);
7349 requirement_vector_iterate(&r
->first_reqs
, preq
) {
7350 packet
.first_reqs
[j
++] = *preq
;
7351 } requirement_vector_iterate_end
;
7352 packet
.first_reqs_count
= j
;
7354 packet
.move_cost
= r
->move_cost
;
7355 packet
.move_mode
= r
->move_mode
;
7357 output_type_iterate(o
) {
7358 packet
.tile_incr_const
[o
] = r
->tile_incr_const
[o
];
7359 packet
.tile_incr
[o
] = r
->tile_incr
[o
];
7360 packet
.tile_bonus
[o
] = r
->tile_bonus
[o
];
7361 } output_type_iterate_end
;
7363 packet
.compat
= r
->compat
;
7365 packet
.integrates
= r
->integrates
;
7366 packet
.flags
= r
->flags
;
7368 lsend_packet_ruleset_road(dest
, &packet
);
7369 } extra_type_by_cause_iterate_end
;
7372 /**************************************************************************
7373 Send the goods ruleset information (all individual goods types) to the
7374 specified connections.
7375 **************************************************************************/
7376 static void send_ruleset_goods(struct conn_list
*dest
)
7378 struct packet_ruleset_goods packet
;
7380 goods_type_iterate(g
) {
7383 packet
.id
= goods_number(g
);
7384 sz_strlcpy(packet
.name
, untranslated_name(&g
->name
));
7385 sz_strlcpy(packet
.rule_name
, rule_name_get(&g
->name
));
7388 requirement_vector_iterate(&g
->reqs
, preq
) {
7389 packet
.reqs
[j
++] = *preq
;
7390 } requirement_vector_iterate_end
;
7391 packet
.reqs_count
= j
;
7393 packet
.from_pct
= g
->from_pct
;
7394 packet
.to_pct
= g
->to_pct
;
7395 packet
.flags
= g
->flags
;
7397 PACKET_STRVEC_COMPUTE(packet
.helptext
, g
->helptext
);
7399 lsend_packet_ruleset_goods(dest
, &packet
);
7400 } goods_type_iterate_end
;
7403 /**************************************************************************
7404 Send the disaster ruleset information (all individual disaster types) to the
7405 specified connections.
7406 **************************************************************************/
7407 static void send_ruleset_disasters(struct conn_list
*dest
)
7409 struct packet_ruleset_disaster packet
;
7411 disaster_type_iterate(d
) {
7414 packet
.id
= disaster_number(d
);
7416 sz_strlcpy(packet
.name
, untranslated_name(&d
->name
));
7417 sz_strlcpy(packet
.rule_name
, rule_name_get(&d
->name
));
7420 requirement_vector_iterate(&d
->reqs
, preq
) {
7421 packet
.reqs
[j
++] = *preq
;
7422 } requirement_vector_iterate_end
;
7423 packet
.reqs_count
= j
;
7425 packet
.frequency
= d
->frequency
;
7427 packet
.effects
= d
->effects
;
7429 lsend_packet_ruleset_disaster(dest
, &packet
);
7430 } disaster_type_iterate_end
;
7433 /**************************************************************************
7434 Send the achievement ruleset information (all individual achievement types)
7435 to the specified connections.
7436 **************************************************************************/
7437 static void send_ruleset_achievements(struct conn_list
*dest
)
7439 struct packet_ruleset_achievement packet
;
7441 achievements_iterate(a
) {
7442 packet
.id
= achievement_number(a
);
7444 sz_strlcpy(packet
.name
, untranslated_name(&a
->name
));
7445 sz_strlcpy(packet
.rule_name
, rule_name_get(&a
->name
));
7447 packet
.type
= a
->type
;
7448 packet
.unique
= a
->unique
;
7449 packet
.value
= a
->value
;
7451 lsend_packet_ruleset_achievement(dest
, &packet
);
7452 } achievements_iterate_end
;
7455 /**************************************************************************
7456 Send action ruleset information to the specified connections.
7457 **************************************************************************/
7458 static void send_ruleset_actions(struct conn_list
*dest
)
7460 struct packet_ruleset_action packet
;
7462 action_iterate(act
) {
7464 sz_strlcpy(packet
.ui_name
, action_by_number(act
)->ui_name
);
7465 packet
.quiet
= action_by_number(act
)->quiet
;
7467 packet
.act_kind
= action_by_number(act
)->actor_kind
;
7468 packet
.tgt_kind
= action_by_number(act
)->target_kind
;
7470 packet
.min_distance
= action_by_number(act
)->min_distance
;
7471 packet
.max_distance
= action_by_number(act
)->max_distance
;
7472 packet
.blocked_by
= action_by_number(act
)->blocked_by
;
7474 lsend_packet_ruleset_action(dest
, &packet
);
7475 } action_iterate_end
;
7478 /**************************************************************************
7479 Send the action enabler ruleset information to the specified connections.
7480 **************************************************************************/
7481 static void send_ruleset_action_enablers(struct conn_list
*dest
)
7484 struct packet_ruleset_action_enabler packet
;
7486 action_enablers_iterate(enabler
) {
7487 packet
.enabled_action
= enabler
->action
;
7490 requirement_vector_iterate(&enabler
->actor_reqs
, req
) {
7491 packet
.actor_reqs
[counter
++] = *req
;
7492 } requirement_vector_iterate_end
;
7493 packet
.actor_reqs_count
= counter
;
7496 requirement_vector_iterate(&enabler
->target_reqs
, req
) {
7497 packet
.target_reqs
[counter
++] = *req
;
7498 } requirement_vector_iterate_end
;
7499 packet
.target_reqs_count
= counter
;
7501 lsend_packet_ruleset_action_enabler(dest
, &packet
);
7502 } action_enablers_iterate_end
;
7505 /**************************************************************************
7506 Send action auto performer ruleset information to the specified
7508 **************************************************************************/
7509 static void send_ruleset_action_auto_performers(struct conn_list
*dest
)
7513 struct packet_ruleset_action_auto packet
;
7516 action_auto_perf_iterate(aperf
) {
7519 packet
.cause
= aperf
->cause
;
7522 requirement_vector_iterate(&aperf
->reqs
, req
) {
7523 packet
.reqs
[counter
++] = *req
;
7524 } requirement_vector_iterate_end
;
7525 packet
.reqs_count
= counter
;
7528 /* Can't list more actions than all actions. */
7529 counter
< NUM_ACTIONS
7530 /* ACTION_NONE terminates the list. */
7531 && aperf
->alternatives
[counter
] != ACTION_NONE
;
7533 packet
.alternatives
[counter
] = aperf
->alternatives
[counter
];
7535 packet
.alternatives_count
= counter
;
7537 lsend_packet_ruleset_action_auto(dest
, &packet
);
7538 } action_auto_perf_iterate_end
;
7541 /**************************************************************************
7542 Send the disaster ruleset information (all individual disaster types) to the
7543 specified connections.
7544 **************************************************************************/
7545 static void send_ruleset_trade_routes(struct conn_list
*dest
)
7547 struct packet_ruleset_trade packet
;
7548 enum trade_route_type type
;
7550 for (type
= TRT_NATIONAL
; type
< TRT_LAST
; type
++) {
7551 struct trade_route_settings
*set
= trade_route_settings_by_type(type
);
7554 packet
.trade_pct
= set
->trade_pct
;
7555 packet
.cancelling
= set
->cancelling
;
7556 packet
.bonus_type
= set
->bonus_type
;
7558 lsend_packet_ruleset_trade(dest
, &packet
);
7562 /**************************************************************************
7563 Send the government ruleset information to the specified connections.
7564 One packet per government type, and for each type one per ruler title.
7565 **************************************************************************/
7566 static void send_ruleset_governments(struct conn_list
*dest
)
7568 struct packet_ruleset_government gov
;
7569 struct packet_ruleset_government_ruler_title title
;
7572 governments_iterate(g
) {
7573 /* send one packet_government */
7574 gov
.id
= government_number(g
);
7577 requirement_vector_iterate(&g
->reqs
, preq
) {
7578 gov
.reqs
[j
++] = *preq
;
7579 } requirement_vector_iterate_end
;
7582 sz_strlcpy(gov
.name
, untranslated_name(&g
->name
));
7583 sz_strlcpy(gov
.rule_name
, rule_name_get(&g
->name
));
7584 sz_strlcpy(gov
.graphic_str
, g
->graphic_str
);
7585 sz_strlcpy(gov
.graphic_alt
, g
->graphic_alt
);
7586 PACKET_STRVEC_COMPUTE(gov
.helptext
, g
->helptext
);
7588 lsend_packet_ruleset_government(dest
, &gov
);
7590 /* Send one packet_government_ruler_title per ruler title. */
7591 ruler_titles_iterate(government_ruler_titles(g
), pruler_title
) {
7592 const struct nation_type
*pnation
= ruler_title_nation(pruler_title
);
7594 title
.gov
= government_number(g
);
7595 title
.nation
= pnation
? nation_number(pnation
) : nation_count();
7596 sz_strlcpy(title
.male_title
,
7597 ruler_title_male_untranslated_name(pruler_title
));
7598 sz_strlcpy(title
.female_title
,
7599 ruler_title_female_untranslated_name(pruler_title
));
7600 lsend_packet_ruleset_government_ruler_title(dest
, &title
);
7601 } ruler_titles_iterate_end
;
7602 } governments_iterate_end
;
7605 /**************************************************************************
7606 Send the nations ruleset information (info on each nation) to the
7607 specified connections.
7608 **************************************************************************/
7609 static void send_ruleset_nations(struct conn_list
*dest
)
7611 struct packet_ruleset_nation_sets sets_packet
;
7612 struct packet_ruleset_nation_groups groups_packet
;
7613 struct packet_ruleset_nation packet
;
7616 sets_packet
.nsets
= nation_set_count();
7618 nation_sets_iterate(pset
) {
7619 sz_strlcpy(sets_packet
.names
[i
], nation_set_untranslated_name(pset
));
7620 sz_strlcpy(sets_packet
.rule_names
[i
], nation_set_rule_name(pset
));
7621 sz_strlcpy(sets_packet
.descriptions
[i
], nation_set_description(pset
));
7623 } nation_sets_iterate_end
;
7624 lsend_packet_ruleset_nation_sets(dest
, &sets_packet
);
7626 groups_packet
.ngroups
= nation_group_count();
7628 nation_groups_iterate(pgroup
) {
7629 sz_strlcpy(groups_packet
.groups
[i
],
7630 nation_group_untranslated_name(pgroup
));
7631 groups_packet
.hidden
[i
] = pgroup
->hidden
;
7633 } nation_groups_iterate_end
;
7634 lsend_packet_ruleset_nation_groups(dest
, &groups_packet
);
7636 nations_iterate(n
) {
7637 packet
.id
= nation_number(n
);
7638 if (n
->translation_domain
== NULL
) {
7639 packet
.translation_domain
[0] = '\0';
7641 sz_strlcpy(packet
.translation_domain
, n
->translation_domain
);
7643 sz_strlcpy(packet
.adjective
, untranslated_name(&n
->adjective
));
7644 sz_strlcpy(packet
.rule_name
, rule_name_get(&n
->adjective
));
7645 sz_strlcpy(packet
.noun_plural
, untranslated_name(&n
->noun_plural
));
7646 sz_strlcpy(packet
.graphic_str
, n
->flag_graphic_str
);
7647 sz_strlcpy(packet
.graphic_alt
, n
->flag_graphic_alt
);
7650 nation_leader_list_iterate(nation_leaders(n
), pleader
) {
7651 sz_strlcpy(packet
.leader_name
[i
], nation_leader_name(pleader
));
7652 packet
.leader_is_male
[i
] = nation_leader_is_male(pleader
);
7654 } nation_leader_list_iterate_end
;
7655 packet
.leader_count
= i
;
7657 packet
.style
= style_number(n
->style
);
7658 packet
.is_playable
= n
->is_playable
;
7659 packet
.barbarian_type
= n
->barb_type
;
7661 sz_strlcpy(packet
.legend
, n
->legend
);
7664 nation_set_list_iterate(n
->sets
, pset
) {
7665 packet
.sets
[i
++] = nation_set_number(pset
);
7666 } nation_set_list_iterate_end
;
7670 nation_group_list_iterate(n
->groups
, pgroup
) {
7671 packet
.groups
[i
++] = nation_group_number(pgroup
);
7672 } nation_group_list_iterate_end
;
7675 packet
.init_government_id
= n
->init_government
7676 ? government_number(n
->init_government
) : government_count();
7677 fc_assert(ARRAY_SIZE(packet
.init_techs
) == ARRAY_SIZE(n
->init_techs
));
7678 for (i
= 0; i
< MAX_NUM_TECH_LIST
; i
++) {
7679 packet
.init_techs
[i
] = n
->init_techs
[i
];
7681 fc_assert(ARRAY_SIZE(packet
.init_units
) == ARRAY_SIZE(n
->init_units
));
7682 for (i
= 0; i
< MAX_NUM_UNIT_LIST
; i
++) {
7683 const struct unit_type
*t
= n
->init_units
[i
];
7684 packet
.init_units
[i
] = t
? utype_number(t
) : U_LAST
;
7686 fc_assert(ARRAY_SIZE(packet
.init_buildings
)
7687 == ARRAY_SIZE(n
->init_buildings
));
7688 for (i
= 0; i
< MAX_NUM_BUILDING_LIST
; i
++) {
7689 /* Impr_type_id to int */
7690 packet
.init_buildings
[i
] = n
->init_buildings
[i
];
7693 lsend_packet_ruleset_nation(dest
, &packet
);
7694 } nations_iterate_end
;
7696 /* Send initial values of is_pickable */
7697 send_nation_availability(dest
, FALSE
);
7700 /**************************************************************************
7701 Send the nation style ruleset information (each style) to the specified
7703 **************************************************************************/
7704 static void send_ruleset_styles(struct conn_list
*dest
)
7706 struct packet_ruleset_style packet
;
7709 packet
.id
= style_index(s
);
7710 sz_strlcpy(packet
.name
, untranslated_name(&s
->name
));
7711 sz_strlcpy(packet
.rule_name
, rule_name_get(&s
->name
));
7713 lsend_packet_ruleset_style(dest
, &packet
);
7714 } styles_iterate_end
;
7717 /**************************************************************************
7718 Send the multiplier ruleset information to the specified
7720 **************************************************************************/
7721 static void send_ruleset_multipliers(struct conn_list
*dest
)
7723 char helptext
[MAX_LEN_PACKET
];
7725 multipliers_iterate(pmul
) {
7726 PACKET_STRVEC_COMPUTE(helptext
, pmul
->helptext
);
7728 dlsend_packet_ruleset_multiplier(dest
, multiplier_number(pmul
),
7729 pmul
->start
, pmul
->stop
,
7730 pmul
->step
, pmul
->def
,
7731 pmul
->offset
, pmul
->factor
,
7732 untranslated_name(&pmul
->name
),
7733 rule_name_get(&pmul
->name
),
7735 } multipliers_iterate_end
;
7738 /**************************************************************************
7739 Send the city-style ruleset information (each style) to the specified
7741 **************************************************************************/
7742 static void send_ruleset_cities(struct conn_list
*dest
)
7744 struct packet_ruleset_city city_p
;
7747 for (k
= 0; k
< game
.control
.styles_count
; k
++) {
7748 city_p
.style_id
= k
;
7751 requirement_vector_iterate(&city_styles
[k
].reqs
, preq
) {
7752 city_p
.reqs
[j
++] = *preq
;
7753 } requirement_vector_iterate_end
;
7754 city_p
.reqs_count
= j
;
7756 sz_strlcpy(city_p
.name
, untranslated_name(&city_styles
[k
].name
));
7757 sz_strlcpy(city_p
.rule_name
, rule_name_get(&city_styles
[k
].name
));
7758 sz_strlcpy(city_p
.graphic
, city_styles
[k
].graphic
);
7759 sz_strlcpy(city_p
.graphic_alt
, city_styles
[k
].graphic_alt
);
7760 sz_strlcpy(city_p
.citizens_graphic
, city_styles
[k
].citizens_graphic
);
7761 sz_strlcpy(city_p
.citizens_graphic_alt
,
7762 city_styles
[k
].citizens_graphic_alt
);
7764 lsend_packet_ruleset_city(dest
, &city_p
);
7768 /**************************************************************************
7769 Send the music-style ruleset information (each style) to the specified
7771 **************************************************************************/
7772 static void send_ruleset_musics(struct conn_list
*dest
)
7774 struct packet_ruleset_music packet
;
7776 music_styles_iterate(pmus
) {
7779 packet
.id
= pmus
->id
;
7781 sz_strlcpy(packet
.music_peaceful
, pmus
->music_peaceful
);
7782 sz_strlcpy(packet
.music_combat
, pmus
->music_combat
);
7785 requirement_vector_iterate(&(pmus
->reqs
), preq
) {
7786 packet
.reqs
[j
++] = *preq
;
7787 } requirement_vector_iterate_end
;
7788 packet
.reqs_count
= j
;
7790 lsend_packet_ruleset_music(dest
, &packet
);
7791 } music_styles_iterate_end
;
7794 /**************************************************************************
7795 Send information in packet_ruleset_game (miscellaneous rules) to the
7796 specified connections.
7797 **************************************************************************/
7798 static void send_ruleset_game(struct conn_list
*dest
)
7800 struct packet_ruleset_game misc_p
;
7803 fc_assert_ret(game
.veteran
!= NULL
);
7805 /* Per unit veteran system definition. */
7806 misc_p
.veteran_levels
= game
.veteran
->levels
;
7808 for (i
= 0; i
< misc_p
.veteran_levels
; i
++) {
7809 const struct veteran_level
*vlevel
= game
.veteran
->definitions
+ i
;
7811 sz_strlcpy(misc_p
.veteran_name
[i
], untranslated_name(&vlevel
->name
));
7812 misc_p
.power_fact
[i
] = vlevel
->power_fact
;
7813 misc_p
.move_bonus
[i
] = vlevel
->move_bonus
;
7816 fc_assert(sizeof(misc_p
.global_init_techs
)
7817 == sizeof(game
.rgame
.global_init_techs
));
7818 fc_assert(ARRAY_SIZE(misc_p
.global_init_techs
)
7819 == ARRAY_SIZE(game
.rgame
.global_init_techs
));
7820 memcpy(misc_p
.global_init_techs
, game
.rgame
.global_init_techs
,
7821 sizeof(misc_p
.global_init_techs
));
7823 fc_assert(ARRAY_SIZE(misc_p
.global_init_buildings
)
7824 == ARRAY_SIZE(game
.rgame
.global_init_buildings
));
7825 for (i
= 0; i
< MAX_NUM_BUILDING_LIST
; i
++) {
7826 /* Impr_type_id to int */
7827 misc_p
.global_init_buildings
[i
] =
7828 game
.rgame
.global_init_buildings
[i
];
7831 misc_p
.default_specialist
= DEFAULT_SPECIALIST
;
7833 fc_assert_ret(game
.plr_bg_color
!= NULL
);
7835 misc_p
.background_red
= game
.plr_bg_color
->r
;
7836 misc_p
.background_green
= game
.plr_bg_color
->g
;
7837 misc_p
.background_blue
= game
.plr_bg_color
->b
;
7839 lsend_packet_ruleset_game(dest
, &misc_p
);
7842 /**************************************************************************
7843 Send all team names defined in the ruleset file(s) to the
7844 specified connections.
7845 **************************************************************************/
7846 static void send_ruleset_team_names(struct conn_list
*dest
)
7848 struct packet_team_name_info team_name_info_p
;
7850 team_slots_iterate(tslot
) {
7851 const char *name
= team_slot_defined_name(tslot
);
7854 /* End of defined names. */
7858 team_name_info_p
.team_id
= team_slot_index(tslot
);
7859 sz_strlcpy(team_name_info_p
.team_name
, name
);
7861 lsend_packet_team_name_info(dest
, &team_name_info_p
);
7862 } team_slots_iterate_end
;
7865 /**************************************************************************
7866 Make it clear to everyone that requested ruleset has not been loaded.
7867 **************************************************************************/
7868 static void notify_ruleset_fallback(const char *msg
)
7870 notify_conn(NULL
, NULL
, E_LOG_FATAL
, ftc_warning
, "%s", msg
);
7873 /**************************************************************************
7875 **************************************************************************/
7876 bool load_rulesets(const char *restore
, bool compat_mode
,
7877 bool act
, bool buffer_script
)
7879 if (load_rulesetdir(game
.server
.rulesetdir
, compat_mode
, act
, buffer_script
)) {
7883 /* Fallback to previous one. */
7884 if (restore
!= NULL
) {
7885 if (load_rulesetdir(restore
, compat_mode
, act
, buffer_script
)) {
7886 sz_strlcpy(game
.server
.rulesetdir
, restore
);
7888 notify_ruleset_fallback(_("Ruleset couldn't be loaded. Keeping previous one."));
7890 /* We're in sane state as restoring previous ruleset succeeded,
7891 * but return failure to indicate that this is not what caller
7897 /* Fallback to default one, but not if that's what we tried already */
7898 if (strcmp(GAME_DEFAULT_RULESETDIR
, game
.server
.rulesetdir
)
7899 && (restore
== NULL
|| strcmp(GAME_DEFAULT_RULESETDIR
, restore
))) {
7900 if (load_rulesetdir(GAME_DEFAULT_RULESETDIR
, FALSE
, act
, buffer_script
)) {
7901 /* We're in sane state as fallback ruleset loading succeeded,
7902 * but return failure to indicate that this is not what caller
7904 sz_strlcpy(game
.server
.rulesetdir
, GAME_DEFAULT_RULESETDIR
);
7906 notify_ruleset_fallback(_("Ruleset couldn't be loaded. Switching to default one."));
7913 log_normal(_("Cannot load any ruleset. Freeciv-web ruleset is available from "
7914 "https://github.com/freeciv/freeciv-web"));
7915 #endif /* FREECIV_WEB */
7917 /* Cannot load even default ruleset, we're in completely unusable state */
7921 /**************************************************************************
7922 destroy secfile. Handle NULL parameter gracefully.
7923 **************************************************************************/
7924 static void nullcheck_secfile_destroy(struct section_file
*file
)
7927 secfile_destroy(file
);
7931 /**************************************************************************
7932 Completely deinitialize ruleset system. Server is not in usable
7934 **************************************************************************/
7935 void rulesets_deinit(void)
7937 script_server_free();
7938 requirement_vector_free(&reqs_list
);
7941 /**************************************************************************
7942 Loads the rulesets from directory.
7943 This may be called more than once and it will free any stale data.
7944 **************************************************************************/
7945 static bool load_rulesetdir(const char *rsdir
, bool compat_mode
,
7946 bool act
, bool buffer_script
)
7948 struct section_file
*techfile
, *unitfile
, *buildfile
, *govfile
, *terrfile
;
7949 struct section_file
*stylefile
, *cityfile
, *nationfile
, *effectfile
, *gamefile
;
7951 struct rscompat_info compat_info
;
7953 log_normal(_("Loading rulesets."));
7955 rscompat_init_info(&compat_info
);
7956 compat_info
.compat_mode
= compat_mode
;
7958 game_ruleset_free();
7959 /* Reset the list of available player colors. */
7962 game_ruleset_init();
7964 if (script_buffer
!= NULL
) {
7965 FC_FREE(script_buffer
);
7966 script_buffer
= NULL
;
7969 server
.playable_nations
= 0;
7971 techfile
= openload_ruleset_file("techs", rsdir
);
7972 buildfile
= openload_ruleset_file("buildings", rsdir
);
7973 govfile
= openload_ruleset_file("governments", rsdir
);
7974 unitfile
= openload_ruleset_file("units", rsdir
);
7975 terrfile
= openload_ruleset_file("terrain", rsdir
);
7976 stylefile
= openload_ruleset_file("styles", rsdir
);
7977 cityfile
= openload_ruleset_file("cities", rsdir
);
7978 nationfile
= openload_ruleset_file("nations", rsdir
);
7979 effectfile
= openload_ruleset_file("effects", rsdir
);
7980 gamefile
= openload_ruleset_file("game", rsdir
);
7982 if (techfile
== NULL
7983 || buildfile
== NULL
7987 || stylefile
== NULL
7989 || nationfile
== NULL
7990 || effectfile
== NULL
7991 || gamefile
== NULL
) {
7996 ok
= load_game_names(gamefile
, &compat_info
)
7997 && load_tech_names(techfile
, &compat_info
)
7998 && load_building_names(buildfile
, &compat_info
)
7999 && load_government_names(govfile
, &compat_info
)
8000 && load_unit_names(unitfile
, &compat_info
)
8001 && load_terrain_names(terrfile
, &compat_info
)
8002 && load_style_names(stylefile
, &compat_info
)
8003 && load_nation_names(nationfile
, &compat_info
);
8007 ok
= rscompat_names(&compat_info
);
8011 ok
= load_ruleset_techs(techfile
, &compat_info
);
8014 ok
= load_ruleset_styles(stylefile
, &compat_info
);
8017 ok
= load_ruleset_cities(cityfile
, &compat_info
);
8020 ok
= load_ruleset_governments(govfile
, &compat_info
);
8023 /* terrain must precede nations and units */
8024 ok
= load_ruleset_terrain(terrfile
, &compat_info
);
8027 ok
= load_ruleset_units(unitfile
, &compat_info
);
8030 ok
= load_ruleset_buildings(buildfile
, &compat_info
);
8033 ok
= load_ruleset_nations(nationfile
, &compat_info
);
8036 ok
= load_ruleset_effects(effectfile
, &compat_info
);
8039 ok
= load_ruleset_game(gamefile
, act
, &compat_info
);
8043 /* Init nations we just loaded. */
8044 update_nations_with_startpos();
8046 /* Needed by role_unit_precalcs(). */
8047 unit_type_action_cache_init();
8049 /* Prepare caches we want to sanity check. */
8050 role_unit_precalcs();
8051 road_integrators_cache_init();
8052 actions_rs_pre_san_gen();
8054 ok
= autoadjust_ruleset_data()
8055 && sanity_check_ruleset_data(compat_info
.compat_mode
);
8059 /* Only load settings for a sane ruleset */
8060 ok
= settings_ruleset(gamefile
, "settings", act
);
8063 secfile_check_unused(gamefile
);
8067 nullcheck_secfile_destroy(techfile
);
8068 nullcheck_secfile_destroy(stylefile
);
8069 nullcheck_secfile_destroy(cityfile
);
8070 nullcheck_secfile_destroy(govfile
);
8071 nullcheck_secfile_destroy(terrfile
);
8072 nullcheck_secfile_destroy(unitfile
);
8073 nullcheck_secfile_destroy(buildfile
);
8074 nullcheck_secfile_destroy(nationfile
);
8075 nullcheck_secfile_destroy(effectfile
);
8076 nullcheck_secfile_destroy(gamefile
);
8078 if (extra_sections
) {
8079 free(extra_sections
);
8080 extra_sections
= NULL
;
8082 if (base_sections
) {
8083 free(base_sections
);
8084 base_sections
= NULL
;
8086 if (road_sections
) {
8087 free(road_sections
);
8088 road_sections
= NULL
;
8090 if (resource_sections
) {
8091 free(resource_sections
);
8092 resource_sections
= NULL
;
8094 if (terrain_sections
) {
8095 free(terrain_sections
);
8096 terrain_sections
= NULL
;
8100 rscompat_postprocess(&compat_info
);
8105 char **buffer
= buffer_script
? &script_buffer
: NULL
;
8107 script_server_free();
8109 script_server_init();
8111 ok
= openload_script_file("script", rsdir
, buffer
);
8114 if (ok
&& !buffer_script
) {
8115 ok
= openload_script_file("default", rsdir
, NULL
);
8119 /* Populate remaining caches. */
8120 techs_precalc_data();
8121 improvement_feature_cache_init();
8122 unit_class_iterate(pclass
) {
8123 set_unit_class_caches(pclass
);
8124 } unit_class_iterate_end
;
8125 unit_type_iterate(ptype
) {
8126 ptype
->unknown_move_cost
= utype_unknown_move_cost(ptype
);
8127 set_unit_type_caches(ptype
);
8128 } unit_type_iterate_end
;
8129 city_production_caravan_shields_init();
8131 /* Build advisors unit class cache corresponding to loaded rulesets */
8132 adv_units_ruleset_init();
8133 CALL_FUNC_EACH_AI(units_ruleset_init
);
8135 /* We may need to adjust the number of AI players
8136 * if the number of available nations changed. */
8137 (void) aifill(game
.info
.aifill
);
8143 /**************************************************************************
8144 Reload the game settings saved in the ruleset file.
8145 **************************************************************************/
8146 bool reload_rulesets_settings(void)
8148 struct section_file
*file
;
8151 file
= openload_ruleset_file("game", game
.server
.rulesetdir
);
8153 ruleset_error(LOG_ERROR
, "Could not load game.ruleset:\n%s",
8158 settings_ruleset(file
, "settings", TRUE
);
8159 secfile_destroy(file
);
8165 /**************************************************************************
8166 Send all ruleset information to the specified connections.
8167 **************************************************************************/
8168 void send_rulesets(struct conn_list
*dest
)
8170 conn_list_compression_freeze(dest
);
8172 /* ruleset_control also indicates to client that ruleset sending starts. */
8173 send_ruleset_control(dest
);
8175 send_ruleset_game(dest
);
8176 send_ruleset_disasters(dest
);
8177 send_ruleset_achievements(dest
);
8178 send_ruleset_trade_routes(dest
);
8179 send_ruleset_team_names(dest
);
8180 send_ruleset_actions(dest
);
8181 send_ruleset_action_enablers(dest
);
8182 send_ruleset_action_auto_performers(dest
);
8183 send_ruleset_tech_classes(dest
);
8184 send_ruleset_techs(dest
);
8185 send_ruleset_governments(dest
);
8186 send_ruleset_unit_classes(dest
);
8187 send_ruleset_units(dest
);
8188 send_ruleset_specialists(dest
);
8189 send_ruleset_extras(dest
);
8190 send_ruleset_bases(dest
);
8191 send_ruleset_roads(dest
);
8192 send_ruleset_resources(dest
);
8193 send_ruleset_terrain(dest
);
8194 send_ruleset_goods(dest
);
8195 send_ruleset_buildings(dest
);
8196 send_ruleset_nations(dest
);
8197 send_ruleset_styles(dest
);
8198 send_ruleset_cities(dest
);
8199 send_ruleset_multipliers(dest
);
8200 send_ruleset_musics(dest
);
8201 send_ruleset_cache(dest
);
8203 /* Indicate client that all rulesets have now been sent. */
8204 lsend_packet_rulesets_ready(dest
);
8206 /* changed game settings will be send in
8207 * connecthand.c:establish_new_connection() */
8209 conn_list_compression_thaw(dest
);