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"
30 #include "string_vector.h"
36 #include "capability.h"
40 #include "featured_text.h"
42 #include "government.h"
45 #include "name_translation.h"
49 #include "requirements.h"
52 #include "specialist.h"
54 #include "traderoutes.h"
59 #include "citytools.h"
67 #include "advruleset.h"
69 /* server/scripting */
70 #include "script_server.h"
75 #define RULESET_CAPABILITIES "+Freeciv-2.5-ruleset"
77 * Ruleset capabilities acceptable to this program:
79 * +Freeciv-2.3-ruleset
80 * - basic ruleset format for Freeciv versions 2.3.x; required
82 * +Freeciv-tilespec-Devel-YYYY.MMM.DD
83 * - ruleset of the development version at the given data
86 /* RULESET_SUFFIX already used, no leading dot here */
87 #define RULES_SUFFIX "ruleset"
88 #define SCRIPT_SUFFIX "lua"
90 #define ADVANCE_SECTION_PREFIX "advance_"
91 #define BUILDING_SECTION_PREFIX "building_"
92 #define CITYSTYLE_SECTION_PREFIX "citystyle_"
93 #define EFFECT_SECTION_PREFIX "effect_"
94 #define GOVERNMENT_SECTION_PREFIX "government_"
95 #define NATION_SET_SECTION_PREFIX "nset" /* without underscore? */
96 #define NATION_GROUP_SECTION_PREFIX "ngroup" /* without underscore? */
97 #define NATION_SECTION_PREFIX "nation" /* without underscore? */
98 #define RESOURCE_SECTION_PREFIX "resource_"
99 #define BASE_SECTION_PREFIX "base_"
100 #define ROAD_SECTION_PREFIX "road_"
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_"
107 #define check_name(name) (check_strlen(name, MAX_LEN_NAME, NULL))
109 /* avoid re-reading files */
110 static const char name_too_long
[] = "Name \"%s\" too long; truncating.";
111 #define MAX_SECTION_LABEL 64
112 #define section_strlcpy(dst, src) \
113 (void) loud_strlcpy(dst, src, MAX_SECTION_LABEL, name_too_long)
114 static char *resource_sections
= NULL
;
115 static char *terrain_sections
= NULL
;
116 static char *base_sections
= NULL
;
117 static char *road_sections
= NULL
;
119 static bool load_rulesetdir(const char *rsdir
, bool act
);
120 static struct section_file
*openload_ruleset_file(const char *whichset
,
122 static const char *check_ruleset_capabilities(struct section_file
*file
,
123 const char *us_capstr
,
124 const char *filename
);
126 static bool load_tech_names(struct section_file
*file
);
127 static bool load_unit_names(struct section_file
*file
);
128 static bool load_building_names(struct section_file
*file
);
129 static bool load_government_names(struct section_file
*file
);
130 static bool load_terrain_names(struct section_file
*file
);
131 static bool load_citystyle_names(struct section_file
*file
);
132 static bool load_nation_names(struct section_file
*file
);
133 static bool load_city_name_list(struct section_file
*file
,
134 struct nation_type
*pnation
,
135 const char *secfile_str1
,
136 const char *secfile_str2
,
137 const char **allowed_terrains
,
140 static bool load_ruleset_techs(struct section_file
*file
);
141 static bool load_ruleset_units(struct section_file
*file
);
142 static bool load_ruleset_buildings(struct section_file
*file
);
143 static bool load_ruleset_governments(struct section_file
*file
);
144 static bool load_ruleset_terrain(struct section_file
*file
);
145 static bool load_ruleset_cities(struct section_file
*file
);
146 static bool load_ruleset_effects(struct section_file
*file
);
148 static bool load_ruleset_game(const char *rsdir
, bool act
);
150 static void send_ruleset_techs(struct conn_list
*dest
);
151 static void send_ruleset_unit_classes(struct conn_list
*dest
);
152 static void send_ruleset_units(struct conn_list
*dest
);
153 static void send_ruleset_buildings(struct conn_list
*dest
);
154 static void send_ruleset_terrain(struct conn_list
*dest
);
155 static void send_ruleset_resources(struct conn_list
*dest
);
156 static void send_ruleset_bases(struct conn_list
*dest
);
157 static void send_ruleset_roads(struct conn_list
*dest
);
158 static void send_ruleset_governments(struct conn_list
*dest
);
159 static void send_ruleset_cities(struct conn_list
*dest
);
160 static void send_ruleset_game(struct conn_list
*dest
);
161 static void send_ruleset_team_names(struct conn_list
*dest
);
163 static bool load_ruleset_veteran(struct section_file
*file
,
165 struct veteran_system
**vsystem
, char *err
,
169 /**************************************************************************
170 Notifications about ruleset errors to clients. Especially important in
171 case of internal server crashing.
172 **************************************************************************/
173 void ruleset_error_real(const char *file
, const char *function
,
174 int line
, enum log_level level
,
175 const char *format
, ...)
179 va_start(args
, format
);
180 vdo_log(file
, function
, line
, FALSE
, level
, format
, args
);
183 if (LOG_FATAL
>= level
) {
188 /**************************************************************************
189 datafilename() wrapper: tries to match in two ways.
190 Returns NULL on failure, the (statically allocated) filename on success.
191 **************************************************************************/
192 static const char *valid_ruleset_filename(const char *subdir
,
194 const char *extension
)
197 const char *dfilename
;
199 fc_assert_ret_val(subdir
&& name
&& extension
, NULL
);
201 fc_snprintf(filename
, sizeof(filename
), "%s/%s.%s",
202 subdir
, name
, extension
);
203 log_verbose("Trying \"%s\".", filename
);
204 dfilename
= fileinfoname(get_data_dirs(), filename
);
209 fc_snprintf(filename
, sizeof(filename
), "default/%s.%s", name
, extension
);
210 log_verbose("Trying \"%s\": default ruleset directory.", filename
);
211 dfilename
= fileinfoname(get_data_dirs(), filename
);
216 fc_snprintf(filename
, sizeof(filename
), "%s_%s.%s",
217 subdir
, name
, extension
);
218 log_verbose("Trying \"%s\": alternative ruleset filename syntax.",
220 dfilename
= fileinfoname(get_data_dirs(), filename
);
224 ruleset_error(LOG_ERROR
,
225 /* TRANS: message about an installation error. */
226 _("Could not find a readable \"%s.%s\" ruleset file."),
233 /**************************************************************************
234 Do initial section_file_load on a ruleset file.
235 "whichset" = "techs", "units", "buildings", "terrain", ...
236 **************************************************************************/
237 static struct section_file
*openload_ruleset_file(const char *whichset
,
241 const char *dfilename
= valid_ruleset_filename(rsdir
, whichset
,
243 struct section_file
*secfile
;
245 if (dfilename
== NULL
) {
249 /* Need to save a copy of the filename for following message, since
250 section_file_load() may call datafilename() for includes. */
251 sz_strlcpy(sfilename
, dfilename
);
252 secfile
= secfile_load(sfilename
, FALSE
);
254 if (secfile
== NULL
) {
255 ruleset_error(LOG_ERROR
, "Could not load ruleset '%s':\n%s",
256 sfilename
, secfile_error());
262 /**************************************************************************
264 **************************************************************************/
265 static bool openload_script_file(const char *whichset
, const char *rsdir
)
267 const char *dfilename
= valid_ruleset_filename(rsdir
, whichset
,
270 if (dfilename
== NULL
) {
274 if (!script_server_do_file(NULL
, dfilename
)) {
275 ruleset_error(LOG_ERROR
, "\"%s\": could not load ruleset script.",
284 /**************************************************************************
285 Ruleset files should have a capabilities string datafile.options
286 This gets and returns that string, and checks that the required
287 capabilities specified are satisified.
288 **************************************************************************/
289 static const char *check_ruleset_capabilities(struct section_file
*file
,
290 const char *us_capstr
,
291 const char *filename
)
293 const char *datafile_options
;
295 if (!(datafile_options
= secfile_lookup_str(file
, "datafile.options"))) {
296 log_fatal("\"%s\": ruleset capability problem:", filename
);
297 ruleset_error(LOG_ERROR
, "%s", secfile_error());
301 if (!has_capabilities(us_capstr
, datafile_options
)) {
302 log_fatal("\"%s\": ruleset datafile appears incompatible:", filename
);
303 log_fatal(" datafile options: %s", datafile_options
);
304 log_fatal(" supported options: %s", us_capstr
);
305 ruleset_error(LOG_ERROR
, "Capability problem");
309 if (!has_capabilities(datafile_options
, us_capstr
)) {
310 log_fatal("\"%s\": ruleset datafile claims required option(s)"
311 " that we don't support:", filename
);
312 log_fatal(" datafile options: %s", datafile_options
);
313 log_fatal(" supported options: %s", us_capstr
);
314 ruleset_error(LOG_ERROR
, "Capability problem");
318 return datafile_options
;
321 /**************************************************************************
322 Load a requirement list. The list is returned as a static vector
323 (callers need not worry about freeing anything).
324 **************************************************************************/
325 static struct requirement_vector
*lookup_req_list(struct section_file
*file
,
330 const char *type
, *name
;
332 const char *filename
;
333 static struct requirement_vector list
;
335 filename
= secfile_name(file
);
337 requirement_vector_reserve(&list
, 0);
339 for (j
= 0; (type
= secfile_lookup_str_default(file
, NULL
, "%s.%s%d.type",
340 sec
, sub
, j
)); j
++) {
341 char buf
[MAX_LEN_NAME
];
343 bool survives
, negated
;
344 struct entry
*pentry
;
345 struct requirement req
;
347 if (!(pentry
= secfile_entry_lookup(file
, "%s.%s%d.name",
349 ruleset_error(LOG_ERROR
, "%s", secfile_error());
354 switch (entry_type(pentry
)) {
359 if (entry_bool_get(pentry
, &val
)) {
360 fc_snprintf(buf
, sizeof(buf
), "%d", val
);
369 if (entry_int_get(pentry
, &val
)) {
370 fc_snprintf(buf
, sizeof(buf
), "%d", val
);
376 (void) entry_str_get(pentry
, &name
);
380 ruleset_error(LOG_ERROR
,
381 "\"%s\": error in handling requirement name for '%s.%s%d'.",
382 filename
, sec
, sub
, j
);
386 if (!(range
= secfile_lookup_str(file
, "%s.%s%d.range", sec
, sub
, j
))) {
387 ruleset_error(LOG_ERROR
, "%s", secfile_error());
393 if ((pentry
= secfile_entry_lookup(file
, "%s.%s%d.survives",
395 && !entry_bool_get(pentry
, &survives
)) {
396 ruleset_error(LOG_ERROR
,
397 "\"%s\": invalid boolean value for survives for "
398 "'%s.%s%d'.", filename
, sec
, sub
, j
);
402 if ((pentry
= secfile_entry_lookup(file
, "%s.%s%d.negated",
404 && !entry_bool_get(pentry
, &negated
)) {
405 ruleset_error(LOG_ERROR
,
406 "\"%s\": invalid boolean value for negated for "
407 "'%s.%s%d'.", filename
, sec
, sub
, j
);
410 req
= req_from_str(type
, range
, survives
, negated
, name
);
411 if (req
.source
.kind
== universals_n_invalid()) {
412 ruleset_error(LOG_ERROR
, "\"%s\" [%s] has invalid or unknown req: "
414 filename
, sec
, type
, name
);
419 requirement_vector_append(&list
, req
);
422 if (j
> MAX_NUM_REQS
) {
423 ruleset_error(LOG_ERROR
, "Too many (%d) requirements for %s. Max is %d",
424 j
, rfor
, MAX_NUM_REQS
);
432 /**************************************************************************
433 Load combat bonus list
434 **************************************************************************/
435 static bool lookup_cbonus_list(struct combat_bonus_list
*list
,
436 struct section_file
*file
,
442 const char *filename
;
445 filename
= secfile_name(file
);
447 for (j
= 0; (flag
= secfile_lookup_str_default(file
, NULL
, "%s.%s%d.flag",
448 sec
, sub
, j
)); j
++) {
449 struct combat_bonus
*bonus
= fc_malloc(sizeof(*bonus
));
452 bonus
->flag
= unit_type_flag_id_by_name(flag
, fc_strcasecmp
);
453 if (!unit_type_flag_id_is_valid(bonus
->flag
)) {
454 log_error("\"%s\": unknown flag name \"%s\" in '%s.%s'.",
455 filename
, flag
, sec
, sub
);
460 type
= secfile_lookup_str(file
, "%s.%s%d.type", sec
, sub
, j
);
461 bonus
->type
= combat_bonus_type_by_name(type
, fc_strcasecmp
);
462 if (!combat_bonus_type_is_valid(bonus
->type
)) {
463 log_error("\"%s\": unknown bonus type \"%s\" in '%s.%s'.",
464 filename
, type
, sec
, sub
);
469 if (!secfile_lookup_int(file
, &bonus
->value
, "%s.%s%d.value",
471 log_error("\"%s\": failed to get value from '%s.%s%d'.",
472 filename
, sec
, sub
, j
);
477 combat_bonus_list_append(list
, bonus
);
483 /**************************************************************************
484 Lookup a string prefix.entry in the file and return the corresponding
485 advances pointer. If (!required), return A_NEVER for match "Never" or
486 can't match. If (required), die when can't match. Note the first tech
487 should have name "None" so that will always match.
488 If description is not NULL, it is used in the warning message
489 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
490 **************************************************************************/
491 static bool lookup_tech(struct section_file
*file
,
492 struct advance
**result
,
493 const char *prefix
, const char *entry
,
494 const char *filename
,
495 const char *description
)
499 sval
= secfile_lookup_str_default(file
, NULL
, "%s.%s", prefix
, entry
);
500 if (!sval
|| !strcmp(sval
, "Never")) {
503 *result
= advance_by_rule_name(sval
);
505 if (A_NEVER
== *result
) {
506 ruleset_error(LOG_ERROR
,
507 "\"%s\" %s %s: couldn't match \"%s\".",
508 filename
, (description
? description
: prefix
), entry
, sval
);
516 /**************************************************************************
517 Lookup a string prefix.entry in the file and return the corresponding
518 improvement pointer. If (!required), return B_NEVER for match "None" or
519 can't match. If (required), die when can't match.
520 If description is not NULL, it is used in the warning message
521 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
522 **************************************************************************/
523 static bool lookup_building(struct section_file
*file
,
524 const char *prefix
, const char *entry
,
525 struct impr_type
**result
,
526 const char *filename
,
527 const char *description
)
532 sval
= secfile_lookup_str_default(file
, NULL
, "%s.%s", prefix
, entry
);
533 if (!sval
|| strcmp(sval
, "None") == 0) {
536 *result
= improvement_by_rule_name(sval
);
538 if (B_NEVER
== *result
) {
539 ruleset_error(LOG_ERROR
,
540 "\"%s\" %s %s: couldn't match \"%s\".",
541 filename
, (description
? description
: prefix
), entry
, sval
);
549 /**************************************************************************
550 Lookup a prefix.entry string vector in the file and fill in the
551 array, which should hold MAX_NUM_UNIT_LIST items. The output array is
552 either NULL terminated or full (contains MAX_NUM_UNIT_LIST
553 items). If the vector is not found and the required parameter is set,
554 we report it as an error, otherwise we just punt.
555 **************************************************************************/
556 static bool lookup_unit_list(struct section_file
*file
, const char *prefix
,
558 struct unit_type
**output
,
559 const char *filename
)
566 /* pre-fill with NULL: */
567 for(i
= 0; i
< MAX_NUM_UNIT_LIST
; i
++) {
570 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.%s", prefix
, entry
);
572 ruleset_error(LOG_ERROR
, "\"%s\": missing string vector %s.%s",
573 filename
, prefix
, entry
);
576 if (nval
> MAX_NUM_UNIT_LIST
) {
577 ruleset_error(LOG_ERROR
,
578 "\"%s\": string vector %s.%s too long (%d, max %d)",
579 filename
, prefix
, entry
, (int) nval
, MAX_NUM_UNIT_LIST
);
581 } else if (nval
== 1 && strcmp(slist
[0], "") == 0) {
586 for (i
= 0; i
< nval
; i
++) {
587 const char *sval
= slist
[i
];
588 struct unit_type
*punittype
= unit_type_by_rule_name(sval
);
591 ruleset_error(LOG_ERROR
,
592 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
593 filename
, prefix
, entry
, i
, sval
);
597 output
[i
] = punittype
;
598 log_debug("\"%s\" %s.%s (%d): %s (%d)", filename
, prefix
, entry
, i
, sval
,
599 utype_number(punittype
));
607 /**************************************************************************
608 Lookup a prefix.entry string vector in the file and fill in the
609 array, which should hold MAX_NUM_TECH_LIST items. The output array is
610 either A_LAST terminated or full (contains MAX_NUM_TECH_LIST
611 items). All valid entries of the output array are guaranteed to
612 exist. There should be at least one value, but it may be "",
614 **************************************************************************/
615 static bool lookup_tech_list(struct section_file
*file
, const char *prefix
,
616 const char *entry
, int *output
,
617 const char *filename
)
624 /* pre-fill with A_LAST: */
625 for (i
= 0; i
< MAX_NUM_TECH_LIST
; i
++) {
628 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.%s", prefix
, entry
);
629 if (slist
== NULL
|| nval
== 0) {
630 ruleset_error(LOG_ERROR
, "\"%s\": missing string vector %s.%s",
631 filename
, prefix
, entry
);
633 } else if (nval
> MAX_NUM_TECH_LIST
) {
634 ruleset_error(LOG_ERROR
,
635 "\"%s\": string vector %s.%s too long (%d, max %d)",
636 filename
, prefix
, entry
, (int) nval
, MAX_NUM_TECH_LIST
);
641 if (nval
== 1 && strcmp(slist
[0], "") == 0) {
645 for (i
= 0; i
< nval
&& ok
; i
++) {
646 const char *sval
= slist
[i
];
647 struct advance
*padvance
= advance_by_rule_name(sval
);
649 if (NULL
== padvance
) {
650 ruleset_error(LOG_ERROR
,
651 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
652 filename
, prefix
, entry
, i
, sval
);
655 if (!valid_advance(padvance
)) {
656 ruleset_error(LOG_ERROR
, "\"%s\" %s.%s (%d): \"%s\" is removed.",
657 filename
, prefix
, entry
, i
, sval
);
662 output
[i
] = advance_number(padvance
);
663 log_debug("\"%s\" %s.%s (%d): %s (%d)", filename
, prefix
, entry
, i
, sval
,
664 advance_number(padvance
));
673 /**************************************************************************
674 Lookup a prefix.entry string vector in the file and fill in the
675 array, which should hold MAX_NUM_BUILDING_LIST items. The output array is
676 either B_LAST terminated or full (contains MAX_NUM_BUILDING_LIST
677 items). [All valid entries of the output array are guaranteed to pass
678 improvement_exist()?] There should be at least one value, but it may be
679 "", meaning an empty list.
680 **************************************************************************/
681 static bool lookup_building_list(struct section_file
*file
,
682 const char *prefix
, const char *entry
,
683 int *output
, const char *filename
)
690 /* pre-fill with B_LAST: */
691 for (i
= 0; i
< MAX_NUM_BUILDING_LIST
; i
++) {
694 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.%s", prefix
, entry
);
696 ruleset_error(LOG_ERROR
, "\"%s\": missing string vector %s.%s",
697 filename
, prefix
, entry
);
699 } else if (nval
> MAX_NUM_BUILDING_LIST
) {
700 ruleset_error(LOG_ERROR
,
701 "\"%s\": string vector %s.%s too long (%d, max %d)",
702 filename
, prefix
, entry
, (int) nval
, MAX_NUM_BUILDING_LIST
);
704 } else if (nval
== 1 && strcmp(slist
[0], "") == 0) {
709 for (i
= 0; i
< nval
; i
++) {
710 const char *sval
= slist
[i
];
711 struct impr_type
*pimprove
= improvement_by_rule_name(sval
);
713 if (NULL
== pimprove
) {
714 ruleset_error(LOG_ERROR
,
715 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
716 filename
, prefix
, entry
, i
, sval
);
720 output
[i
] = improvement_number(pimprove
);
721 log_debug("%s.%s,%d %s %d", prefix
, entry
, i
, sval
, output
[i
]);
729 /**************************************************************************
730 Lookup a string prefix.entry in the file and set result to the corresponding
732 If description is not NULL, it is used in the warning message
733 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
734 **************************************************************************/
735 static bool lookup_unit_type(struct section_file
*file
,
738 struct unit_type
**result
,
739 const char *filename
,
740 const char *description
)
744 sval
= secfile_lookup_str_default(file
, "None", "%s.%s", prefix
, entry
);
746 if (strcmp(sval
, "None") == 0) {
749 *result
= unit_type_by_rule_name(sval
);
750 if (*result
== NULL
) {
751 ruleset_error(LOG_ERROR
,
752 "\"%s\" %s %s: couldn't match \"%s\".",
753 filename
, (description
? description
: prefix
), entry
, sval
);
762 /**************************************************************************
763 Lookup entry in the file and return the corresponding government index.
764 filename is for error message.
765 **************************************************************************/
766 static struct government
*lookup_government(struct section_file
*file
,
768 const char *filename
,
769 struct government
*fallback
)
772 struct government
*gov
;
774 sval
= secfile_lookup_str_default(file
, NULL
, "%s", entry
);
778 gov
= government_by_rule_name(sval
);
781 ruleset_error(LOG_ERROR
,
782 "\"%s\" %s: couldn't match \"%s\".",
783 filename
, entry
, sval
);
788 /**************************************************************************
789 Lookup entry in the file and return the corresponding move_type index.
790 Returns if success. Note that result can still be unit_move_type_invalid()
791 when the function success - it means move type is not explicitly given.
792 filename is for error message.
793 **************************************************************************/
794 static bool lookup_move_type(struct section_file
*file
,
796 enum unit_move_type
*result
,
797 const char *filename
)
800 enum unit_move_type mt
;
802 sval
= secfile_lookup_str_default(file
, NULL
, "%s", entry
);
804 *result
= unit_move_type_invalid();
808 mt
= unit_move_type_by_name(sval
, fc_strcasecmp
);
809 if (!unit_move_type_is_valid(mt
)) {
810 ruleset_error(LOG_ERROR
,
811 "\"%s\" %s: couldn't match \"%s\".",
812 filename
, entry
, sval
);
820 /**************************************************************************
821 What move types nativity of this road will give?
822 **************************************************************************/
823 static enum unit_move_type
move_type_from_road(struct road_type
*proad
,
824 struct unit_class
*puc
)
826 bool land_allowed
= TRUE
;
827 bool sea_allowed
= TRUE
;
829 if (!road_has_flag(proad
, RF_NATIVE_TILE
)) {
830 return unit_move_type_invalid();
832 if (!is_native_road_to_uclass(proad
, puc
)) {
833 return unit_move_type_invalid();
836 if (road_has_flag(proad
, RF_RIVER
)) {
837 /* Natural rivers are created to land only */
841 requirement_vector_iterate(&proad
->reqs
, preq
) {
842 if (preq
->source
.kind
== VUT_TERRAINCLASS
) {
844 if (preq
->source
.value
.terrainclass
== TC_LAND
) {
845 land_allowed
= FALSE
;
846 } else if (preq
->source
.value
.terrainclass
== TC_OCEAN
) {
850 if (preq
->source
.value
.terrainclass
== TC_LAND
) {
852 } else if (preq
->source
.value
.terrainclass
== TC_OCEAN
) {
853 land_allowed
= FALSE
;
856 } else if (preq
->source
.kind
== VUT_TERRAIN
) {
858 if (preq
->source
.value
.terrain
->tclass
== TC_LAND
) {
859 land_allowed
= FALSE
;
860 } else if (preq
->source
.value
.terrain
->tclass
== TC_OCEAN
) {
864 if (preq
->source
.value
.terrain
->tclass
== TC_LAND
) {
866 } else if (preq
->source
.value
.terrain
->tclass
== TC_OCEAN
) {
867 land_allowed
= FALSE
;
871 } requirement_vector_iterate_end
;
873 if (land_allowed
&& sea_allowed
) {
876 if (land_allowed
&& !sea_allowed
) {
879 if (!land_allowed
&& sea_allowed
) {
883 return unit_move_type_invalid();
886 /**************************************************************************
887 What move types nativity of this base will give?
888 **************************************************************************/
889 static enum unit_move_type
move_type_from_base(struct base_type
*pbase
,
890 struct unit_class
*puc
)
892 bool land_allowed
= TRUE
;
893 bool sea_allowed
= TRUE
;
895 if (!base_has_flag(pbase
, BF_NATIVE_TILE
)) {
896 return unit_move_type_invalid();
898 if (!is_native_base_to_uclass(pbase
, puc
)) {
899 return unit_move_type_invalid();
902 requirement_vector_iterate(&pbase
->reqs
, preq
) {
903 if (preq
->source
.kind
== VUT_TERRAINCLASS
) {
905 if (preq
->source
.value
.terrainclass
== TC_LAND
) {
906 land_allowed
= FALSE
;
907 } else if (preq
->source
.value
.terrainclass
== TC_OCEAN
) {
911 if (preq
->source
.value
.terrainclass
== TC_LAND
) {
913 } else if (preq
->source
.value
.terrainclass
== TC_OCEAN
) {
914 land_allowed
= FALSE
;
917 } else if (preq
->source
.kind
== VUT_TERRAIN
) {
919 if (preq
->source
.value
.terrain
->tclass
== TC_LAND
) {
920 land_allowed
= FALSE
;
921 } else if (preq
->source
.value
.terrain
->tclass
== TC_OCEAN
) {
925 if (preq
->source
.value
.terrain
->tclass
== TC_LAND
) {
927 } else if (preq
->source
.value
.terrain
->tclass
== TC_OCEAN
) {
928 land_allowed
= FALSE
;
932 } requirement_vector_iterate_end
;
934 if (land_allowed
&& sea_allowed
) {
937 if (land_allowed
&& !sea_allowed
) {
940 if (!land_allowed
&& sea_allowed
) {
944 return unit_move_type_invalid();
947 /****************************************************************************
948 Lookup optional string, returning allocated memory or NULL.
949 ****************************************************************************/
950 static char *lookup_string(struct section_file
*file
, const char *prefix
,
953 const char *sval
= secfile_lookup_str(file
, "%s.%s", prefix
, suffix
);
956 char copy
[strlen(sval
) + 1];
959 remove_leading_trailing_spaces(copy
);
960 if (strlen(copy
) > 0) {
961 return fc_strdup(copy
);
967 /****************************************************************************
968 Lookup optional string vector, returning allocated memory or NULL.
969 ****************************************************************************/
970 static struct strvec
*lookup_strvec(struct section_file
*file
,
971 const char *prefix
, const char *suffix
)
974 const char **vec
= secfile_lookup_str_vec(file
, &dim
,
975 "%s.%s", prefix
, suffix
);
978 struct strvec
*dest
= strvec_new();
980 strvec_store(dest
, vec
, dim
);
987 /**************************************************************************
988 Look up the resource section name and return its pointer.
989 **************************************************************************/
990 static struct resource
*lookup_resource(const char *filename
,
992 const char *jsection
)
994 resource_type_iterate(presource
) {
995 const int i
= resource_index(presource
);
996 const char *isection
= &resource_sections
[i
* MAX_SECTION_LABEL
];
997 if (0 == fc_strcasecmp(isection
, name
)) {
1000 } resource_type_iterate_end
;
1002 ruleset_error(LOG_ERROR
,
1003 "\"%s\" [%s] has unknown \"%s\".",
1010 /**************************************************************************
1011 Look up the terrain section name and return its pointer.
1012 **************************************************************************/
1013 static struct terrain
*lookup_terrain(struct section_file
*file
,
1015 struct terrain
*pthis
)
1017 const int j
= terrain_index(pthis
);
1018 const char *jsection
= &terrain_sections
[j
* MAX_SECTION_LABEL
];
1019 const char *name
= secfile_lookup_str(file
, "%s.%s", jsection
, item
);
1023 || (0 == strcmp(name
, "none"))
1024 || (0 == strcmp(name
, "no"))) {
1027 if (0 == strcmp(name
, "yes")) {
1031 terrain_type_iterate(pterrain
) {
1032 const int i
= terrain_index(pterrain
);
1033 const char *isection
= &terrain_sections
[i
* MAX_SECTION_LABEL
];
1034 if (0 == fc_strcasecmp(isection
, name
)) {
1037 } terrain_type_iterate_end
;
1039 ruleset_error(LOG_ERROR
, "\"%s\" [%s] has unknown \"%s\".",
1040 secfile_name(file
), jsection
, name
);
1044 /**************************************************************************
1045 Look up a value comparable to activity_count (road_time, etc).
1046 item_name describes the thing which has the time property, if non-NULL,
1047 for any error message.
1048 Returns FALSE if not found in secfile, but TRUE even if validation failed.
1049 Sets *ok to FALSE if validation failed, leaves it alone otherwise.
1050 **************************************************************************/
1051 static bool lookup_time(const struct section_file
*secfile
, int *time
,
1052 const char *sec_name
, const char *property_name
,
1053 const char *filename
, const char *item_name
,
1056 /* Assumes that PACKET_UNIT_INFO.activity_count in packets.def is UINT16 */
1057 const int max_time
= 65535 / ACTIVITY_FACTOR
;
1059 if (!secfile_lookup_int(secfile
, time
, "%s.%s", sec_name
, property_name
)) {
1063 if (*time
> max_time
) {
1064 ruleset_error(LOG_ERROR
,
1065 "\"%s\": \"%s\": \"%s\" value %d too large (max %d)",
1066 filename
, item_name
? item_name
: sec_name
,
1067 property_name
, *time
, max_time
);
1070 return TRUE
; /* we found _something */
1073 /**************************************************************************
1074 Load "name" and (optionally) "rule_name" into a struct name_translation.
1075 **************************************************************************/
1076 static bool ruleset_load_names(struct name_translation
*pname
,
1078 struct section_file
*file
,
1079 const char *sec_name
)
1081 const char *name
= secfile_lookup_str(file
, "%s.name", sec_name
);
1082 const char *rule_name
= secfile_lookup_str(file
, "%s.rule_name", sec_name
);
1085 ruleset_error(LOG_ERROR
,
1086 "\"%s\" [%s]: no \"name\" specified.",
1087 secfile_name(file
), sec_name
);
1091 names_set(pname
, domain
, name
, rule_name
);
1096 /**************************************************************************
1097 Load trait values to array.
1098 **************************************************************************/
1099 static void ruleset_load_traits(int *traits
, struct section_file
*file
,
1100 const char *secname
, const char *field_prefix
)
1104 /* FIXME: Use specenum trait names without duplicating them here.
1105 * Just needs to take care of case. */
1106 const char *trait_names
[] = {
1113 for (tr
= trait_begin(); tr
!= trait_end() && trait_names
[tr
] != NULL
; tr
= trait_next(tr
)) {
1114 traits
[tr
] = secfile_lookup_int_default(file
, -1, "%s.%s%s",
1120 fc_assert(tr
== trait_end()); /* number of trait_names correct */
1123 /**************************************************************************
1124 Load names of technologies so other rulesets can refer to techs with
1126 **************************************************************************/
1127 static bool load_tech_names(struct section_file
*file
)
1129 struct section_list
*sec
= NULL
;
1130 /* Number of techs in the ruleset (means without A_NONE). */
1133 const char *filename
= secfile_name(file
);
1137 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
1139 /* User tech flag names */
1140 for (i
= 0; (flag
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.name", i
)) ;
1142 const char *helptxt
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.helptxt",
1144 if (i
> MAX_NUM_USER_TECH_FLAGS
) {
1145 ruleset_error(LOG_ERROR
, "\"%s\": Too many user tech flags!",
1151 set_user_tech_flag_name(TECH_USER_1
+ i
, flag
, helptxt
);
1155 for (; i
< MAX_NUM_USER_TECH_FLAGS
; i
++) {
1156 set_user_tech_flag_name(TECH_USER_1
+ i
, NULL
, NULL
);
1160 sec
= secfile_sections_by_name_prefix(file
, ADVANCE_SECTION_PREFIX
);
1161 if (NULL
== sec
|| 0 == (num_techs
= section_list_size(sec
))) {
1162 ruleset_error(LOG_ERROR
, "\"%s\": No Advances?!?", filename
);
1165 log_verbose("%d advances (including possibly unused)", num_techs
);
1166 if (num_techs
+ A_FIRST
> A_LAST_REAL
) {
1167 ruleset_error(LOG_ERROR
, "\"%s\": Too many advances (%d, max %d)",
1168 filename
, num_techs
, A_LAST_REAL
-A_FIRST
);
1175 game
.control
.num_tech_types
= num_techs
+ A_FIRST
; /* includes A_NONE */
1178 advance_iterate(A_FIRST
, a
) {
1179 if (!ruleset_load_names(&a
->name
, NULL
, file
, section_name(section_list_get(sec
, i
)))) {
1184 } advance_iterate_end
;
1186 section_list_destroy(sec
);
1191 /**************************************************************************
1192 Load technologies related ruleset data
1193 **************************************************************************/
1194 static bool load_ruleset_techs(struct section_file
*file
)
1196 struct section_list
*sec
;
1198 struct advance
*a_none
= advance_by_number(A_NONE
);
1199 const char *filename
= secfile_name(file
);
1202 if (check_ruleset_capabilities(file
, RULESET_CAPABILITIES
, filename
) == NULL
) {
1205 sec
= secfile_sections_by_name_prefix(file
, ADVANCE_SECTION_PREFIX
);
1207 /* Initialize dummy tech A_NONE */
1208 a_none
->require
[AR_ONE
] = a_none
;
1209 a_none
->require
[AR_TWO
] = a_none
;
1210 a_none
->require
[AR_ROOT
] = A_NEVER
;
1211 BV_CLR_ALL(a_none
->flags
);
1214 advance_iterate(A_FIRST
, a
) {
1215 const char *sec_name
= section_name(section_list_get(sec
, i
));
1216 const char *sval
, **slist
;
1220 if (!lookup_tech(file
, &a
->require
[AR_ONE
], sec_name
, "req1",
1221 filename
, rule_name(&a
->name
))
1222 || !lookup_tech(file
, &a
->require
[AR_TWO
], sec_name
, "req2",
1223 filename
, rule_name(&a
->name
))
1224 || !lookup_tech(file
, &a
->require
[AR_ROOT
], sec_name
, "root_req",
1225 filename
, rule_name(&a
->name
))) {
1230 if ((A_NEVER
== a
->require
[AR_ONE
] && A_NEVER
!= a
->require
[AR_TWO
])
1231 || (A_NEVER
!= a
->require
[AR_ONE
] && A_NEVER
== a
->require
[AR_TWO
])) {
1232 ruleset_error(LOG_ERROR
, "\"%s\" [%s] \"%s\": \"Never\" with non-\"Never\".",
1233 filename
, sec_name
, rule_name(&a
->name
));
1237 if (a_none
== a
->require
[AR_ONE
] && a_none
!= a
->require
[AR_TWO
]) {
1238 ruleset_error(LOG_ERROR
, "\"%s\" [%s] \"%s\": should have \"None\" second.",
1239 filename
, sec_name
, rule_name(&a
->name
));
1244 BV_CLR_ALL(a
->flags
);
1246 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", sec_name
);
1247 for (j
= 0; j
< nval
; j
++) {
1249 if (strcmp(sval
, "") == 0) {
1252 ival
= tech_flag_id_by_name(sval
, fc_strcasecmp
);
1253 if (!tech_flag_id_is_valid(ival
)) {
1254 ruleset_error(LOG_ERROR
, "\"%s\" [%s] \"%s\": bad flag name \"%s\".",
1255 filename
, sec_name
, rule_name(&a
->name
), sval
);
1259 BV_SET(a
->flags
, ival
);
1268 sz_strlcpy(a
->graphic_str
,
1269 secfile_lookup_str_default(file
, "-", "%s.graphic", sec_name
));
1270 sz_strlcpy(a
->graphic_alt
,
1271 secfile_lookup_str_default(file
, "-",
1272 "%s.graphic_alt", sec_name
));
1274 a
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
1275 a
->bonus_message
= lookup_string(file
, sec_name
, "bonus_message");
1277 secfile_lookup_int_default(file
, -1, "%s.%s", sec_name
, "cost");
1281 } advance_iterate_end
;
1283 /* Propagate a root tech up into the tech tree. Thus if a technology
1284 * X has Y has a root tech, then any technology requiring X also has
1285 * Y as a root tech. */
1289 advance_iterate(A_FIRST
, a
) {
1290 if (valid_advance(a
)
1291 && A_NEVER
!= a
->require
[AR_ROOT
]) {
1292 bool out_of_order
= FALSE
;
1294 /* Now find any tech depending on this technology and update its
1296 advance_iterate(A_FIRST
, b
) {
1297 if (valid_advance(b
)
1298 && A_NEVER
== b
->require
[AR_ROOT
]
1299 && (a
== b
->require
[AR_ONE
] || a
== b
->require
[AR_TWO
])) {
1300 b
->require
[AR_ROOT
] = a
->require
[AR_ROOT
];
1302 out_of_order
= TRUE
;
1305 } advance_iterate_end
;
1308 /* HACK: If we just changed the root_tech of a lower-numbered
1309 * technology, we need to go back so that we can propagate the
1310 * root_tech up to that technology's parents... */
1314 } advance_iterate_end
;
1316 /* Now rename A_NEVER to A_NONE for consistency */
1317 advance_iterate(A_NONE
, a
) {
1318 if (A_NEVER
== a
->require
[AR_ROOT
]) {
1319 a
->require
[AR_ROOT
] = a_none
;
1321 } advance_iterate_end
;
1323 /* Some more consistency checking:
1324 Non-removed techs depending on removed techs is too
1325 broken to fix by default, so die.
1327 advance_iterate(A_FIRST
, a
) {
1328 if (valid_advance(a
)) {
1329 /* We check for recursive tech loops later,
1330 * in build_required_techs_helper. */
1331 if (!valid_advance(a
->require
[AR_ONE
])) {
1332 ruleset_error(LOG_ERROR
,
1333 "\"%s\" tech \"%s\": req1 leads to removed tech.",
1335 advance_rule_name(a
));
1339 if (!valid_advance(a
->require
[AR_TWO
])) {
1340 ruleset_error(LOG_ERROR
,
1341 "\"%s\" tech \"%s\": req2 leads to removed tech.",
1343 advance_rule_name(a
));
1348 } advance_iterate_end
;
1351 section_list_destroy(sec
);
1353 secfile_check_unused(file
);
1359 /**************************************************************************
1360 Load names of units so other rulesets can refer to units with
1362 **************************************************************************/
1363 static bool load_unit_names(struct section_file
*file
)
1365 struct section_list
*sec
= NULL
;
1368 const char *filename
= secfile_name(file
);
1372 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
1374 /* User unit flag names */
1375 for (i
= 0; (flag
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.name", i
)) ;
1377 const char *helptxt
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.helptxt",
1380 if (i
> MAX_NUM_USER_UNIT_FLAGS
) {
1381 ruleset_error(LOG_ERROR
, "\"%s\": Too many user unit type flags!",
1387 set_user_unit_type_flag_name(UTYF_USER_FLAG_1
+ i
, flag
, helptxt
);
1391 for (; i
< MAX_NUM_USER_UNIT_FLAGS
; i
++) {
1392 set_user_unit_type_flag_name(UTYF_USER_FLAG_1
+ i
, NULL
, NULL
);
1396 sec
= secfile_sections_by_name_prefix(file
, UNIT_CLASS_SECTION_PREFIX
);
1397 if (NULL
== sec
|| 0 == (nval
= section_list_size(sec
))) {
1398 ruleset_error(LOG_ERROR
, "\"%s\": No unit classes?!?", filename
);
1401 log_verbose("%d unit classes", nval
);
1402 if (nval
> UCL_LAST
) {
1403 ruleset_error(LOG_ERROR
, "\"%s\": Too many unit classes (%d, max %d)",
1404 filename
, nval
, UCL_LAST
);
1411 game
.control
.num_unit_classes
= nval
;
1413 unit_class_iterate(punitclass
) {
1414 const int i
= uclass_index(punitclass
);
1415 if (!ruleset_load_names(&punitclass
->name
, NULL
, file
,
1416 section_name(section_list_get(sec
, i
)))) {
1420 } unit_class_iterate_end
;
1422 section_list_destroy(sec
);
1427 sec
= secfile_sections_by_name_prefix(file
, UNIT_SECTION_PREFIX
);
1428 if (NULL
== sec
|| 0 == (nval
= section_list_size(sec
))) {
1429 ruleset_error(LOG_ERROR
, "\"%s\": No unit types?!?", filename
);
1432 log_verbose("%d unit types (including possibly unused)", nval
);
1433 if (nval
> U_LAST
) {
1434 ruleset_error(LOG_ERROR
, "\"%s\": Too many unit types (%d, max %d)",
1435 filename
, nval
, U_LAST
);
1442 game
.control
.num_unit_types
= nval
;
1444 unit_type_iterate(punittype
) {
1445 const int i
= utype_index(punittype
);
1446 if (!ruleset_load_names(&punittype
->name
, NULL
, file
,
1447 section_name(section_list_get(sec
, i
)))) {
1451 } unit_type_iterate_end
;
1453 section_list_destroy(sec
);
1458 /**************************************************************************
1459 Load veteran levels.
1460 **************************************************************************/
1461 static bool load_ruleset_veteran(struct section_file
*file
,
1463 struct veteran_system
**vsystem
, char *err
,
1466 const char **vlist_name
;
1467 int *vlist_power
, *vlist_raise
, *vlist_wraise
, *vlist_move
;
1468 size_t count_name
, count_power
, count_raise
, count_wraise
, count_move
;
1472 /* The pointer should be uninitialised. */
1473 if (*vsystem
!= NULL
) {
1474 fc_snprintf(err
, err_len
, "Veteran system is defined?!");
1479 vlist_name
= secfile_lookup_str_vec(file
, &count_name
,
1480 "%s.veteran_names", path
);
1481 vlist_power
= secfile_lookup_int_vec(file
, &count_power
,
1482 "%s.veteran_power_fact", path
);
1483 vlist_raise
= secfile_lookup_int_vec(file
, &count_raise
,
1484 "%s.veteran_raise_chance", path
);
1485 vlist_wraise
= secfile_lookup_int_vec(file
, &count_wraise
,
1486 "%s.veteran_work_raise_chance",
1488 vlist_move
= secfile_lookup_int_vec(file
, &count_move
,
1489 "%s.veteran_move_bonus", path
);
1491 if (count_name
> MAX_VET_LEVELS
) {
1493 fc_snprintf(err
, err_len
, "\"%s\": Too many veteran levels (section "
1494 "'%s': %lu, max %d)", secfile_name(file
), path
,
1495 (long unsigned)count_name
, MAX_VET_LEVELS
);
1496 } else if (count_name
!= count_power
1497 || count_name
!= count_raise
1498 || count_name
!= count_wraise
1499 || count_name
!= count_move
) {
1501 fc_snprintf(err
, err_len
, "\"%s\": Different lengths for the veteran "
1502 "settings in section '%s'", secfile_name(file
),
1504 } else if (count_name
== 0) {
1505 /* Nothing defined. */
1508 /* Generate the veteran system. */
1509 *vsystem
= veteran_system_new((int)count_name
);
1511 #define rs_sanity_veteran(_path, _entry, _i, _condition, _action) \
1513 log_error("Invalid veteran definition '%s.%s[%d]'!", \
1514 _path, _entry, _i); \
1515 log_debug("Failed check: '%s'. Update value: '%s'.", \
1516 #_condition, #_action); \
1519 for (i
= 0; i
< count_name
; i
++) {
1520 /* Some sanity checks. */
1521 rs_sanity_veteran(path
, "veteran_power_fact", i
,
1522 (vlist_power
[i
] < 0), vlist_power
[i
] = 0);
1523 rs_sanity_veteran(path
, "veteran_raise_chance", i
,
1524 (vlist_raise
[i
] < 0), vlist_raise
[i
] = 0);
1525 rs_sanity_veteran(path
, "veteran_work_raise_chance", i
,
1526 (vlist_wraise
[i
] < 0), vlist_wraise
[i
] = 0);
1527 rs_sanity_veteran(path
, "veteran_move_bonus", i
,
1528 (vlist_move
[i
] < 0), vlist_move
[i
] = 0);
1531 rs_sanity_veteran(path
, "veteran_power_fact", i
,
1532 (vlist_power
[i
] != 100), vlist_power
[i
] = 100);
1533 } else if (i
== count_name
- 1) {
1535 rs_sanity_veteran(path
, "veteran_power_fact", i
,
1536 (vlist_power
[i
] < vlist_power
[i
- 1]),
1537 vlist_power
[i
] = vlist_power
[i
- 1]);
1538 rs_sanity_veteran(path
, "veteran_raise_chance", i
,
1539 (vlist_raise
[i
] != 0), vlist_raise
[i
] = 0);
1540 rs_sanity_veteran(path
, "veteran_work_raise_chance", i
,
1541 (vlist_wraise
[i
] != 0), vlist_wraise
[i
] = 0);
1543 /* All elements inbetween. */
1544 rs_sanity_veteran(path
, "veteran_power_fact", i
,
1545 (vlist_power
[i
] < vlist_power
[i
- 1]),
1546 vlist_power
[i
] = vlist_power
[i
- 1]);
1547 rs_sanity_veteran(path
, "veteran_raise_chance", i
,
1548 (vlist_raise
[i
] > 100), vlist_raise
[i
] = 100);
1549 rs_sanity_veteran(path
, "veteran_work_raise_chance", i
,
1550 (vlist_wraise
[i
] > 100), vlist_wraise
[i
] = 100);
1553 veteran_system_definition(*vsystem
, i
, vlist_name
[i
], vlist_power
[i
],
1554 vlist_move
[i
], vlist_raise
[i
],
1557 #undef rs_sanity_veteran
1579 /**************************************************************************
1580 Load units related ruleset data.
1581 **************************************************************************/
1582 static bool load_ruleset_units(struct section_file
*file
)
1586 struct section_list
*sec
, *csec
;
1587 const char *sval
, **slist
;
1588 const char *filename
= secfile_name(file
);
1589 char msg
[MAX_LEN_MSG
];
1592 if (check_ruleset_capabilities(file
, RULESET_CAPABILITIES
, filename
) == NULL
) {
1596 if (!load_ruleset_veteran(file
, "veteran_system", &game
.veteran
, msg
,
1597 sizeof(msg
)) || game
.veteran
== NULL
) {
1598 ruleset_error(LOG_ERROR
, "Error loading the default veteran system: %s",
1603 sec
= secfile_sections_by_name_prefix(file
, UNIT_SECTION_PREFIX
);
1604 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
1606 csec
= secfile_sections_by_name_prefix(file
, UNIT_CLASS_SECTION_PREFIX
);
1607 nval
= (NULL
!= csec
? section_list_size(csec
) : 0);
1610 unit_class_iterate(uc
) {
1611 int i
= uclass_index(uc
);
1612 char tmp
[200] = "\0";
1613 const char *hut_str
;
1614 const char *sec_name
= section_name(section_list_get(csec
, i
));
1616 if (secfile_lookup_int(file
, &uc
->min_speed
, "%s.min_speed", sec_name
)) {
1617 uc
->min_speed
*= SINGLE_MOVE
;
1619 ruleset_error(LOG_ERROR
, "%s", secfile_error());
1623 if (!secfile_lookup_int(file
, &uc
->hp_loss_pct
,
1624 "%s.hp_loss_pct", sec_name
)) {
1625 ruleset_error(LOG_ERROR
, "%s", secfile_error());
1630 uc
->non_native_def_pct
= secfile_lookup_int_default(file
, 100,
1631 "%s.non_native_def_pct",
1634 hut_str
= secfile_lookup_str_default(file
, "Normal", "%s.hut_behavior", sec_name
);
1635 if (fc_strcasecmp(hut_str
, "Normal") == 0) {
1636 uc
->hut_behavior
= HUT_NORMAL
;
1637 } else if (fc_strcasecmp(hut_str
, "Nothing") == 0) {
1638 uc
->hut_behavior
= HUT_NOTHING
;
1639 } else if (fc_strcasecmp(hut_str
, "Frighten") == 0) {
1640 uc
->hut_behavior
= HUT_FRIGHTEN
;
1642 ruleset_error(LOG_ERROR
,
1643 "\"%s\" unit_class \"%s\":"
1644 " Illegal hut behavior \"%s\".",
1646 uclass_rule_name(uc
),
1652 BV_CLR_ALL(uc
->flags
);
1653 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", sec_name
);
1654 for(j
= 0; j
< nval
; j
++) {
1656 if(strcmp(sval
,"") == 0) {
1659 ival
= unit_class_flag_id_by_name(sval
, fc_strcasecmp
);
1660 if (!unit_class_flag_id_is_valid(ival
)) {
1662 ival
= unit_type_flag_id_by_name(sval
, fc_strcasecmp
);
1663 if (unit_type_flag_id_is_valid(ival
)) {
1664 ruleset_error(LOG_ERROR
,
1665 "\"%s\" unit_class \"%s\": unit_type flag \"%s\"!",
1666 filename
, uclass_rule_name(uc
), sval
);
1668 ruleset_error(LOG_ERROR
,
1669 "\"%s\" unit_class \"%s\": bad flag name \"%s\".",
1670 filename
, uclass_rule_name(uc
), sval
);
1674 BV_SET(uc
->flags
, ival
);
1683 fc_strlcat(tmp
, sec_name
, 200);
1684 fc_strlcat(tmp
, ".move_type", 200);
1685 if (!lookup_move_type(file
, tmp
, &uc
->move_type
,
1691 set_unit_class_caches(uc
);
1693 if (!unit_move_type_is_valid(uc
->move_type
)) {
1694 /* Not explicitly given, determine automatically */
1695 bool land_moving
= FALSE
;
1696 bool sea_moving
= FALSE
;
1698 road_type_iterate(proad
) {
1699 enum unit_move_type eut
= move_type_from_road(proad
, uc
);
1701 if (eut
== UMT_BOTH
) {
1704 } else if (eut
== UMT_LAND
) {
1706 } else if (eut
== UMT_SEA
) {
1709 } road_type_iterate_end
;
1711 base_type_iterate(pbase
) {
1712 enum unit_move_type eut
= move_type_from_base(pbase
, uc
);
1714 if (eut
== UMT_BOTH
) {
1717 } else if (eut
== UMT_LAND
) {
1719 } else if (eut
== UMT_SEA
) {
1722 } base_type_iterate_end
;
1724 terrain_type_iterate(pterrain
) {
1731 if (is_native_to_class(uc
, pterrain
, bases
, roads
)) {
1732 if (is_ocean(pterrain
)) {
1738 } terrain_type_iterate_end
;
1740 if (land_moving
&& sea_moving
) {
1741 uc
->move_type
= UMT_BOTH
;
1742 } else if (sea_moving
) {
1743 uc
->move_type
= UMT_SEA
;
1745 /* If unit has no native terrains, it is considered land moving */
1746 uc
->move_type
= UMT_LAND
;
1748 } else if (uc
->move_type
!= UMT_BOTH
) {
1749 /* Explicitly given move type */
1750 road_type_iterate(proad
) {
1751 enum unit_move_type eut
= move_type_from_road(proad
, uc
);
1754 || (uc
->move_type
== UMT_LAND
&& eut
== UMT_SEA
)
1755 || (uc
->move_type
== UMT_SEA
&& eut
== UMT_LAND
)) {
1756 ruleset_error(LOG_ERROR
,
1757 "\"%s\" unit_class \"%s\": cannot make road \"%s\" "
1758 "native to unit of current move_type.",
1759 filename
, uclass_rule_name(uc
),
1760 road_rule_name(proad
));
1764 } road_type_iterate_end
;
1765 base_type_iterate(pbase
) {
1766 enum unit_move_type eut
= move_type_from_base(pbase
, uc
);
1769 || (uc
->move_type
== UMT_LAND
&& eut
== UMT_SEA
)
1770 || (uc
->move_type
== UMT_SEA
&& eut
== UMT_LAND
)) {
1771 ruleset_error(LOG_ERROR
,
1772 "\"%s\" unit_class \"%s\": cannot make base \"%s\" "
1773 "native to unit of current move_type.",
1774 filename
, uclass_rule_name(uc
),
1775 base_rule_name(pbase
));
1779 } base_type_iterate_end
;
1785 } unit_class_iterate_end
;
1789 /* Tech and Gov requirements; per unit veteran system */
1790 unit_type_iterate(u
) {
1791 const int i
= utype_index(u
);
1792 const struct section
*psection
= section_list_get(sec
, i
);
1793 const char *sec_name
= section_name(psection
);
1795 if (!lookup_tech(file
, &u
->require_advance
, sec_name
,
1796 "tech_req", filename
,
1797 rule_name(&u
->name
))) {
1801 if (NULL
!= section_entry_by_name(psection
, "gov_req")) {
1802 char tmp
[200] = "\0";
1803 fc_strlcat(tmp
, section_name(psection
), sizeof(tmp
));
1804 fc_strlcat(tmp
, ".gov_req", sizeof(tmp
));
1805 u
->need_government
= lookup_government(file
, tmp
, filename
, NULL
);
1806 if (u
->need_government
== NULL
) {
1811 u
->need_government
= NULL
; /* no requirement */
1814 if (!load_ruleset_veteran(file
, sec_name
, &u
->veteran
,
1815 msg
, sizeof(msg
))) {
1816 ruleset_error(LOG_ERROR
, "Error loading the veteran system: %s",
1822 if (!lookup_unit_type(file
, sec_name
, "obsolete_by",
1823 &u
->obsoleted_by
, filename
,
1824 rule_name(&u
->name
))
1825 || !lookup_unit_type(file
, sec_name
, "convert_to",
1826 &u
->converted_to
, filename
,
1827 rule_name(&u
->name
))) {
1831 u
->convert_time
= 1; /* default */
1832 lookup_time(file
, &u
->convert_time
, sec_name
, "convert_time",
1833 filename
, rule_name(&u
->name
), &ok
);
1834 } unit_type_iterate_end
;
1839 unit_type_iterate(u
) {
1840 const int i
= utype_index(u
);
1841 struct unit_class
*pclass
;
1842 const char *sec_name
= section_name(section_list_get(sec
, i
));
1845 if (!lookup_building(file
, sec_name
, "impr_req",
1846 &u
->need_improvement
, filename
,
1847 rule_name(&u
->name
))) {
1852 sval
= secfile_lookup_str(file
, "%s.class", sec_name
);
1853 pclass
= unit_class_by_rule_name(sval
);
1855 ruleset_error(LOG_ERROR
,
1856 "\"%s\" unit_type \"%s\":"
1857 " bad class \"%s\".",
1866 sz_strlcpy(u
->sound_move
,
1867 secfile_lookup_str_default(file
, "-", "%s.sound_move",
1869 sz_strlcpy(u
->sound_move_alt
,
1870 secfile_lookup_str_default(file
, "-", "%s.sound_move_alt",
1872 sz_strlcpy(u
->sound_fight
,
1873 secfile_lookup_str_default(file
, "-", "%s.sound_fight",
1875 sz_strlcpy(u
->sound_fight_alt
,
1876 secfile_lookup_str_default(file
, "-", "%s.sound_fight_alt",
1879 if ((string
= secfile_lookup_str(file
, "%s.graphic", sec_name
))) {
1880 sz_strlcpy(u
->graphic_str
, string
);
1882 ruleset_error(LOG_ERROR
, "%s", secfile_error());
1886 sz_strlcpy(u
->graphic_alt
,
1887 secfile_lookup_str_default(file
, "-", "%s.graphic_alt",
1890 if (!secfile_lookup_int(file
, &u
->build_cost
,
1891 "%s.build_cost", sec_name
)
1892 || !secfile_lookup_int(file
, &u
->pop_cost
,
1893 "%s.pop_cost", sec_name
)
1894 || !secfile_lookup_int(file
, &u
->attack_strength
,
1895 "%s.attack", sec_name
)
1896 || !secfile_lookup_int(file
, &u
->defense_strength
,
1897 "%s.defense", sec_name
)
1898 || !secfile_lookup_int(file
, &u
->move_rate
,
1899 "%s.move_rate", sec_name
)
1900 || !secfile_lookup_int(file
, &u
->vision_radius_sq
,
1901 "%s.vision_radius_sq", sec_name
)
1902 || !secfile_lookup_int(file
, &u
->transport_capacity
,
1903 "%s.transport_cap", sec_name
)
1904 || !secfile_lookup_int(file
, &u
->hp
,
1905 "%s.hitpoints", sec_name
)
1906 || !secfile_lookup_int(file
, &u
->firepower
,
1907 "%s.firepower", sec_name
)
1908 || !secfile_lookup_int(file
, &u
->fuel
,
1909 "%s.fuel", sec_name
)
1910 || !secfile_lookup_int(file
, &u
->happy_cost
,
1911 "%s.uk_happy", sec_name
)) {
1912 ruleset_error(LOG_ERROR
, "%s", secfile_error());
1916 u
->move_rate
*= SINGLE_MOVE
;
1918 if (u
->firepower
<= 0) {
1919 ruleset_error(LOG_ERROR
,
1920 "\"%s\" unit_type \"%s\":"
1922 " but must be at least 1. "
1923 " If you want no attack ability,"
1924 " set the unit's attack strength to 0.",
1932 lookup_cbonus_list(u
->bonuses
, file
, sec_name
, "bonuses");
1934 output_type_iterate(o
) {
1935 u
->upkeep
[o
] = secfile_lookup_int_default(file
, 0, "%s.uk_%s",
1937 get_output_identifier(o
));
1938 } output_type_iterate_end
;
1940 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.cargo", sec_name
);
1941 BV_CLR_ALL(u
->cargo
);
1942 for (j
= 0; j
< nval
; j
++) {
1943 struct unit_class
*uclass
= unit_class_by_rule_name(slist
[j
]);
1946 ruleset_error(LOG_ERROR
,
1947 "\"%s\" unit_type \"%s\":"
1948 "has unknown unit class %s as cargo.",
1956 BV_SET(u
->cargo
, uclass_index(uclass
));
1964 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.targets", sec_name
);
1965 BV_CLR_ALL(u
->targets
);
1966 for (j
= 0; j
< nval
; j
++) {
1967 struct unit_class
*uclass
= unit_class_by_rule_name(slist
[j
]);
1970 ruleset_error(LOG_ERROR
,
1971 "\"%s\" unit_type \"%s\":"
1972 "has unknown unit class %s as target.",
1980 BV_SET(u
->targets
, uclass_index(uclass
));
1988 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.embarks", sec_name
);
1989 BV_CLR_ALL(u
->embarks
);
1990 for (j
= 0; j
< nval
; j
++) {
1991 struct unit_class
*uclass
= unit_class_by_rule_name(slist
[j
]);
1994 ruleset_error(LOG_ERROR
,
1995 "\"%s\" unit_type \"%s\":"
1996 "has unknown unit class %s as embarkable.",
2004 BV_SET(u
->embarks
, uclass_index(uclass
));
2012 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.disembarks", sec_name
);
2013 BV_CLR_ALL(u
->disembarks
);
2014 for (j
= 0; j
< nval
; j
++) {
2015 struct unit_class
*uclass
= unit_class_by_rule_name(slist
[j
]);
2018 ruleset_error(LOG_ERROR
,
2019 "\"%s\" unit_type \"%s\":"
2020 "has unknown unit class %s as disembarkable.",
2028 BV_SET(u
->disembarks
, uclass_index(uclass
));
2036 /* Set also all classes that are never unreachable as targets,
2037 * embarks, and disembarks. */
2038 unit_class_iterate(pclass
) {
2039 if (!uclass_has_flag(pclass
, UCF_UNREACHABLE
)) {
2040 BV_SET(u
->targets
, uclass_index(pclass
));
2041 BV_SET(u
->embarks
, uclass_index(pclass
));
2042 BV_SET(u
->disembarks
, uclass_index(pclass
));
2044 } unit_class_iterate_end
;
2046 u
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
2048 u
->paratroopers_range
= secfile_lookup_int_default(file
,
2049 0, "%s.paratroopers_range", sec_name
);
2050 u
->paratroopers_mr_req
= SINGLE_MOVE
* secfile_lookup_int_default(file
,
2051 0, "%s.paratroopers_mr_req", sec_name
);
2052 u
->paratroopers_mr_sub
= SINGLE_MOVE
* secfile_lookup_int_default(file
,
2053 0, "%s.paratroopers_mr_sub", sec_name
);
2054 u
->bombard_rate
= secfile_lookup_int_default(file
,
2055 0, "%s.bombard_rate", sec_name
);
2056 u
->city_size
= secfile_lookup_int_default(file
,
2057 1, "%s.city_size", sec_name
);
2058 } unit_type_iterate_end
;
2063 unit_type_iterate(u
) {
2064 const int i
= utype_index(u
);
2066 BV_CLR_ALL(u
->flags
);
2067 fc_assert(!utype_has_flag(u
, UTYF_LAST_USER_FLAG
- 1));
2069 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags",
2070 section_name(section_list_get(sec
, i
)));
2071 for(j
= 0; j
< nval
; j
++) {
2073 if (0 == strcmp(sval
, "")) {
2076 ival
= unit_type_flag_id_by_name(sval
, fc_strcasecmp
);
2077 if (!unit_type_flag_id_is_valid(ival
)) {
2079 ival
= unit_class_flag_id_by_name(sval
, fc_strcasecmp
);
2080 if (unit_class_flag_id_is_valid(ival
)) {
2081 ruleset_error(LOG_ERROR
, "\"%s\" unit_type \"%s\": unit_class flag!",
2082 filename
, utype_rule_name(u
));
2084 ruleset_error(LOG_ERROR
,
2085 "\"%s\" unit_type \"%s\": bad flag name \"%s\".",
2086 filename
, utype_rule_name(u
), sval
);
2090 BV_SET(u
->flags
, ival
);
2092 fc_assert(utype_has_flag(u
, ival
));
2099 } unit_type_iterate_end
;
2104 unit_type_iterate(u
) {
2105 const int i
= utype_index(u
);
2107 BV_CLR_ALL(u
->roles
);
2109 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.roles",
2110 section_name(section_list_get(sec
, i
)));
2111 for (j
= 0; j
< nval
; j
++) {
2113 if (strcmp(sval
, "") == 0) {
2116 ival
= unit_role_id_by_name(sval
, fc_strcasecmp
);
2117 if (!unit_role_id_is_valid(ival
)) {
2118 ruleset_error(LOG_ERROR
, "\"%s\" unit_type \"%s\": bad role name \"%s\".",
2119 filename
, utype_rule_name(u
), sval
);
2122 } else if ((ival
== L_FERRYBOAT
|| ival
== L_BARBARIAN_BOAT
)
2123 && u
->uclass
->move_type
== UMT_LAND
) {
2124 ruleset_error(LOG_ERROR
, "\"%s\" unit_type \"%s\": role \"%s\" "
2125 "for land moving unit.",
2126 filename
, utype_rule_name(u
), sval
);
2130 BV_SET(u
->roles
, ival
- L_FIRST
);
2132 fc_assert(utype_has_role(u
, ival
));
2135 } unit_type_iterate_end
;
2139 /* Some more consistency checking: */
2140 unit_type_iterate(u
) {
2141 if (!valid_advance(u
->require_advance
)) {
2142 ruleset_error(LOG_ERROR
, "\"%s\" unit_type \"%s\": depends on removed tech \"%s\".",
2143 filename
, utype_rule_name(u
),
2144 advance_rule_name(u
->require_advance
));
2145 u
->require_advance
= A_NEVER
;
2150 if (utype_has_flag(u
, UTYF_SETTLERS
)
2151 && u
->city_size
<= 0) {
2152 ruleset_error(LOG_ERROR
, "\"%s\": Unit %s would build size %d cities",
2153 filename
, utype_rule_name(u
), u
->city_size
);
2158 } unit_type_iterate_end
;
2162 /* Setup roles and flags pre-calcs: */
2163 role_unit_precalcs();
2166 section_list_destroy(csec
);
2167 section_list_destroy(sec
);
2170 secfile_check_unused(file
);
2176 /**************************************************************************
2177 Load names of buildings so other rulesets can refer to buildings with
2179 **************************************************************************/
2180 static bool load_building_names(struct section_file
*file
)
2182 struct section_list
*sec
;
2184 const char *filename
= secfile_name(file
);
2187 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
2190 sec
= secfile_sections_by_name_prefix(file
, BUILDING_SECTION_PREFIX
);
2191 if (NULL
== sec
|| 0 == (nval
= section_list_size(sec
))) {
2192 ruleset_error(LOG_ERROR
, "\"%s\": No improvements?!?", filename
);
2195 log_verbose("%d improvement types (including possibly unused)", nval
);
2196 if (nval
> B_LAST
) {
2197 ruleset_error(LOG_ERROR
, "\"%s\": Too many improvements (%d, max %d)",
2198 filename
, nval
, B_LAST
);
2204 game
.control
.num_impr_types
= nval
;
2206 for (i
= 0; i
< nval
; i
++) {
2207 struct impr_type
*b
= improvement_by_number(i
);
2209 if (!ruleset_load_names(&b
->name
, NULL
, file
, section_name(section_list_get(sec
, i
)))) {
2216 section_list_destroy(sec
);
2221 /**************************************************************************
2222 Load buildings related ruleset data
2223 **************************************************************************/
2224 static bool load_ruleset_buildings(struct section_file
*file
)
2226 struct section_list
*sec
;
2229 const char *filename
= secfile_name(file
);
2232 if (check_ruleset_capabilities(file
, RULESET_CAPABILITIES
, filename
) == NULL
) {
2236 sec
= secfile_sections_by_name_prefix(file
, BUILDING_SECTION_PREFIX
);
2237 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
2239 for (i
= 0; i
< nval
&& ok
; i
++) {
2240 struct impr_type
*b
= improvement_by_number(i
);
2241 const char *sec_name
= section_name(section_list_get(sec
, i
));
2242 struct requirement_vector
*reqs
=
2243 lookup_req_list(file
, sec_name
, "reqs",
2244 improvement_rule_name(b
));
2250 const char *sval
, **slist
;
2254 item
= secfile_lookup_str(file
, "%s.genus", sec_name
);
2255 b
->genus
= impr_genus_id_by_name(item
, fc_strcasecmp
);
2256 if (!impr_genus_id_is_valid(b
->genus
)) {
2257 ruleset_error(LOG_ERROR
, "\"%s\" improvement \"%s\": couldn't match "
2258 "genus \"%s\".", filename
,
2259 improvement_rule_name(b
), item
);
2264 slist
= secfile_lookup_str_vec(file
, &nflags
, "%s.flags", sec_name
);
2265 BV_CLR_ALL(b
->flags
);
2267 for (j
= 0; j
< nflags
; j
++) {
2269 if (strcmp(sval
,"") == 0) {
2272 ival
= impr_flag_id_by_name(sval
, fc_strcasecmp
);
2273 if (!impr_flag_id_is_valid(ival
)) {
2274 ruleset_error(LOG_ERROR
,
2275 "\"%s\" improvement \"%s\": bad flag name \"%s\".",
2276 filename
, improvement_rule_name(b
), sval
);
2280 BV_SET(b
->flags
, ival
);
2289 requirement_vector_copy(&b
->reqs
, reqs
);
2291 if (!lookup_tech(file
, &b
->obsolete_by
, sec_name
, "obsolete_by",
2292 filename
, rule_name(&b
->name
))) {
2296 if (advance_by_number(A_NONE
) == b
->obsolete_by
) {
2298 * The ruleset can specify "None" for a never-obsoleted
2299 * improvement. Currently this means A_NONE, which is an
2300 * unnecessary special-case. We use A_NEVER to flag a
2301 * never-obsoleted improvement in the code instead.
2302 * (Test for valid_advance() later.)
2304 b
->obsolete_by
= A_NEVER
;
2307 if (!lookup_building(file
, sec_name
, "replaced_by",
2308 &b
->replaced_by
, filename
,
2309 rule_name(&b
->name
))) {
2314 if (!secfile_lookup_int(file
, &b
->build_cost
,
2315 "%s.build_cost", sec_name
)
2316 || !secfile_lookup_int(file
, &b
->upkeep
,
2317 "%s.upkeep", sec_name
)
2318 || !secfile_lookup_int(file
, &b
->sabotage
,
2319 "%s.sabotage", sec_name
)) {
2320 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2325 sz_strlcpy(b
->graphic_str
,
2326 secfile_lookup_str_default(file
, "-",
2327 "%s.graphic", sec_name
));
2328 sz_strlcpy(b
->graphic_alt
,
2329 secfile_lookup_str_default(file
, "-",
2330 "%s.graphic_alt", sec_name
));
2332 sz_strlcpy(b
->soundtag
,
2333 secfile_lookup_str_default(file
, "-",
2334 "%s.sound", sec_name
));
2335 sz_strlcpy(b
->soundtag_alt
,
2336 secfile_lookup_str_default(file
, "-",
2337 "%s.sound_alt", sec_name
));
2338 b
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
2340 b
->allows_units
= FALSE
;
2341 unit_type_iterate(ut
) {
2342 if (ut
->need_improvement
== b
) {
2343 b
->allows_units
= TRUE
;
2346 } unit_type_iterate_end
;
2351 /* Some more consistency checking: */
2352 improvement_iterate(b
) {
2353 if (valid_improvement(b
)) {
2354 if (A_NEVER
!= b
->obsolete_by
2355 && !valid_advance(b
->obsolete_by
)) {
2356 log_error("\"%s\" improvement \"%s\": obsoleted by "
2357 "removed tech \"%s\".",
2358 filename
, improvement_rule_name(b
),
2359 advance_rule_name(b
->obsolete_by
));
2360 b
->obsolete_by
= A_NEVER
;
2363 } improvement_iterate_end
;
2366 section_list_destroy(sec
);
2368 secfile_check_unused(file
);
2374 /**************************************************************************
2375 Load names of terrain types so other rulesets can refer to terrains with
2377 **************************************************************************/
2378 static bool load_terrain_names(struct section_file
*file
)
2381 struct section_list
*sec
= NULL
;
2384 const char *filename
= secfile_name(file
);
2387 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
2389 /* User terrain flag names */
2390 for (i
= 0; (flag
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.name", i
)) ;
2392 const char *helptxt
= secfile_lookup_str_default(file
, NULL
, "control.flags%d.helptxt",
2395 if (i
> MAX_NUM_USER_TER_FLAGS
) {
2396 ruleset_error(LOG_ERROR
, "\"%s\": Too many user terrain flags!",
2402 set_user_terrain_flag_name(TER_USER_1
+ i
, flag
, helptxt
);
2406 for (; i
< MAX_NUM_USER_TER_FLAGS
; i
++) {
2407 set_user_terrain_flag_name(TER_USER_1
+ i
, NULL
, NULL
);
2412 sec
= secfile_sections_by_name_prefix(file
, TERRAIN_SECTION_PREFIX
);
2413 if (NULL
== sec
|| 0 == (nval
= section_list_size(sec
))) {
2414 ruleset_error(LOG_ERROR
, "\"%s\": ruleset doesn't have any terrains.",
2418 if (nval
> MAX_NUM_TERRAINS
) {
2419 ruleset_error(LOG_ERROR
, "\"%s\": Too many terrains (%d, max %d)",
2420 filename
, nval
, MAX_NUM_TERRAINS
);
2427 game
.control
.terrain_count
= nval
;
2429 /* avoid re-reading files */
2430 if (terrain_sections
) {
2431 free(terrain_sections
);
2433 terrain_sections
= fc_calloc(nval
, MAX_SECTION_LABEL
);
2435 terrain_type_iterate(pterrain
) {
2436 const int i
= terrain_index(pterrain
);
2437 const char *sec_name
= section_name(section_list_get(sec
, i
));
2439 if (!ruleset_load_names(&pterrain
->name
, NULL
, file
, sec_name
)) {
2444 if (0 == strcmp(rule_name(&pterrain
->name
), "unused")) {
2445 name_set(&pterrain
->name
, NULL
, "");
2448 section_strlcpy(&terrain_sections
[i
* MAX_SECTION_LABEL
], sec_name
);
2449 } terrain_type_iterate_end
;
2452 section_list_destroy(sec
);
2455 /* resource names */
2457 sec
= secfile_sections_by_name_prefix(file
, RESOURCE_SECTION_PREFIX
);
2458 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
2459 if (nval
> MAX_NUM_RESOURCES
) {
2460 ruleset_error(LOG_ERROR
, "\"%s\": Too many resources (%d, max %d)",
2461 filename
, nval
, MAX_NUM_RESOURCES
);
2467 game
.control
.resource_count
= nval
;
2469 /* avoid re-reading files */
2470 if (resource_sections
) {
2471 free(resource_sections
);
2473 resource_sections
= fc_calloc(nval
, MAX_SECTION_LABEL
);
2475 resource_type_iterate(presource
) {
2476 const int i
= resource_index(presource
);
2477 const char *sec_name
= section_name(section_list_get(sec
, i
));
2479 if (!ruleset_load_names(&presource
->name
, NULL
, file
, sec_name
)) {
2484 if (0 == strcmp(rule_name(&presource
->name
), "unused")) {
2485 name_set(&presource
->name
, NULL
, "");
2488 section_strlcpy(&resource_sections
[i
* MAX_SECTION_LABEL
], sec_name
);
2489 } resource_type_iterate_end
;
2492 section_list_destroy(sec
);
2498 sec
= secfile_sections_by_name_prefix(file
, BASE_SECTION_PREFIX
);
2499 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
2500 if (nval
> MAX_BASE_TYPES
) {
2501 ruleset_error(LOG_ERROR
, "\"%s\": Too many base types (%d, max %d)",
2502 filename
, nval
, MAX_BASE_TYPES
);
2508 game
.control
.num_base_types
= nval
;
2510 if (base_sections
) {
2511 free(base_sections
);
2513 base_sections
= fc_calloc(nval
, MAX_SECTION_LABEL
);
2515 base_type_iterate(pbase
) {
2516 const int i
= base_index(pbase
);
2517 const char *sec_name
= section_name(section_list_get(sec
, i
));
2519 if (!ruleset_load_names(&pbase
->name
, NULL
, file
, sec_name
)) {
2523 section_strlcpy(&base_sections
[i
* MAX_SECTION_LABEL
], sec_name
);
2524 } base_type_iterate_end
;
2527 section_list_destroy(sec
);
2533 sec
= secfile_sections_by_name_prefix(file
, ROAD_SECTION_PREFIX
);
2534 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
2535 if (nval
> MAX_ROAD_TYPES
) {
2536 ruleset_error(LOG_ERROR
, "\"%s\": Too many road types (%d, max %d)",
2537 filename
, nval
, MAX_ROAD_TYPES
);
2543 game
.control
.num_road_types
= nval
;
2545 if (road_sections
) {
2546 free(road_sections
);
2548 road_sections
= fc_calloc(nval
, MAX_SECTION_LABEL
);
2550 road_type_iterate(proad
) {
2551 const int i
= road_index(proad
);
2552 const char *sec_name
= section_name(section_list_get(sec
, i
));
2554 if (!ruleset_load_names(&proad
->name
, NULL
, file
, sec_name
)) {
2558 section_strlcpy(&road_sections
[i
* MAX_SECTION_LABEL
], sec_name
);
2559 } road_type_iterate_end
;
2562 section_list_destroy(sec
);
2567 /**************************************************************************
2568 Load terrain types related ruleset data
2569 **************************************************************************/
2570 static bool load_ruleset_terrain(struct section_file
*file
)
2574 bool compat_road
= FALSE
;
2575 bool compat_rail
= FALSE
;
2576 bool compat_river
= FALSE
;
2578 const char *filename
= secfile_name(file
);
2581 if (check_ruleset_capabilities(file
, RULESET_CAPABILITIES
, filename
) == NULL
) {
2587 terrain_control
.ocean_reclaim_requirement_pct
2588 = secfile_lookup_int_default(file
, 101,
2589 "parameters.ocean_reclaim_requirement");
2590 terrain_control
.land_channel_requirement_pct
2591 = secfile_lookup_int_default(file
, 101,
2592 "parameters.land_channel_requirement");
2593 terrain_control
.lake_max_size
2594 = secfile_lookup_int_default(file
, 0,
2595 "parameters.lake_max_size");
2596 terrain_control
.min_start_native_area
2597 = secfile_lookup_int_default(file
, 0,
2598 "parameters.min_start_native_area");
2599 terrain_control
.move_fragments
2600 = secfile_lookup_int_default(file
, 3,
2601 "parameters.move_fragments");
2602 if (terrain_control
.move_fragments
< 1) {
2603 ruleset_error(LOG_ERROR
, "\"%s\": move_fragments must be at least 1",
2607 init_move_fragments();
2608 terrain_control
.igter_cost
2609 = secfile_lookup_int_default(file
, 1,
2610 "parameters.igter_cost");
2611 if (terrain_control
.igter_cost
< 1) {
2612 ruleset_error(LOG_ERROR
, "\"%s\": igter_cost must be at least 1",
2616 map
.server
.ocean_resources
2617 = secfile_lookup_bool_default(file
, FALSE
,
2618 "parameters.ocean_resources");
2620 output_type_iterate(o
) {
2621 terrain_control
.pollution_tile_penalty
[o
]
2622 = secfile_lookup_int_default(file
, 50,
2623 "parameters.pollution_%s_penalty",
2624 get_output_identifier(o
));
2625 terrain_control
.fallout_tile_penalty
[o
]
2626 = secfile_lookup_int_default(file
, 50,
2627 "parameters.fallout_%s_penalty",
2628 get_output_identifier(o
));
2629 } output_type_iterate_end
;
2632 /* terrain details */
2634 terrain_type_iterate(pterrain
) {
2636 const int i
= terrain_index(pterrain
);
2637 const char *tsection
= &terrain_sections
[i
* MAX_SECTION_LABEL
];
2640 sz_strlcpy(pterrain
->graphic_str
,
2641 secfile_lookup_str(file
,"%s.graphic", tsection
));
2642 sz_strlcpy(pterrain
->graphic_alt
,
2643 secfile_lookup_str(file
,"%s.graphic_alt", tsection
));
2645 pterrain
->identifier
2646 = secfile_lookup_str(file
, "%s.identifier", tsection
)[0];
2647 if ('\0' == pterrain
->identifier
) {
2648 ruleset_error(LOG_ERROR
, "\"%s\" [%s] identifier missing value.",
2649 filename
, tsection
);
2653 if (TERRAIN_UNKNOWN_IDENTIFIER
== pterrain
->identifier
) {
2654 ruleset_error(LOG_ERROR
,
2655 "\"%s\" [%s] cannot use '%c' as an identifier;"
2656 " it is reserved for unknown terrain.",
2657 filename
, tsection
, pterrain
->identifier
);
2661 for (j
= T_FIRST
; j
< i
; j
++) {
2662 if (pterrain
->identifier
== terrain_by_number(j
)->identifier
) {
2663 ruleset_error(LOG_ERROR
,
2664 "\"%s\" [%s] has the same identifier as [%s].",
2667 &terrain_sections
[j
* MAX_SECTION_LABEL
]);
2677 cstr
= secfile_lookup_str(file
, "%s.class", tsection
);
2678 pterrain
->tclass
= terrain_class_by_name(cstr
, fc_strcasecmp
);
2679 if (!terrain_class_is_valid(pterrain
->tclass
)) {
2680 ruleset_error(LOG_ERROR
, "\"%s\": [%s] unknown class \"%s\"",
2681 filename
, tsection
, cstr
);
2686 if (!secfile_lookup_int(file
, &pterrain
->movement_cost
,
2687 "%s.movement_cost", tsection
)
2688 || !secfile_lookup_int(file
, &pterrain
->defense_bonus
,
2689 "%s.defense_bonus", tsection
)) {
2690 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2695 output_type_iterate(o
) {
2697 = secfile_lookup_int_default(file
, 0, "%s.%s", tsection
,
2698 get_output_identifier(o
));
2699 } output_type_iterate_end
;
2701 res
= secfile_lookup_str_vec(file
, &nval
, "%s.resources", tsection
);
2702 pterrain
->resources
= fc_calloc(nval
+ 1, sizeof(*pterrain
->resources
));
2703 for (j
= 0; j
< nval
; j
++) {
2704 pterrain
->resources
[j
] = lookup_resource(filename
, res
[j
], tsection
);
2706 pterrain
->resources
[nval
] = NULL
;
2710 output_type_iterate(o
) {
2711 pterrain
->road_output_incr_pct
[o
]
2712 = secfile_lookup_int_default(file
, 0, "%s.road_%s_incr_pct",
2713 tsection
, get_output_identifier(o
));
2714 } output_type_iterate_end
;
2716 if (!lookup_time(file
, &pterrain
->base_time
, tsection
, "base_time",
2717 filename
, NULL
, &ok
)
2718 || !lookup_time(file
, &pterrain
->road_time
, tsection
, "road_time",
2719 filename
, NULL
, &ok
)) {
2720 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2725 pterrain
->irrigation_result
2726 = lookup_terrain(file
, "irrigation_result", pterrain
);
2727 if (!secfile_lookup_int(file
, &pterrain
->irrigation_food_incr
,
2728 "%s.irrigation_food_incr", tsection
)
2729 || !lookup_time(file
, &pterrain
->irrigation_time
,
2730 tsection
, "irrigation_time", filename
, NULL
, &ok
)) {
2731 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2736 pterrain
->mining_result
2737 = lookup_terrain(file
, "mining_result", pterrain
);
2738 if (!secfile_lookup_int(file
, &pterrain
->mining_shield_incr
,
2739 "%s.mining_shield_incr", tsection
)
2740 || !lookup_time(file
, &pterrain
->mining_time
,
2741 tsection
, "mining_time", filename
, NULL
, &ok
)) {
2742 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2747 pterrain
->transform_result
2748 = lookup_terrain(file
, "transform_result", pterrain
);
2749 if (!lookup_time(file
, &pterrain
->transform_time
,
2750 tsection
, "transform_time", filename
, NULL
, &ok
)) {
2751 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2755 pterrain
->clean_pollution_time
= 3; /* default */
2756 lookup_time(file
, &pterrain
->clean_pollution_time
,
2757 tsection
, "clean_pollution_time", filename
, NULL
, &ok
);
2758 pterrain
->clean_fallout_time
= 3; /* default */
2759 lookup_time(file
, &pterrain
->clean_fallout_time
,
2760 tsection
, "clean_fallout_time", filename
, NULL
, &ok
);
2762 pterrain
->warmer_wetter_result
2763 = lookup_terrain(file
, "warmer_wetter_result", pterrain
);
2764 pterrain
->warmer_drier_result
2765 = lookup_terrain(file
, "warmer_drier_result", pterrain
);
2766 pterrain
->cooler_wetter_result
2767 = lookup_terrain(file
, "cooler_wetter_result", pterrain
);
2768 pterrain
->cooler_drier_result
2769 = lookup_terrain(file
, "cooler_drier_result", pterrain
);
2771 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", tsection
);
2772 BV_CLR_ALL(pterrain
->flags
);
2773 for (j
= 0; j
< nval
; j
++) {
2774 const char *sval
= slist
[j
];
2775 enum terrain_flag_id flag
2776 = terrain_flag_id_by_name(sval
, fc_strcasecmp
);
2778 if (!terrain_flag_id_is_valid(flag
)) {
2779 ruleset_error(LOG_ERROR
, "\"%s\" [%s] has unknown flag \"%s\".",
2780 filename
, tsection
, sval
);
2784 BV_SET(pterrain
->flags
, flag
);
2794 enum mapgen_terrain_property mtp
;
2795 for (mtp
= mapgen_terrain_property_begin();
2796 mtp
!= mapgen_terrain_property_end();
2797 mtp
= mapgen_terrain_property_next(mtp
)) {
2798 pterrain
->property
[mtp
]
2799 = secfile_lookup_int_default(file
, 0, "%s.property_%s", tsection
,
2800 mapgen_terrain_property_name(mtp
));
2804 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.native_to", tsection
);
2805 BV_CLR_ALL(pterrain
->native_to
);
2806 for (j
= 0; j
< nval
; j
++) {
2807 struct unit_class
*class = unit_class_by_rule_name(slist
[j
]);
2810 ruleset_error(LOG_ERROR
,
2811 "\"%s\" [%s] is native to unknown unit class \"%s\".",
2812 filename
, tsection
, slist
[j
]);
2816 BV_SET(pterrain
->native_to
, uclass_index(class));
2825 /* get terrain color */
2827 fc_assert_ret_val(pterrain
->rgb
== NULL
, FALSE
);
2828 if (!rgbcolor_load(file
, &pterrain
->rgb
, "%s.color", tsection
)) {
2829 ruleset_error(LOG_ERROR
, "Missing terrain color definition: %s",
2836 pterrain
->helptext
= lookup_strvec(file
, tsection
, "helptext");
2837 } terrain_type_iterate_end
;
2841 /* resource details */
2843 resource_type_iterate(presource
) {
2844 char identifier
[MAX_LEN_NAME
];
2845 const int i
= resource_index(presource
);
2846 const char *rsection
= &resource_sections
[i
* MAX_SECTION_LABEL
];
2848 output_type_iterate (o
) {
2849 presource
->output
[o
] =
2850 secfile_lookup_int_default(file
, 0, "%s.%s", rsection
,
2851 get_output_identifier(o
));
2852 } output_type_iterate_end
;
2853 sz_strlcpy(presource
->graphic_str
,
2854 secfile_lookup_str(file
,"%s.graphic", rsection
));
2855 sz_strlcpy(presource
->graphic_alt
,
2856 secfile_lookup_str(file
,"%s.graphic_alt", rsection
));
2858 sz_strlcpy(identifier
,
2859 secfile_lookup_str(file
,"%s.identifier", rsection
));
2860 presource
->identifier
= identifier
[0];
2861 if (RESOURCE_NULL_IDENTIFIER
== presource
->identifier
) {
2862 ruleset_error(LOG_ERROR
, "\"%s\" [%s] identifier missing value.",
2863 filename
, rsection
);
2867 if (RESOURCE_NONE_IDENTIFIER
== presource
->identifier
) {
2868 ruleset_error(LOG_ERROR
,
2869 "\"%s\" [%s] cannot use '%c' as an identifier;"
2871 filename
, rsection
, presource
->identifier
);
2875 for (j
= 0; j
< i
; j
++) {
2876 if (presource
->identifier
== resource_by_number(j
)->identifier
) {
2877 ruleset_error(LOG_ERROR
,
2878 "\"%s\" [%s] has the same identifier as [%s].",
2881 &resource_sections
[j
* MAX_SECTION_LABEL
]);
2891 } resource_type_iterate_end
;
2896 base_type_iterate(pbase
) {
2897 BV_CLR_ALL(pbase
->conflicts
);
2898 } base_type_iterate_end
;
2900 base_type_iterate(pbase
) {
2901 const char *section
= &base_sections
[base_index(pbase
) * MAX_SECTION_LABEL
];
2904 struct requirement_vector
*reqs
;
2905 const char *gui_str
;
2907 pbase
->buildable
= secfile_lookup_bool_default(file
, TRUE
,
2908 "%s.buildable", section
);
2909 pbase
->pillageable
= secfile_lookup_bool_default(file
, TRUE
,
2910 "%s.pillageable", section
);
2912 sz_strlcpy(pbase
->graphic_str
,
2913 secfile_lookup_str_default(file
, "-", "%s.graphic", section
));
2914 sz_strlcpy(pbase
->graphic_alt
,
2915 secfile_lookup_str_default(file
, "-",
2916 "%s.graphic_alt", section
));
2917 sz_strlcpy(pbase
->activity_gfx
,
2918 secfile_lookup_str_default(file
, "-",
2919 "%s.activity_gfx", section
));
2920 sz_strlcpy(pbase
->act_gfx_alt
,
2921 secfile_lookup_str_default(file
, "-",
2922 "%s.act_gfx_alt", section
));
2924 reqs
= lookup_req_list(file
, section
, "reqs", base_rule_name(pbase
));
2929 requirement_vector_copy(&pbase
->reqs
, reqs
);
2931 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.native_to", section
);
2932 BV_CLR_ALL(pbase
->native_to
);
2933 for (j
= 0; j
< nval
; j
++) {
2934 struct unit_class
*uclass
= unit_class_by_rule_name(slist
[j
]);
2936 if (uclass
== NULL
) {
2937 ruleset_error(LOG_ERROR
,
2938 "\"%s\" base \"%s\" is native to unknown unit class \"%s\".",
2940 base_rule_name(pbase
),
2945 BV_SET(pbase
->native_to
, uclass_index(uclass
));
2954 gui_str
= secfile_lookup_str(file
,"%s.gui_type", section
);
2955 pbase
->gui_type
= base_gui_type_by_name(gui_str
, fc_strcasecmp
);
2956 if (!base_gui_type_is_valid(pbase
->gui_type
)) {
2957 ruleset_error(LOG_ERROR
, "\"%s\" base \"%s\": unknown gui_type \"%s\".",
2959 base_rule_name(pbase
),
2965 if (!lookup_time(file
, &pbase
->build_time
, section
, "build_time",
2966 filename
, base_rule_name(pbase
), &ok
)) {
2967 ruleset_error(LOG_ERROR
, "%s", secfile_error());
2971 pbase
->border_sq
= secfile_lookup_int_default(file
, -1, "%s.border_sq",
2973 pbase
->vision_main_sq
= secfile_lookup_int_default(file
, -1,
2974 "%s.vision_main_sq",
2976 pbase
->vision_invis_sq
= secfile_lookup_int_default(file
, -1,
2977 "%s.vision_invis_sq",
2979 pbase
->defense_bonus
= secfile_lookup_int_default(file
, 0,
2983 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", section
);
2984 BV_CLR_ALL(pbase
->flags
);
2985 for (j
= 0; j
< nval
; j
++) {
2986 const char *sval
= slist
[j
];
2987 enum base_flag_id flag
= base_flag_id_by_name(sval
, fc_strcasecmp
);
2989 if (!base_flag_id_is_valid(flag
)) {
2990 ruleset_error(LOG_ERROR
, "\"%s\" base \"%s\": unknown flag \"%s\".",
2992 base_rule_name(pbase
),
2997 BV_SET(pbase
->flags
, flag
);
3007 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.conflicts", section
);
3008 for (j
= 0; j
< nval
; j
++) {
3009 const char *sval
= slist
[j
];
3010 struct base_type
*pbase2
= base_type_by_rule_name(sval
);
3012 if (pbase2
== NULL
) {
3013 ruleset_error(LOG_ERROR
, "\"%s\" base \"%s\": unknown conflict base \"%s\".",
3015 base_rule_name(pbase
),
3020 BV_SET(pbase
->conflicts
, base_index(pbase2
));
3021 BV_SET(pbase2
->conflicts
, base_index(pbase
));
3031 if (territory_claiming_base(pbase
)) {
3032 base_type_iterate(pbase2
) {
3033 if (pbase
== pbase2
) {
3034 /* End of the fully initialized bases iteration. */
3037 if (territory_claiming_base(pbase2
)) {
3038 BV_SET(pbase
->conflicts
, base_index(pbase2
));
3039 BV_SET(pbase2
->conflicts
, base_index(pbase
));
3041 } base_type_iterate_end
;
3044 pbase
->helptext
= lookup_strvec(file
, section
, "helptext");
3045 } base_type_iterate_end
;
3049 road_type_iterate(proad
) {
3050 const char *section
= &road_sections
[road_index(proad
) * MAX_SECTION_LABEL
];
3052 struct requirement_vector
*reqs
;
3053 const char *special
;
3054 const char *modestr
;
3056 sz_strlcpy(proad
->graphic_str
,
3057 secfile_lookup_str_default(file
, "-", "%s.graphic", section
));
3058 sz_strlcpy(proad
->graphic_alt
,
3059 secfile_lookup_str_default(file
, "-",
3060 "%s.graphic_alt", section
));
3061 sz_strlcpy(proad
->activity_gfx
,
3062 secfile_lookup_str_default(file
, "-",
3063 "%s.activity_gfx", section
));
3064 sz_strlcpy(proad
->act_gfx_alt
,
3065 secfile_lookup_str_default(file
, "-",
3066 "%s.act_gfx_alt", section
));
3068 if (!secfile_lookup_int(file
, &proad
->move_cost
,
3069 "%s.move_cost", section
)) {
3070 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
3075 modestr
= secfile_lookup_str_default(file
, "FastAlways", "%s.move_mode",
3077 proad
->move_mode
= road_move_mode_by_name(modestr
, fc_strcasecmp
);
3078 if (!road_move_mode_is_valid(proad
->move_mode
)) {
3079 ruleset_error(LOG_ERROR
, "Illegal move_type \"%s\" for road \"%s\"",
3080 modestr
, road_rule_name(proad
));
3085 proad
->build_time
= 0; /* default */
3086 lookup_time(file
, &proad
->build_time
, section
, "build_time",
3087 filename
, road_rule_name(proad
), &ok
);
3089 proad
->defense_bonus
= secfile_lookup_int_default(file
, 0,
3093 proad
->buildable
= secfile_lookup_bool_default(file
, TRUE
,
3094 "%s.buildable", section
);
3095 proad
->pillageable
= secfile_lookup_bool_default(file
, TRUE
,
3096 "%s.pillageable", section
);
3098 output_type_iterate(o
) {
3099 proad
->tile_incr_const
[o
] =
3100 secfile_lookup_int_default(file
, 0, "%s.%s_incr_const",
3101 section
, get_output_identifier(o
));
3102 proad
->tile_incr
[o
] =
3103 secfile_lookup_int_default(file
, 0, "%s.%s_incr",
3104 section
, get_output_identifier(o
));
3105 proad
->tile_bonus
[o
] =
3106 secfile_lookup_int_default(file
, 0, "%s.%s_bonus",
3107 section
, get_output_identifier(o
));
3108 } output_type_iterate_end
;
3110 reqs
= lookup_req_list(file
, section
, "reqs", road_rule_name(proad
));
3115 requirement_vector_copy(&proad
->reqs
, reqs
);
3117 special
= secfile_lookup_str_default(file
, "None", "%s.compat_special", section
);
3118 if (!fc_strcasecmp(special
, "Road")) {
3120 ruleset_error(LOG_ERROR
, "Multiple roads marked as compatibility \"Road\"");
3124 proad
->compat
= ROCO_ROAD
;
3125 } else if (!fc_strcasecmp(special
, "Railroad")) {
3127 ruleset_error(LOG_ERROR
, "Multiple roads marked as compatibility \"Railroad\"");
3131 proad
->compat
= ROCO_RAILROAD
;
3132 } else if (!fc_strcasecmp(special
, "River")) {
3134 ruleset_error(LOG_ERROR
, "Multiple roads marked as compatibility \"River\"");
3137 compat_river
= TRUE
;
3138 proad
->compat
= ROCO_RIVER
;
3139 } else if (!fc_strcasecmp(special
, "None")) {
3140 proad
->compat
= ROCO_NONE
;
3142 ruleset_error(LOG_ERROR
, "Illegal compatibility special \"%s\" for road %s",
3143 special
, road_rule_name(proad
));
3151 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.native_to", section
);
3152 BV_CLR_ALL(proad
->native_to
);
3153 for (j
= 0; j
< nval
; j
++) {
3154 struct unit_class
*uclass
= unit_class_by_rule_name(slist
[j
]);
3157 ruleset_error(LOG_ERROR
,
3158 "\"%s\" road \"%s\" is native to unknown unit class \"%s\".",
3160 road_rule_name(proad
),
3165 BV_SET(proad
->native_to
, uclass_index(uclass
));
3174 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.hidden_by", section
);
3175 BV_CLR_ALL(proad
->hidden_by
);
3176 for (j
= 0; j
< nval
; j
++) {
3177 const char *sval
= slist
[j
];
3178 const struct road_type
*top
= road_type_by_rule_name(sval
);
3181 ruleset_error(LOG_ERROR
, "\"%s\" road \"%s\" hidden by unknown road \"%s\".",
3183 road_rule_name(proad
),
3188 BV_SET(proad
->hidden_by
, road_index(top
));
3197 slist
= secfile_lookup_str_vec(file
, &nval
, "%s.flags", section
);
3198 BV_CLR_ALL(proad
->flags
);
3199 for (j
= 0; j
< nval
; j
++) {
3200 const char *sval
= slist
[j
];
3201 enum road_flag_id flag
= road_flag_id_by_name(sval
, fc_strcasecmp
);
3203 if (!road_flag_id_is_valid(flag
)) {
3204 ruleset_error(LOG_ERROR
, "\"%s\" road \"%s\": unknown flag \"%s\".",
3206 road_rule_name(proad
),
3211 BV_SET(proad
->flags
, flag
);
3220 proad
->helptext
= lookup_strvec(file
, section
, "helptext");
3222 } road_type_iterate_end
;
3226 secfile_check_unused(file
);
3232 /**************************************************************************
3233 Load names of governments so other rulesets can refer to governments with
3235 **************************************************************************/
3236 static bool load_government_names(struct section_file
*file
)
3239 struct section_list
*sec
;
3240 const char *filename
= secfile_name(file
);
3243 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
3245 sec
= secfile_sections_by_name_prefix(file
, GOVERNMENT_SECTION_PREFIX
);
3246 if (NULL
== sec
|| 0 == (nval
= section_list_size(sec
))) {
3247 ruleset_error(LOG_ERROR
, "\"%s\": No governments?!?", filename
);
3249 } else if (nval
> G_MAGIC
) {
3250 /* upper limit is really about 255 for 8-bit id values, but
3251 use G_MAGIC elsewhere as a sanity check, and should be plenty
3253 ruleset_error(LOG_ERROR
, "\"%s\": Too many governments (%d, max %d)",
3254 filename
, nval
, G_MAGIC
);
3259 governments_alloc(nval
);
3261 /* Government names are needed early so that get_government_by_name will
3263 governments_iterate(gov
) {
3264 const char *sec_name
=
3265 section_name(section_list_get(sec
, government_index(gov
)));
3267 if (!ruleset_load_names(&gov
->name
, NULL
, file
, sec_name
)) {
3271 } governments_iterate_end
;
3274 section_list_destroy(sec
);
3279 /**************************************************************************
3280 This loads information from given governments.ruleset
3281 **************************************************************************/
3282 static bool load_ruleset_governments(struct section_file
*file
)
3284 struct section_list
*sec
;
3285 const char *filename
= secfile_name(file
);
3288 if (check_ruleset_capabilities(file
, RULESET_CAPABILITIES
, filename
) == NULL
) {
3292 sec
= secfile_sections_by_name_prefix(file
, GOVERNMENT_SECTION_PREFIX
);
3294 game
.government_during_revolution
3295 = lookup_government(file
, "governments.during_revolution", filename
, NULL
);
3296 if (game
.government_during_revolution
== NULL
) {
3301 game
.info
.government_during_revolution_id
=
3302 government_number(game
.government_during_revolution
);
3305 governments_iterate(g
) {
3306 const int i
= government_index(g
);
3307 const char *sec_name
= section_name(section_list_get(sec
, i
));
3308 struct requirement_vector
*reqs
=
3309 lookup_req_list(file
, sec_name
, "reqs", government_rule_name(g
));
3316 if (NULL
!= secfile_entry_lookup(file
, "%s.ai_better", sec_name
)) {
3319 fc_snprintf(entry
, sizeof(entry
), "%s.ai_better", sec_name
);
3320 g
->ai
.better
= lookup_government(file
, entry
, filename
, NULL
);
3321 if (g
->ai
.better
== NULL
) {
3326 g
->ai
.better
= NULL
;
3328 requirement_vector_copy(&g
->reqs
, reqs
);
3330 sz_strlcpy(g
->graphic_str
,
3331 secfile_lookup_str(file
, "%s.graphic", sec_name
));
3332 sz_strlcpy(g
->graphic_alt
,
3333 secfile_lookup_str(file
, "%s.graphic_alt", sec_name
));
3335 g
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
3336 } governments_iterate_end
;
3342 governments_iterate(g
) {
3343 const char *sec_name
=
3344 section_name(section_list_get(sec
, government_index(g
)));
3345 const char *male
, *female
;
3347 if (!(male
= secfile_lookup_str(file
, "%s.ruler_male_title", sec_name
))
3348 || !(female
= secfile_lookup_str(file
, "%s.ruler_female_title",
3350 ruleset_error(LOG_ERROR
, "Lack of default ruler titles for "
3351 "government \"%s\" (nb %d): %s",
3352 government_rule_name(g
), government_number(g
),
3356 } else if (NULL
== government_ruler_title_new(g
, NULL
, male
, female
)) {
3357 ruleset_error(LOG_ERROR
, "Lack of default ruler titles for "
3358 "government \"%s\" (nb %d).",
3359 government_rule_name(g
), government_number(g
));
3363 } governments_iterate_end
;
3366 section_list_destroy(sec
);
3369 secfile_check_unused(file
);
3375 /**************************************************************************
3376 Send information in packet_ruleset_control (numbers of units etc, and
3377 other miscellany) to specified connections.
3379 The client assumes that exactly one ruleset control packet is sent as
3380 a part of each ruleset send. So after sending this packet we have to
3381 resend every other part of the rulesets (and none of them should be
3382 is-info in the network code!). The client frees ruleset data when
3383 receiving this packet and then re-initializes as it receives the
3384 individual ruleset packets. See packhand.c.
3385 **************************************************************************/
3386 static void send_ruleset_control(struct conn_list
*dest
)
3388 struct packet_ruleset_control packet
;
3390 packet
= game
.control
;
3391 lsend_packet_ruleset_control(dest
, &packet
);
3394 /****************************************************************************
3395 This checks if nations[pos] leader names are not already defined in any
3396 previous nation, or twice in its own leader name table.
3397 If not return NULL, if yes return pointer to name which is repeated
3398 and id of a conflicting nation as second parameter.
3399 ****************************************************************************/
3400 static const char *check_leader_names(struct nation_type
*pnation
,
3401 struct nation_type
**ppconflict_nation
)
3403 nation_leader_list_iterate(nation_leaders(pnation
), pleader
) {
3404 const char *name
= nation_leader_name(pleader
);
3406 nation_leader_list_iterate(nation_leaders(pnation
), prev_leader
) {
3407 if (prev_leader
== pleader
) {
3409 } else if (0 == fc_strcasecmp(name
, nation_leader_name(prev_leader
))) {
3410 *ppconflict_nation
= pnation
;
3413 } nation_leader_list_iterate_end
;
3414 } nation_leader_list_iterate_end
;
3416 nations_iterate(prev_nation
) {
3417 if (prev_nation
== pnation
) {
3421 nation_leader_list_iterate(nation_leaders(prev_nation
), pleader
) {
3422 const char *name
= nation_leader_name(pleader
);
3424 nation_leader_list_iterate(nation_leaders(prev_nation
), prev_leader
) {
3425 if (prev_leader
== pleader
) {
3427 } else if (0 == fc_strcasecmp(name
,
3428 nation_leader_name(prev_leader
))) {
3429 *ppconflict_nation
= prev_nation
;
3432 } nation_leader_list_iterate_end
;
3433 } nation_leader_list_iterate_end
;
3434 } nations_iterate_end
;
3438 /**************************************************************************
3439 Load names of nations so other rulesets can refer to nations with
3441 **************************************************************************/
3442 static bool load_nation_names(struct section_file
*file
)
3444 struct section_list
*sec
;
3448 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
3450 sec
= secfile_sections_by_name_prefix(file
, NATION_SECTION_PREFIX
);
3452 ruleset_error(LOG_ERROR
, "No available nations in this ruleset!");
3454 } else if (section_list_size(sec
) > MAX_NUM_NATIONS
) {
3455 ruleset_error(LOG_ERROR
, "Too many nations (max %d, we have %d)!",
3456 MAX_NUM_NATIONS
, section_list_size(sec
));
3459 game
.control
.nation_count
= section_list_size(sec
);
3460 nations_alloc(game
.control
.nation_count
);
3462 nations_iterate(pl
) {
3463 const int i
= nation_index(pl
);
3464 const char *sec_name
= section_name(section_list_get(sec
, i
));
3465 const char *domain
= secfile_lookup_str_default(file
, NULL
,
3466 "%s.translation_domain", sec_name
);
3467 const char *noun_plural
= secfile_lookup_str(file
,
3468 "%s.plural", sec_name
);
3471 if (domain
== NULL
) {
3472 domain
= "freeciv-nations";
3475 if (!strcmp("freeciv", domain
)) {
3476 pl
->translation_domain
= NULL
;
3477 } else if (!strcmp("freeciv-nations", domain
)) {
3478 pl
->translation_domain
= fc_malloc(strlen(domain
) + 1);
3479 strcpy(pl
->translation_domain
, domain
);
3481 ruleset_error(LOG_ERROR
, "Unsupported translation domain \"%s\" for %s",
3487 if (!ruleset_load_names(&pl
->adjective
, domain
, file
, sec_name
)) {
3491 name_set(&pl
->noun_plural
, domain
, noun_plural
);
3493 /* Check if nation name is already defined. */
3494 for (j
= 0; j
< i
&& ok
; j
++) {
3495 struct nation_type
*n2
= nation_by_number(j
);
3497 /* Compare strings after stripping off qualifiers -- we don't want
3498 * two nations to end up with identical adjectives displayed to users.
3499 * (This check only catches English, not localisations, of course.) */
3500 if (0 == strcmp(Qn_(untranslated_name(&n2
->adjective
)),
3501 Qn_(untranslated_name(&pl
->adjective
)))) {
3502 ruleset_error(LOG_ERROR
,
3503 "Two nations defined with the same adjective \"%s\": "
3504 "in section \'%s\' and section \'%s\'",
3505 Qn_(untranslated_name(&pl
->adjective
)),
3506 section_name(section_list_get(sec
, j
)), sec_name
);
3508 } else if (0 == strcmp(rule_name(&n2
->adjective
),
3509 rule_name(&pl
->adjective
))) {
3510 /* We cannot have the same rule name, as the game needs them to be
3512 ruleset_error(LOG_ERROR
,
3513 "Two nations defined with the same rule_name \"%s\": "
3514 "in section \'%s\' and section \'%s\'",
3515 rule_name(&pl
->adjective
),
3516 section_name(section_list_get(sec
, j
)), sec_name
);
3518 } else if (0 == strcmp(Qn_(untranslated_name(&n2
->noun_plural
)),
3519 Qn_(untranslated_name(&pl
->noun_plural
)))) {
3520 /* We don't want identical English plural names either. */
3521 ruleset_error(LOG_ERROR
,
3522 "Two nations defined with the same plural name \"%s\": "
3523 "in section \'%s\' and section \'%s\'",
3524 Qn_(untranslated_name(&pl
->noun_plural
)),
3525 section_name(section_list_get(sec
, j
)), sec_name
);
3532 } nations_iterate_end
;
3535 section_list_destroy(sec
);
3540 /**************************************************************************
3541 Check if a string is in a vector (case-insensitively).
3542 **************************************************************************/
3543 static bool is_on_allowed_list(const char *name
, const char **list
, size_t len
)
3546 for (i
= 0; i
< len
; i
++) {
3547 if (!fc_strcasecmp(name
, list
[i
])) {
3554 /****************************************************************************
3555 This function loads a city name list from a section file. The file and
3556 two section names (which will be concatenated) are passed in.
3557 ****************************************************************************/
3558 static bool load_city_name_list(struct section_file
*file
,
3559 struct nation_type
*pnation
,
3560 const char *secfile_str1
,
3561 const char *secfile_str2
,
3562 const char **allowed_terrains
,
3567 const char **cities
= secfile_lookup_str_vec(file
, &dim
, "%s.%s",
3568 secfile_str1
, secfile_str2
);
3570 /* Each string will be of the form "<cityname> (<label>, <label>, ...)".
3571 * The cityname is just the name for this city, while each "label" matches
3572 * a terrain type for the city (or "river"), with a preceeding ! to negate
3573 * it. The parentheses are optional (but necessary to have the settings,
3574 * of course). Our job is now to parse it. */
3575 for (j
= 0; j
< dim
; j
++) {
3576 size_t len
= strlen(cities
[j
]);
3577 char city_name
[len
+ 1], *p
, *next
, *end
;
3578 struct nation_city
*pncity
;
3580 sz_strlcpy(city_name
, cities
[j
]);
3582 /* Now we wish to determine values for all of the city labels. A value
3583 * of NCP_NONE means no preference (which is necessary so that the use
3584 * of this is optional); NCP_DISLIKE means the label is negated and
3585 * NCP_LIKE means it's labelled. Mostly the parsing just involves
3586 * a lot of ugly string handling... */
3587 if ((p
= strchr(city_name
, '('))) {
3590 if (!(end
= strchr(p
, ')'))) {
3591 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city name \"%s\" "
3592 "unmatched parenthesis.", secfile_name(file
),
3593 secfile_str1
, secfile_str2
, cities
[j
]);
3596 for (*end
++ = '\0'; '\0' != *end
; end
++) {
3597 if (!fc_isspace(*end
)) {
3598 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city name \"%s\" "
3599 "contains characters after last parenthesis.",
3600 secfile_name(file
), secfile_str1
, secfile_str2
,
3609 /* Build the nation_city. */
3610 remove_leading_trailing_spaces(city_name
);
3611 if (check_name(city_name
)) {
3612 /* The ruleset contains a name that is too long. This shouldn't
3613 * happen - if it does, the author should get immediate feedback. */
3614 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city name \"%s\" "
3615 "is too long.", secfile_name(file
),
3616 secfile_str1
, secfile_str2
, city_name
);
3618 city_name
[MAX_LEN_NAME
- 1] = '\0';
3620 pncity
= nation_city_new(pnation
, city_name
);
3623 /* Handle the labels one at a time. */
3625 enum nation_city_preference prefer
;
3627 if ((next
= strchr(p
, ','))) {
3630 remove_leading_trailing_spaces(p
);
3632 /* The ! is used to mark a negative, which is recorded with
3633 * NCP_DISLIKE. Otherwise we use a NCP_LIKE.
3637 prefer
= NCP_DISLIKE
;
3642 if (0 == fc_strcasecmp(p
, "river")) {
3643 if (allowed_terrains
3644 && !is_on_allowed_list(p
, allowed_terrains
, atcount
)) {
3645 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city \"%s\" "
3646 "has terrain hint \"%s\" not in allowed_terrains.",
3647 secfile_name(file
), secfile_str1
, secfile_str2
,
3651 nation_city_set_river_preference(pncity
, prefer
);
3654 const struct terrain
*pterrain
= terrain_by_rule_name(p
);
3656 if (NULL
== pterrain
) {
3657 /* Try with removing frequent trailing 's'. */
3658 size_t l
= strlen(p
);
3660 if (0 < l
&& 's' == fc_tolower(p
[l
- 1])) {
3663 pterrain
= terrain_by_rule_name(p
);
3666 /* Nationset may have been devised with a specific set of terrains
3667 * in mind which don't quite match this ruleset, in which case we
3668 * (a) quietly ignore any hints mentioned that don't happen to be in
3669 * the current ruleset, (b) enforce that terrains mentioned by nations
3670 * must be on the list */
3671 if (pterrain
&& allowed_terrains
) {
3672 if (!is_on_allowed_list(p
, allowed_terrains
, atcount
)) {
3673 /* Terrain exists, but not intended for these nations */
3674 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city \"%s\" "
3675 "has terrain hint \"%s\" not in allowed_terrains.",
3676 secfile_name(file
), secfile_str1
, secfile_str2
,
3681 } else if (!pterrain
) {
3682 /* Terrain doesn't exist; only complain if it's not on any list */
3683 if (!allowed_terrains
3684 || !is_on_allowed_list(p
, allowed_terrains
, atcount
)) {
3685 ruleset_error(LOG_ERROR
, "\"%s\" [%s] %s: city \"%s\" "
3686 "has unknown terrain hint \"%s\".",
3687 secfile_name(file
), secfile_str1
, secfile_str2
,
3693 if (NULL
!= pterrain
) {
3694 nation_city_set_terrain_preference(pncity
, pterrain
, prefer
);
3698 p
= next
? next
+ 1 : NULL
;
3699 } while (NULL
!= p
&& '\0' != *p
);
3703 if (NULL
!= cities
) {
3710 /**************************************************************************
3711 Load nations.ruleset file
3712 **************************************************************************/
3713 static bool load_ruleset_nations(struct section_file
*file
)
3715 struct government
*gov
;
3718 char temp_name
[MAX_LEN_NAME
];
3720 const char *name
, *bad_leader
;
3722 struct government
*default_government
= NULL
;
3724 const char *filename
= secfile_name(file
);
3725 struct section_list
*sec
;
3726 int default_traits
[TRAIT_COUNT
];
3728 const char **allowed_govs
, **allowed_terrains
, **allowed_cstyles
;
3729 size_t agcount
, atcount
, acscount
;
3732 if (check_ruleset_capabilities(file
, RULESET_CAPABILITIES
, filename
) == NULL
) {
3736 ruleset_load_traits(default_traits
, file
, "default_traits", "");
3737 for (tr
= trait_begin(); tr
!= trait_end(); tr
= trait_next(tr
)) {
3738 if (default_traits
[tr
] < 0) {
3739 default_traits
[tr
] = TRAIT_DEFAULT_VALUE
;
3743 allowed_govs
= secfile_lookup_str_vec(file
, &agcount
,
3744 "compatibility.allowed_govs");
3745 allowed_terrains
= secfile_lookup_str_vec(file
, &atcount
,
3746 "compatibility.allowed_terrains");
3747 allowed_cstyles
= secfile_lookup_str_vec(file
, &acscount
,
3748 "compatibility.allowed_city_styles");
3750 sval
= secfile_lookup_str_default(file
, NULL
,
3751 "compatibility.default_government");
3752 /* We deliberately don't check this against allowed_govs. It's only
3753 * specified once so not vulnerable to typos, and may usefully be set in
3754 * a specific ruleset to a gov not explicitly known by the nation set. */
3756 default_government
= government_by_rule_name(sval
);
3759 sec
= secfile_sections_by_name_prefix(file
, NATION_SET_SECTION_PREFIX
);
3761 section_list_iterate(sec
, psection
) {
3762 const char *set_name
, *set_rule_name
, *set_description
;
3764 set_name
= secfile_lookup_str(file
, "%s.name", section_name(psection
));
3766 secfile_lookup_str(file
, "%s.rule_name", section_name(psection
));
3767 set_description
= secfile_lookup_str_default(file
, "", "%s.description",
3768 section_name(psection
));
3769 if (NULL
== set_name
|| NULL
== set_rule_name
) {
3770 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
3774 if (nation_set_new(set_name
, set_rule_name
, set_description
) == NULL
) {
3778 } section_list_iterate_end
;
3779 section_list_destroy(sec
);
3782 ruleset_error(LOG_ERROR
,
3783 "At least one nation set [" NATION_SET_SECTION_PREFIX
"_*] "
3784 "must be defined.");
3789 /* Default set that every nation is a member of. */
3790 sval
= secfile_lookup_str_default(file
, NULL
,
3791 "compatibility.default_nationset");
3793 const struct nation_set
*pset
= nation_set_by_rule_name(sval
);
3795 default_set
= nation_set_number(pset
);
3797 ruleset_error(LOG_ERROR
,
3798 "Unknown default_nationset \"%s\".", sval
);
3801 } else if (nation_set_count() == 1) {
3802 /* If there's only one set defined, every nation is implicitly a
3803 * member of that set. */
3806 /* No default nation set; every nation must explicitly specify at
3807 * least one set to be a member of. */
3813 sec
= secfile_sections_by_name_prefix(file
, NATION_GROUP_SECTION_PREFIX
);
3815 section_list_iterate(sec
, psection
) {
3816 struct nation_group
*pgroup
;
3818 name
= secfile_lookup_str(file
, "%s.name", section_name(psection
));
3820 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
3824 pgroup
= nation_group_new(name
);
3825 if (pgroup
== NULL
) {
3829 if (!secfile_lookup_int(file
, &j
, "%s.match", section_name(psection
))) {
3830 ruleset_error(LOG_ERROR
, "Error: %s", secfile_error());
3834 nation_group_set_match(pgroup
, j
);
3835 } section_list_iterate_end
;
3836 section_list_destroy(sec
);
3842 sec
= secfile_sections_by_name_prefix(file
, NATION_SECTION_PREFIX
);
3843 nations_iterate(pnation
) {
3844 struct nation_type
*pconflict
;
3845 const int i
= nation_index(pnation
);
3846 char tmp
[200] = "\0";
3847 const char *barb_type
;
3848 const char *sec_name
= section_name(section_list_get(sec
, i
));
3850 /* Nation sets and groups. */
3851 if (default_set
>= 0) {
3852 nation_set_list_append(pnation
->sets
,
3853 nation_set_by_number(default_set
));
3855 vec
= secfile_lookup_str_vec(file
, &dim
, "%s.groups", sec_name
);
3856 for (j
= 0; j
< dim
; j
++) {
3857 struct nation_set
*pset
= nation_set_by_rule_name(vec
[j
]);
3858 struct nation_group
*pgroup
= nation_group_by_rule_name(vec
[j
]);
3860 fc_assert(pset
== NULL
|| pgroup
== NULL
);
3863 nation_set_list_append(pnation
->sets
, pset
);
3864 } else if (NULL
!= pgroup
) {
3865 nation_group_list_append(pnation
->groups
, pgroup
);
3867 /* For nation authors, this would probably be considered an error.
3868 * But it can happen normally. The civ1 compatibility ruleset only
3869 * uses the nations that were in civ1, so not all of the links will
3871 log_verbose("Nation %s: Unknown set/group \"%s\".",
3872 nation_rule_name(pnation
), vec
[j
]);
3878 if (nation_set_list_size(pnation
->sets
) < 1) {
3879 ruleset_error(LOG_ERROR
,
3880 "Nation %s is not a member of any nation set",
3881 nation_rule_name(pnation
));
3886 /* Nation conflicts. */
3887 vec
= secfile_lookup_str_vec(file
, &dim
, "%s.conflicts_with", sec_name
);
3888 for (j
= 0; j
< dim
; j
++) {
3889 pconflict
= nation_by_rule_name(vec
[j
]);
3891 if (pnation
== pconflict
) {
3892 ruleset_error(LOG_ERROR
, "Nation %s conflicts with itself",
3893 nation_rule_name(pnation
));
3896 } else if (NULL
!= pconflict
) {
3897 nation_list_append(pnation
->server
.conflicts_with
, pconflict
);
3899 /* For nation authors, this would probably be considered an error.
3900 * But it can happen normally. The civ1 compatibility ruleset only
3901 * uses the nations that were in civ1, so not all of the links will
3903 log_verbose("Nation %s: conflicts_with nation \"%s\" is unknown.",
3904 nation_rule_name(pnation
), vec
[j
]);
3914 /* Nation leaders. */
3915 for (j
= 0; j
< MAX_NUM_LEADERS
; j
++) {
3917 bool is_male
= FALSE
;
3919 name
= secfile_lookup_str(file
, "%s.leaders%d.name", sec_name
, j
);
3921 /* No more to read. */
3925 if (check_name(name
)) {
3926 /* The ruleset contains a name that is too long. This shouldn't
3927 * happen - if it does, the author should get immediate feedback */
3928 sz_strlcpy(temp_name
, name
);
3929 ruleset_error(LOG_ERROR
, "Nation %s: leader name \"%s\" "
3931 nation_rule_name(pnation
), name
);
3936 sex
= secfile_lookup_str(file
, "%s.leaders%d.sex", sec_name
, j
);
3938 ruleset_error(LOG_ERROR
, "Nation %s: leader \"%s\": %s.",
3939 nation_rule_name(pnation
), name
, secfile_error());
3942 } else if (0 == fc_strcasecmp("Male", sex
)) {
3944 } else if (0 != fc_strcasecmp("Female", sex
)) {
3945 ruleset_error(LOG_ERROR
, "Nation %s: leader \"%s\" has unsupported "
3946 "sex variant \"%s\".",
3947 nation_rule_name(pnation
), name
, sex
);
3951 (void) nation_leader_new(pnation
, name
, is_male
);
3957 /* Check the number of leaders. */
3958 if (MAX_NUM_LEADERS
== j
) {
3959 /* Too much leaders, get the real number defined in the ruleset. */
3960 while (NULL
!= secfile_entry_lookup(file
, "%s.leaders%d.name",
3964 ruleset_error(LOG_ERROR
, "Nation %s: Too many leaders; max is %d",
3965 nation_rule_name(pnation
), MAX_NUM_LEADERS
);
3968 } else if (0 == j
) {
3969 ruleset_error(LOG_ERROR
,
3970 "Nation %s: no leaders; at least one is required.",
3971 nation_rule_name(pnation
));
3976 /* Check if leader name is not already defined */
3977 if ((bad_leader
= check_leader_names(pnation
, &pconflict
))) {
3978 if (pnation
== pconflict
) {
3979 ruleset_error(LOG_ERROR
,
3980 "Nation %s: leader \"%s\" defined more than once.",
3981 nation_rule_name(pnation
), bad_leader
);
3985 ruleset_error(LOG_ERROR
,
3986 "Nations %s and %s share the same leader \"%s\".",
3987 nation_rule_name(pnation
), nation_rule_name(pconflict
),
3994 /* Nation player color preference, if any */
3995 fc_assert_ret_val(pnation
->server
.rgb
== NULL
, FALSE
);
3996 (void) rgbcolor_load(file
, &pnation
->server
.rgb
, "%s.color", sec_name
);
3998 /* Load nation traits */
3999 ruleset_load_traits(pnation
->server
.traits
, file
, sec_name
, "trait_");
4000 for (tr
= trait_begin(); tr
!= trait_end(); tr
= trait_next(tr
)) {
4001 if (pnation
->server
.traits
[tr
] < 0) {
4002 pnation
->server
.traits
[tr
] = default_traits
[tr
];
4006 pnation
->is_playable
=
4007 secfile_lookup_bool_default(file
, TRUE
, "%s.is_playable", sec_name
);
4009 /* Check barbarian type. Default is "None" meaning not a barbarian */
4010 barb_type
= secfile_lookup_str_default(file
, "None",
4011 "%s.barbarian_type", sec_name
);
4012 if (fc_strcasecmp(barb_type
, "None") == 0) {
4013 pnation
->barb_type
= NOT_A_BARBARIAN
;
4014 } else if (fc_strcasecmp(barb_type
, "Land") == 0) {
4015 if (pnation
->is_playable
) {
4016 /* We can't allow players to use barbarian nations, barbarians
4017 * may run out of nations */
4018 ruleset_error(LOG_ERROR
,
4019 "Nation %s marked both barbarian and playable.",
4020 nation_rule_name(pnation
));
4024 pnation
->barb_type
= LAND_BARBARIAN
;
4025 } else if (fc_strcasecmp(barb_type
, "Sea") == 0) {
4026 if (pnation
->is_playable
) {
4027 /* We can't allow players to use barbarian nations, barbarians
4028 * may run out of nations */
4029 ruleset_error(LOG_ERROR
,
4030 "Nation %s marked both barbarian and playable.",
4031 nation_rule_name(pnation
));
4035 pnation
->barb_type
= SEA_BARBARIAN
;
4037 ruleset_error(LOG_ERROR
,
4038 "Nation %s, barbarian_type is \"%s\". Must be "
4039 "\"None\" or \"Land\" or \"Sea\".",
4040 nation_rule_name(pnation
), barb_type
);
4046 sz_strlcpy(pnation
->flag_graphic_str
,
4047 secfile_lookup_str_default(file
, "-", "%s.flag", sec_name
));
4048 sz_strlcpy(pnation
->flag_graphic_alt
,
4049 secfile_lookup_str_default(file
, "-",
4050 "%s.flag_alt", sec_name
));
4054 const char *male
, *female
;
4056 name
= secfile_lookup_str_default(file
, NULL
,
4057 "%s.ruler_titles%d.government",
4060 /* End of the list of ruler titles. */
4064 /* NB: even if the government doesn't exist, we load the entries for
4065 * the ruler titles to avoid warnings about unused entries. */
4066 male
= secfile_lookup_str(file
, "%s.ruler_titles%d.male_title",
4068 female
= secfile_lookup_str(file
, "%s.ruler_titles%d.female_title",
4070 gov
= government_by_rule_name(name
);
4072 /* Nationset may have been devised with a specific set of govs in
4073 * mind which don't quite match this ruleset, in which case we
4074 * (a) quietly ignore any govs mentioned that don't happen to be in
4075 * the current ruleset, (b) enforce that govs mentioned by nations
4076 * must be on the list */
4077 if (gov
&& allowed_govs
) {
4078 if (!is_on_allowed_list(name
, allowed_govs
, agcount
)) {
4079 /* Gov exists, but not intended for these nations */
4081 ruleset_error(LOG_ERROR
,
4082 "Nation %s: government \"%s\" not in allowed_govs.",
4083 nation_rule_name(pnation
), name
);
4088 /* Gov doesn't exist; only complain if it's not on any list */
4090 || !is_on_allowed_list(name
, allowed_govs
, agcount
)) {
4091 ruleset_error(LOG_ERROR
, "Nation %s: government \"%s\" not found.",
4092 nation_rule_name(pnation
), name
);
4097 if (NULL
!= male
&& NULL
!= female
) {
4099 (void) government_ruler_title_new(gov
, pnation
, male
, female
);
4102 ruleset_error(LOG_ERROR
, "%s", secfile_error());
4112 name
= secfile_lookup_str(file
, "%s.city_style", sec_name
);
4114 ruleset_error(LOG_ERROR
, "%s", secfile_error());
4118 pnation
->city_style
= city_style_by_rule_name(name
);
4120 if (0 <= pnation
->city_style
&& allowed_cstyles
) {
4121 if (!is_on_allowed_list(name
, allowed_cstyles
, acscount
)) {
4122 /* Style exists, but not intended for these nations */
4123 pnation
->city_style
= 0;
4124 ruleset_error(LOG_ERROR
,
4125 "Nation %s: city style \"%s\" not in "
4126 "allowed_city_styles.",
4127 nation_rule_name(pnation
), name
);
4131 } else if (0 > pnation
->city_style
) {
4132 /* City style doesn't exist, so fall back to default; but only
4133 * complain if it's not on any list */
4134 pnation
->city_style
= 0;
4135 if (!allowed_cstyles
4136 || !is_on_allowed_list(name
, allowed_cstyles
, acscount
)) {
4137 ruleset_error(LOG_ERROR
, "Nation %s: city style \"%s\" not found.",
4138 nation_rule_name(pnation
), name
);
4142 log_verbose("Nation %s: city style \"%s\" not supported in this "
4143 "ruleset; using default.",
4144 nation_rule_name(pnation
), name
);
4148 while (city_style_has_requirements(city_styles
+ pnation
->city_style
)) {
4149 if (pnation
->city_style
== 0) {
4150 ruleset_error(LOG_ERROR
,
4151 "Nation %s: the default city style is not available "
4152 "from the beginning!", nation_rule_name(pnation
));
4153 /* Note that we can't use temp_name here. */
4157 ruleset_error(LOG_ERROR
,
4158 "Nation %s: city style \"%s\" is not available "
4159 "from beginning; using default.",
4160 nation_rule_name(pnation
), name
);
4161 pnation
->city_style
= 0;
4164 /* Civilwar nations */
4165 vec
= secfile_lookup_str_vec(file
, &dim
,
4166 "%s.civilwar_nations", sec_name
);
4167 for (j
= 0; j
< dim
; j
++) {
4168 pconflict
= nation_by_rule_name(vec
[j
]);
4170 /* No test for duplicate nations is performed. If there is a duplicate
4171 * entry it will just cause that nation to have an increased
4172 * probability of being chosen. */
4173 if (pconflict
== pnation
) {
4174 ruleset_error(LOG_ERROR
, "Nation %s is its own civil war nation",
4175 nation_rule_name(pnation
));
4178 } else if (NULL
!= pconflict
) {
4179 nation_list_append(pnation
->server
.civilwar_nations
, pconflict
);
4180 nation_list_append(pconflict
->server
.parent_nations
, pnation
);
4182 /* For nation authors, this would probably be considered an error.
4183 * But it can happen normally. The civ1 compatability ruleset only
4184 * uses the nations that were in civ1, so not all of the links will
4186 log_verbose("Nation %s: civil war nation \"%s\" is unknown.",
4187 nation_rule_name(pnation
), vec
[j
]);
4197 /* Load nation specific initial items */
4198 if (!lookup_tech_list(file
, sec_name
, "init_techs",
4199 pnation
->init_techs
, filename
)) {
4203 if (!lookup_building_list(file
, sec_name
, "init_buildings",
4204 pnation
->init_buildings
, filename
)) {
4208 if (!lookup_unit_list(file
, sec_name
, "init_units",
4209 pnation
->init_units
, filename
)) {
4213 fc_strlcat(tmp
, sec_name
, 200);
4214 fc_strlcat(tmp
, ".init_government", 200);
4215 pnation
->init_government
= lookup_government(file
, tmp
, filename
,
4216 default_government
);
4217 /* init_government has to be in this specific ruleset, not just
4219 if (pnation
->init_government
== NULL
) {
4223 /* ...but if a list of govs has been specified, enforce that this
4224 * nation's init_government is on the list. */
4226 && !is_on_allowed_list(government_rule_name(pnation
->init_government
),
4227 allowed_govs
, agcount
)) {
4228 ruleset_error(LOG_ERROR
,
4229 "Nation %s: init_government \"%s\" not allowed.",
4230 nation_rule_name(pnation
),
4231 government_rule_name(pnation
->init_government
));
4236 /* Read default city names. */
4237 if (!load_city_name_list(file
, pnation
, sec_name
, "cities",
4238 allowed_terrains
, atcount
)) {
4243 pnation
->legend
= fc_strdup(secfile_lookup_str(file
, "%s.legend",
4245 if (check_strlen(pnation
->legend
, MAX_LEN_MSG
, NULL
)) {
4246 ruleset_error(LOG_ERROR
,
4247 "Nation %s: legend \"%s\" is too long.",
4248 nation_rule_name(pnation
),
4254 pnation
->player
= NULL
;
4255 } nations_iterate_end
;
4256 section_list_destroy(sec
);
4260 /* Clean up on aborted load */
4263 section_list_destroy(sec
);
4267 free(allowed_terrains
);
4268 free(allowed_cstyles
);
4271 secfile_check_unused(file
);
4275 /* Update cached number of playable nations in the current set */
4276 count_playable_nations();
4278 /* Sanity checks on all sets */
4279 nation_sets_iterate(pset
) {
4280 int num_playable
= 0, barb_land_count
= 0, barb_sea_count
= 0;
4281 nations_iterate(pnation
) {
4282 if (nation_is_in_set(pnation
, pset
)) {
4283 switch (nation_barbarian_type(pnation
)) {
4284 case NOT_A_BARBARIAN
:
4285 if (is_nation_playable(pnation
)) {
4289 case LAND_BARBARIAN
:
4296 fc_assert_ret_val(FALSE
, FALSE
);
4299 } nations_iterate_end
;
4300 if (num_playable
< 1) {
4301 ruleset_error(LOG_ERROR
,
4302 "Nation set \"%s\" has no playable nations. "
4303 "At least one required!", nation_set_rule_name(pset
));
4307 if (barb_land_count
== 0) {
4308 ruleset_error(LOG_ERROR
,
4309 "No land barbarian nation defined in set \"%s\". "
4310 "At least one required!", nation_set_rule_name(pset
));
4314 if (barb_sea_count
== 0) {
4315 ruleset_error(LOG_ERROR
,
4316 "No sea barbarian nation defined in set \"%s\". "
4317 "At least one required!", nation_set_rule_name(pset
));
4321 } nation_sets_iterate_end
;
4327 /**************************************************************************
4328 Load names of city styles so other rulesets can refer to city styles with
4330 **************************************************************************/
4331 static bool load_citystyle_names(struct section_file
*file
)
4333 struct section_list
*styles
;
4337 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
4340 styles
= secfile_sections_by_name_prefix(file
, CITYSTYLE_SECTION_PREFIX
);
4341 if (NULL
!= styles
) {
4342 city_styles_alloc(section_list_size(styles
));
4343 section_list_iterate(styles
, style
) {
4344 if (!ruleset_load_names(&city_styles
[i
].name
, NULL
, file
, section_name(style
))) {
4349 } section_list_iterate_end
;
4350 section_list_destroy(styles
);
4352 city_styles_alloc(0);
4358 /**************************************************************************
4359 Load cities.ruleset file
4360 **************************************************************************/
4361 static bool load_ruleset_cities(struct section_file
*file
)
4363 const char *replacement
;
4364 const char *filename
= secfile_name(file
);
4366 struct section_list
*sec
;
4369 if (check_ruleset_capabilities(file
, RULESET_CAPABILITIES
, filename
) == NULL
) {
4373 /* Specialist options */
4374 sec
= secfile_sections_by_name_prefix(file
, SPECIALIST_SECTION_PREFIX
);
4375 if (section_list_size(sec
) >= SP_MAX
) {
4376 ruleset_error(LOG_ERROR
, "\"%s\": Too many specialists (%d, max %d).",
4377 filename
, section_list_size(sec
), SP_MAX
);
4384 game
.control
.num_specialist_types
= section_list_size(sec
);
4386 section_list_iterate(sec
, psection
) {
4387 struct specialist
*s
= specialist_by_number(i
);
4388 struct requirement_vector
*reqs
;
4389 const char *sec_name
= section_name(psection
);
4391 if (!ruleset_load_names(&s
->name
, NULL
, file
, sec_name
)) {
4396 item
= secfile_lookup_str_default(file
, untranslated_name(&s
->name
),
4397 "%s.short_name", sec_name
);
4398 name_set(&s
->abbreviation
, NULL
, item
);
4400 sz_strlcpy(s
->graphic_alt
,
4401 secfile_lookup_str_default(file
, "-",
4402 "%s.graphic_alt", sec_name
));
4404 reqs
= lookup_req_list(file
, sec_name
, "reqs", specialist_rule_name(s
));
4409 requirement_vector_copy(&s
->reqs
, reqs
);
4411 s
->helptext
= lookup_strvec(file
, sec_name
, "helptext");
4413 if (requirement_vector_size(&s
->reqs
) == 0 && DEFAULT_SPECIALIST
== -1) {
4414 DEFAULT_SPECIALIST
= i
;
4417 } section_list_iterate_end
;
4420 if (ok
&& DEFAULT_SPECIALIST
== -1) {
4421 ruleset_error(LOG_ERROR
,
4422 "\"%s\": must give a min_size of 0 for at least one "
4423 "specialist type.", filename
);
4426 section_list_destroy(sec
);
4430 /* City Parameters */
4432 game
.info
.celebratesize
=
4433 secfile_lookup_int_default(file
, GAME_DEFAULT_CELEBRATESIZE
,
4434 "parameters.celebrate_size_limit");
4435 game
.info
.add_to_size_limit
=
4436 secfile_lookup_int_default(file
, 9, "parameters.add_to_size_limit");
4437 game
.info
.angrycitizen
=
4438 secfile_lookup_bool_default(file
, GAME_DEFAULT_ANGRYCITIZEN
,
4439 "parameters.angry_citizens");
4441 game
.info
.changable_tax
=
4442 secfile_lookup_bool_default(file
, TRUE
, "parameters.changable_tax");
4443 game
.info
.forced_science
=
4444 secfile_lookup_int_default(file
, 0, "parameters.forced_science");
4445 game
.info
.forced_luxury
=
4446 secfile_lookup_int_default(file
, 100, "parameters.forced_luxury");
4447 game
.info
.forced_gold
=
4448 secfile_lookup_int_default(file
, 0, "parameters.forced_gold");
4449 if (game
.info
.forced_science
+ game
.info
.forced_luxury
4450 + game
.info
.forced_gold
!= 100) {
4451 ruleset_error(LOG_ERROR
,
4452 "\"%s\": Forced taxes do not add up in ruleset!",
4461 /* civ1 & 2 didn't reveal tiles */
4462 game
.server
.vision_reveal_tiles
=
4463 secfile_lookup_bool_default(file
, FALSE
, "parameters.vision_reveal_tiles");
4465 game
.info
.pop_report_zeroes
=
4466 secfile_lookup_int_default(file
, 1, "parameters.pop_report_zeroes");
4468 /* Citizens configuration. */
4469 game
.info
.citizen_nationality
=
4470 secfile_lookup_bool_default(file
, FALSE
,
4471 "citizen.nationality");
4472 game
.info
.citizen_convert_speed
=
4473 secfile_lookup_int_default(file
, 50, "citizen.convert_speed");
4474 game
.info
.citizen_partisans_pct
=
4475 secfile_lookup_int_default(file
, 0, "citizen.partisans_pct");
4477 /* City Styles ... */
4479 sec
= secfile_sections_by_name_prefix(file
, CITYSTYLE_SECTION_PREFIX
);
4482 for (i
= 0; i
< game
.control
.styles_count
; i
++) {
4483 struct requirement_vector
*reqs
;
4484 const char *sec_name
= section_name(section_list_get(sec
, i
));
4486 sz_strlcpy(city_styles
[i
].graphic
,
4487 secfile_lookup_str(file
, "%s.graphic", sec_name
));
4488 sz_strlcpy(city_styles
[i
].graphic_alt
,
4489 secfile_lookup_str(file
, "%s.graphic_alt", sec_name
));
4490 sz_strlcpy(city_styles
[i
].oceanic_graphic
,
4491 secfile_lookup_str_default(file
, "",
4492 "%s.oceanic_graphic", sec_name
));
4493 sz_strlcpy(city_styles
[i
].oceanic_graphic_alt
,
4494 secfile_lookup_str_default(file
, "",
4495 "%s.oceanic_graphic_alt",
4497 sz_strlcpy(city_styles
[i
].citizens_graphic
,
4498 secfile_lookup_str_default(file
, "-",
4499 "%s.citizens_graphic", sec_name
));
4500 sz_strlcpy(city_styles
[i
].citizens_graphic_alt
,
4501 secfile_lookup_str_default(file
, "generic",
4502 "%s.citizens_graphic_alt", sec_name
));
4504 reqs
= lookup_req_list(file
, sec_name
, "reqs", city_style_rule_name(i
));
4509 requirement_vector_copy(&city_styles
[i
].reqs
, reqs
);
4511 replacement
= secfile_lookup_str(file
, "%s.replaced_by", sec_name
);
4512 if (0 == strcmp(replacement
, "-")) {
4513 city_styles
[i
].replaced_by
= -1;
4515 city_styles
[i
].replaced_by
= city_style_by_rule_name(replacement
);
4516 if (city_styles
[i
].replaced_by
< 0) {
4517 log_error("\"%s\": style \"%s\" replacement \"%s\" not found",
4518 filename
, city_style_rule_name(i
), replacement
);
4524 section_list_destroy(sec
);
4527 secfile_check_unused(file
);
4533 /**************************************************************************
4534 Load effects.ruleset file
4535 **************************************************************************/
4536 static bool load_ruleset_effects(struct section_file
*file
)
4538 struct section_list
*sec
;
4540 const char *filename
;
4543 filename
= secfile_name(file
);
4544 if (check_ruleset_capabilities(file
, RULESET_CAPABILITIES
, filename
) == NULL
) {
4547 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
4549 /* Parse effects and add them to the effects ruleset cache. */
4550 sec
= secfile_sections_by_name_prefix(file
, EFFECT_SECTION_PREFIX
);
4551 section_list_iterate(sec
, psection
) {
4552 enum effect_type eff
;
4554 struct effect
*peffect
;
4555 const char *sec_name
= section_name(psection
);
4556 struct requirement_vector
*reqs
;
4558 type
= secfile_lookup_str(file
, "%s.type", sec_name
);
4560 /* Backward compatibility. Field used to be named "name" */
4561 type
= secfile_lookup_str(file
, "%s.name", sec_name
);
4564 ruleset_error(LOG_ERROR
, "\"%s\" [%s] missing effect name.", filename
, sec_name
);
4569 eff
= effect_type_by_name(type
, fc_strcasecmp
);
4570 if (!effect_type_is_valid(eff
)) {
4571 ruleset_error(LOG_ERROR
, "\"%s\" [%s] lists unknown effect type \"%s\".",
4572 filename
, sec_name
, type
);
4577 value
= secfile_lookup_int_default(file
, 1, "%s.value", sec_name
);
4579 peffect
= effect_new(eff
, value
);
4581 reqs
= lookup_req_list(file
, sec_name
, "reqs", type
);
4587 requirement_vector_iterate(reqs
, req
) {
4588 struct requirement
*preq
= fc_malloc(sizeof(*preq
));
4591 effect_req_append(peffect
, FALSE
, preq
);
4592 } requirement_vector_iterate_end
;
4594 reqs
= lookup_req_list(file
, sec_name
, "nreqs", type
);
4599 requirement_vector_iterate(reqs
, req
) {
4600 struct requirement
*preq
= fc_malloc(sizeof(*preq
));
4603 effect_req_append(peffect
, TRUE
, preq
);
4604 } requirement_vector_iterate_end
;
4605 } section_list_iterate_end
;
4606 section_list_destroy(sec
);
4609 secfile_check_unused(file
);
4615 /**************************************************************************
4616 Print an error message if the value is out of range.
4617 **************************************************************************/
4618 static int secfile_lookup_int_default_min_max(struct section_file
*file
,
4619 int def
, int min
, int max
,
4620 const char *path
, ...)
4621 fc__attribute((__format__ (__printf__
, 5, 6)));
4622 static int secfile_lookup_int_default_min_max(struct section_file
*file
,
4623 int def
, int min
, int max
,
4624 const char *path
, ...)
4630 va_start(args
, path
);
4631 fc_vsnprintf(fullpath
, sizeof(fullpath
), path
, args
);
4634 if (!secfile_lookup_int(file
, &ival
, "%s", fullpath
)) {
4639 ruleset_error(LOG_ERROR
,"\"%s\" should be in the interval [%d, %d] "
4640 "but is %d; using the minimal value.",
4641 fullpath
, min
, max
, ival
);
4646 ruleset_error(LOG_ERROR
,"\"%s\" should be in the interval [%d, %d] "
4647 "but is %d; using the maximal value.",
4648 fullpath
, min
, max
, ival
);
4655 /**************************************************************************
4657 **************************************************************************/
4658 static bool load_ruleset_game(const char *rsdir
, bool act
)
4660 struct section_file
*file
;
4661 const char *sval
, **svec
;
4662 const char *filename
;
4668 struct section_list
*sec
;
4673 file
= openload_ruleset_file("game", rsdir
);
4677 filename
= secfile_name(file
);
4679 /* section: datafile */
4680 if (check_ruleset_capabilities(file
, RULESET_CAPABILITIES
, filename
) == NULL
) {
4681 secfile_destroy(file
);
4684 (void) secfile_entry_by_path(file
, "datafile.description"); /* unused */
4686 /* section: tileset */
4687 text
= secfile_lookup_str_default(file
, "", "tileset.prefered");
4688 text
= secfile_lookup_str_default(file
, text
, "tileset.preferred");
4689 if (text
[0] != '\0') {
4690 /* There was tileset suggestion */
4691 sz_strlcpy(game
.control
.prefered_tileset
, text
);
4693 /* No tileset suggestions */
4694 game
.control
.prefered_tileset
[0] = '\0';
4697 /* section: soundset */
4698 text
= secfile_lookup_str_default(file
, "", "soundset.prefered");
4699 text
= secfile_lookup_str_default(file
, text
, "soundset.preferred");
4700 if (text
[0] != '\0') {
4701 /* There was soundset suggestion */
4702 sz_strlcpy(game
.control
.prefered_soundset
, text
);
4704 /* No soundset suggestions */
4705 game
.control
.prefered_soundset
[0] = '\0';
4708 /* section: about */
4709 text
= secfile_lookup_str(file
, "about.name");
4710 /* Ruleset/modpack name found */
4711 sz_strlcpy(game
.control
.name
, text
);
4713 text
= secfile_lookup_str_default(file
, "", "about.description");
4714 if (text
[0] != '\0') {
4715 /* Ruleset/modpack description found */
4716 sz_strlcpy(game
.control
.description
, text
);
4718 /* No description */
4719 game
.control
.description
[0] = '\0';
4722 /* section: options */
4723 if (!lookup_tech_list(file
, "options", "global_init_techs",
4724 game
.rgame
.global_init_techs
, filename
)) {
4729 if (!lookup_building_list(file
, "options", "global_init_buildings",
4730 game
.rgame
.global_init_buildings
, filename
)) {
4739 game
.control
.popup_tech_help
= secfile_lookup_bool_default(file
, FALSE
,
4740 "options.popup_tech_help");
4742 /* section: civstyle */
4743 game
.info
.base_pollution
4744 = secfile_lookup_int_default(file
, RS_DEFAULT_BASE_POLLUTION
,
4745 "civstyle.base_pollution");
4747 game
.info
.gameloss_style
= GAMELOSS_STYLE_CLASSICAL
;
4749 slist
= secfile_lookup_str_vec(file
, &nval
, "civstyle.gameloss_style");
4750 for (j
= 0; j
< nval
; j
++) {
4751 enum gameloss_style style
;
4754 if (strcmp(sval
, "") == 0) {
4757 style
= gameloss_style_by_name(sval
, fc_strcasecmp
);
4758 if (!gameloss_style_is_valid(style
)) {
4759 ruleset_error(LOG_ERROR
, "\"%s\": bad value \"%s\" for gameloss_style.",
4764 game
.info
.gameloss_style
|= style
;
4771 game
.info
.happy_cost
4772 = secfile_lookup_int_def_min_max(file
,
4773 RS_DEFAULT_HAPPY_COST
,
4776 "civstyle.happy_cost");
4778 = secfile_lookup_int_default_min_max(file
,
4779 RS_DEFAULT_FOOD_COST
,
4782 "civstyle.food_cost");
4783 game
.info
.civil_war_enabled
4784 = secfile_lookup_bool_default(file
, TRUE
, "civstyle.civil_war_enabled");
4786 game
.info
.paradrop_to_transport
4787 = secfile_lookup_bool_default(file
, FALSE
,
4788 "civstyle.paradrop_to_transport");
4790 /* TODO: move to global_unit_options */
4791 game
.info
.base_bribe_cost
4792 = secfile_lookup_int_default_min_max(file
,
4793 RS_DEFAULT_BASE_BRIBE_COST
,
4794 RS_MIN_BASE_BRIBE_COST
,
4795 RS_MAX_BASE_BRIBE_COST
,
4796 "civstyle.base_bribe_cost");
4797 /* TODO: move to global_unit_options */
4798 game
.server
.ransom_gold
4799 = secfile_lookup_int_default_min_max(file
,
4800 RS_DEFAULT_RANSOM_GOLD
,
4803 "civstyle.ransom_gold");
4804 /* TODO: move to global_unit_options */
4805 game
.info
.pillage_select
4806 = secfile_lookup_bool_default(file
, RS_DEFAULT_PILLAGE_SELECT
,
4807 "civstyle.pillage_select");
4808 /* TODO: move to global_unit_options */
4809 game
.server
.upgrade_veteran_loss
4810 = secfile_lookup_int_default_min_max(file
,
4811 RS_DEFAULT_UPGRADE_VETERAN_LOSS
,
4812 RS_MIN_UPGRADE_VETERAN_LOSS
,
4813 RS_MAX_UPGRADE_VETERAN_LOSS
,
4814 "civstyle.upgrade_veteran_loss");
4815 /* TODO: move to global_unit_options */
4816 game
.server
.autoupgrade_veteran_loss
4817 = secfile_lookup_int_default_min_max(file
,
4818 RS_DEFAULT_UPGRADE_VETERAN_LOSS
,
4819 RS_MIN_UPGRADE_VETERAN_LOSS
,
4820 RS_MAX_UPGRADE_VETERAN_LOSS
,
4821 "civstyle.autoupgrade_veteran_loss");
4823 /* TODO: move to new section research */
4824 game
.info
.base_tech_cost
4825 = secfile_lookup_int_default_min_max(file
,
4826 RS_DEFAULT_BASE_TECH_COST
,
4827 RS_MIN_BASE_TECH_COST
,
4828 RS_MAX_BASE_TECH_COST
,
4829 "civstyle.base_tech_cost");
4831 food_ini
= secfile_lookup_int_vec(file
, &gni_tmp
,
4832 "civstyle.granary_food_ini");
4833 game
.info
.granary_num_inis
= (int) gni_tmp
;
4835 if (game
.info
.granary_num_inis
> MAX_GRANARY_INIS
) {
4836 ruleset_error(LOG_ERROR
,
4837 "Too many granary_food_ini entries (%d, max %d)",
4838 game
.info
.granary_num_inis
, MAX_GRANARY_INIS
);
4840 } else if (game
.info
.granary_num_inis
== 0) {
4841 log_error("No values for granary_food_ini. Using default "
4842 "value %d.", RS_DEFAULT_GRANARY_FOOD_INI
);
4843 game
.info
.granary_num_inis
= 1;
4844 game
.info
.granary_food_ini
[0] = RS_DEFAULT_GRANARY_FOOD_INI
;
4848 /* check for <= 0 entries */
4849 for (i
= 0; i
< game
.info
.granary_num_inis
; i
++) {
4850 if (food_ini
[i
] <= 0) {
4852 food_ini
[i
] = RS_DEFAULT_GRANARY_FOOD_INI
;
4854 food_ini
[i
] = food_ini
[i
- 1];
4856 log_error("Bad value for granary_food_ini[%i]. Using %i.",
4859 game
.info
.granary_food_ini
[i
] = food_ini
[i
];
4866 game
.info
.granary_food_inc
4867 = secfile_lookup_int_default_min_max(file
,
4868 RS_DEFAULT_GRANARY_FOOD_INC
,
4869 RS_MIN_GRANARY_FOOD_INC
,
4870 RS_MAX_GRANARY_FOOD_INC
,
4871 "civstyle.granary_food_inc");
4873 output_type_iterate(o
) {
4874 game
.info
.min_city_center_output
[o
]
4875 = secfile_lookup_int_default_min_max(file
,
4876 RS_DEFAULT_CITY_CENTER_OUTPUT
,
4877 RS_MIN_CITY_CENTER_OUTPUT
,
4878 RS_MAX_CITY_CENTER_OUTPUT
,
4879 "civstyle.min_city_center_%s",
4880 get_output_identifier(o
));
4881 } output_type_iterate_end
;
4883 sval
= secfile_lookup_str(file
, "civstyle.nuke_contamination" );
4884 if (fc_strcasecmp(sval
, "Pollution") == 0) {
4885 game
.server
.nuke_contamination
= CONTAMINATION_POLLUTION
;
4886 } else if (fc_strcasecmp(sval
, "Fallout") == 0) {
4887 game
.server
.nuke_contamination
= CONTAMINATION_FALLOUT
;
4889 ruleset_error(LOG_ERROR
,
4890 "Bad value %s for nuke_contamination.", sval
);
4896 const char *tus_text
;
4898 game
.server
.init_vis_radius_sq
4899 = secfile_lookup_int_default_min_max(file
,
4900 RS_DEFAULT_VIS_RADIUS_SQ
,
4901 RS_MIN_VIS_RADIUS_SQ
,
4902 RS_MAX_VIS_RADIUS_SQ
,
4903 "civstyle.init_vis_radius_sq");
4905 game
.info
.init_city_radius_sq
4906 = secfile_lookup_int_default_min_max(file
,
4907 RS_DEFAULT_CITY_RADIUS_SQ
,
4908 RS_MIN_CITY_RADIUS_SQ
,
4909 RS_MAX_CITY_RADIUS_SQ
,
4910 "civstyle.init_city_radius_sq");
4912 game
.info
.gold_upkeep_style
4913 = secfile_lookup_int_default_min_max(file
,
4914 RS_DEFAULT_GOLD_UPKEEP_STYLE
,
4915 RS_MIN_GOLD_UPKEEP_STYLE
,
4916 RS_MAX_GOLD_UPKEEP_STYLE
,
4917 "civstyle.gold_upkeep_style");
4919 /* TODO: move to new section research */
4920 game
.info
.tech_cost_style
4921 = secfile_lookup_int_default_min_max(file
,
4922 RS_DEFAULT_TECH_COST_STYLE
,
4923 RS_MIN_TECH_COST_STYLE
,
4924 RS_MAX_TECH_COST_STYLE
,
4925 "civstyle.tech_cost_style");
4926 /* TODO: move to new section research */
4927 game
.info
.tech_leakage
4928 = secfile_lookup_int_default_min_max(file
,
4929 RS_DEFAULT_TECH_LEAKAGE
,
4930 RS_MIN_TECH_LEAKAGE
,
4931 RS_MAX_TECH_LEAKAGE
,
4932 "civstyle.tech_leakage");
4933 if (game
.info
.tech_cost_style
== 0 && game
.info
.tech_leakage
!= 0) {
4934 log_error("Only tech_leakage 0 supported with tech_cost_style 0.");
4935 log_error("Switching to tech_leakage 0.");
4936 game
.info
.tech_leakage
= 0;
4939 /* section: illness */
4940 game
.info
.illness_on
4941 = secfile_lookup_bool_default(file
, RS_DEFAULT_ILLNESS_ON
,
4942 "illness.illness_on");
4943 game
.info
.illness_base_factor
4944 = secfile_lookup_int_default_min_max(file
,
4945 RS_DEFAULT_ILLNESS_BASE_FACTOR
,
4946 RS_MIN_ILLNESS_BASE_FACTOR
,
4947 RS_MAX_ILLNESS_BASE_FACTOR
,
4948 "illness.illness_base_factor");
4949 game
.info
.illness_min_size
4950 = secfile_lookup_int_default_min_max(file
,
4951 RS_DEFAULT_ILLNESS_MIN_SIZE
,
4952 RS_MIN_ILLNESS_MIN_SIZE
,
4953 RS_MAX_ILLNESS_MIN_SIZE
,
4954 "illness.illness_min_size");
4955 game
.info
.illness_trade_infection
4956 = secfile_lookup_int_default_min_max(file
,
4957 RS_DEFAULT_ILLNESS_TRADE_INFECTION_PCT
,
4958 RS_MIN_ILLNESS_TRADE_INFECTION_PCT
,
4959 RS_MAX_ILLNESS_TRADE_INFECTION_PCT
,
4960 "illness.illness_trade_infection");
4961 game
.info
.illness_pollution_factor
4962 = secfile_lookup_int_default_min_max(file
,
4963 RS_DEFAULT_ILLNESS_POLLUTION_PCT
,
4964 RS_MIN_ILLNESS_POLLUTION_PCT
,
4965 RS_MAX_ILLNESS_POLLUTION_PCT
,
4966 "illness.illness_pollution_factor");
4968 /* section: incite_cost */
4969 game
.server
.base_incite_cost
4970 = secfile_lookup_int_default_min_max(file
,
4971 RS_DEFAULT_INCITE_BASE_COST
,
4972 RS_MIN_INCITE_BASE_COST
,
4973 RS_MAX_INCITE_BASE_COST
,
4974 "incite_cost.base_incite_cost");
4975 game
.server
.incite_improvement_factor
4976 = secfile_lookup_int_default_min_max(file
,
4977 RS_DEFAULT_INCITE_IMPROVEMENT_FCT
,
4978 RS_MIN_INCITE_IMPROVEMENT_FCT
,
4979 RS_MAX_INCITE_IMPROVEMENT_FCT
,
4980 "incite_cost.improvement_factor");
4981 game
.server
.incite_unit_factor
4982 = secfile_lookup_int_default_min_max(file
,
4983 RS_DEFAULT_INCITE_UNIT_FCT
,
4984 RS_MIN_INCITE_UNIT_FCT
,
4985 RS_MAX_INCITE_UNIT_FCT
,
4986 "incite_cost.unit_factor");
4987 game
.server
.incite_total_factor
4988 = secfile_lookup_int_default_min_max(file
,
4989 RS_DEFAULT_INCITE_TOTAL_FCT
,
4990 RS_MIN_INCITE_TOTAL_FCT
,
4991 RS_MAX_INCITE_TOTAL_FCT
,
4992 "incite_cost.total_factor");
4994 /* section: global_unit_options */
4995 game
.info
.slow_invasions
4996 = secfile_lookup_bool_default(file
, RS_DEFAULT_SLOW_INVASIONS
,
4997 "global_unit_options.slow_invasions");
4999 /* section: combat_rules */
5000 game
.info
.tired_attack
5001 = secfile_lookup_bool_default(file
, RS_DEFAULT_TIRED_ATTACK
,
5002 "combat_rules.tired_attack");
5004 /* section: borders */
5005 game
.info
.border_city_radius_sq
5006 = secfile_lookup_int_default_min_max(file
,
5007 RS_DEFAULT_BORDER_RADIUS_SQ_CITY
,
5008 RS_MIN_BORDER_RADIUS_SQ_CITY
,
5009 RS_MAX_BORDER_RADIUS_SQ_CITY
,
5010 "borders.radius_sq_city");
5011 game
.info
.border_size_effect
5012 = secfile_lookup_int_default_min_max(file
,
5013 RS_DEFAULT_BORDER_SIZE_EFFECT
,
5014 RS_MIN_BORDER_SIZE_EFFECT
,
5015 RS_MAX_BORDER_SIZE_EFFECT
,
5016 "borders.size_effect");
5018 /* section: research */
5019 tus_text
= secfile_lookup_str_default(file
, RS_DEFAULT_TECH_UPKEEP_STYLE
,
5020 "research.tech_upkeep_style");
5022 game
.info
.tech_upkeep_style
= tech_upkeep_style_by_name(tus_text
, fc_strcasecmp
);
5024 if (!tech_upkeep_style_is_valid(game
.info
.tech_upkeep_style
)) {
5025 ruleset_error(LOG_ERROR
, "Unknown tech upkeep style \"%s\"",
5032 game
.info
.tech_upkeep_divider
5033 = secfile_lookup_int_default_min_max(file
,
5034 RS_DEFAULT_TECH_UPKEEP_DIVIDER
,
5035 RS_MIN_TECH_UPKEEP_DIVIDER
,
5036 RS_MAX_TECH_UPKEEP_DIVIDER
,
5037 "research.tech_upkeep_divider");
5039 sval
= secfile_lookup_str_default(file
, NULL
, "research.free_tech_method");
5041 ruleset_error(LOG_ERROR
, "No free_tech_method given");
5044 game
.info
.free_tech_method
= free_tech_method_by_name(sval
, fc_strcasecmp
);
5045 if (!free_tech_method_is_valid(game
.info
.free_tech_method
)) {
5046 ruleset_error(LOG_ERROR
, "Bad value %s for free_tech_method.", sval
);
5053 /* section: calendar */
5054 game
.info
.calendar_skip_0
5055 = secfile_lookup_bool_default(file
, RS_DEFAULT_CALENDAR_SKIP_0
,
5056 "calendar.skip_year_0");
5057 game
.server
.start_year
5058 = secfile_lookup_int_default(file
, GAME_START_YEAR
,
5059 "calendar.start_year");
5060 sz_strlcpy(game
.info
.positive_year_label
,
5061 _(secfile_lookup_str_default(file
,
5062 RS_DEFAULT_POS_YEAR_LABEL
,
5063 "calendar.positive_label")));
5064 sz_strlcpy(game
.info
.negative_year_label
,
5065 _(secfile_lookup_str_default(file
,
5066 RS_DEFAULT_NEG_YEAR_LABEL
,
5067 "calendar.negative_label")));
5071 /* section playercolors */
5072 struct rgbcolor
*prgbcolor
= NULL
;
5075 /* Check if the player list is defined and empty. */
5076 if (playercolor_count() != 0) {
5084 read
= rgbcolor_load(file
, &prgbcolor
, "playercolors.colorlist%d", i
);
5086 playercolor_add(prgbcolor
);
5092 if (playercolor_count() == 0) {
5093 ruleset_error(LOG_ERROR
, "No player colors defined!");
5098 fc_assert(game
.plr_bg_color
== NULL
);
5099 if (!rgbcolor_load(file
, &game
.plr_bg_color
, "playercolors.background")) {
5100 ruleset_error(LOG_ERROR
, "No background player color defined! (%s)",
5109 /* section: teams */
5110 svec
= secfile_lookup_str_vec(file
, &teams
, "teams.names");
5111 if (team_slot_count() < teams
) {
5112 teams
= team_slot_count();
5114 for (i
= 0; i
< teams
; i
++) {
5115 team_slot_set_defined_name(team_slot_by_number(i
), svec
[i
]);
5119 sec
= secfile_sections_by_name_prefix(file
, DISASTER_SECTION_PREFIX
);
5120 nval
= (NULL
!= sec
? section_list_size(sec
) : 0);
5121 if (nval
> MAX_DISASTER_TYPES
) {
5122 int num
= nval
; /* No "size_t" to printf */
5124 ruleset_error(LOG_ERROR
, "\"%s\": Too many disaster types (%d, max %d)",
5125 filename
, num
, MAX_DISASTER_TYPES
);
5126 section_list_destroy(sec
);
5129 game
.control
.num_disaster_types
= nval
;
5134 disaster_type_iterate(pdis
) {
5135 int id
= disaster_index(pdis
);
5138 struct requirement_vector
*reqs
;
5139 const char *sec_name
= section_name(section_list_get(sec
, id
));
5141 if (!ruleset_load_names(&pdis
->name
, NULL
, file
, sec_name
)) {
5142 ruleset_error(LOG_ERROR
, "\"%s\": Cannot load disaster names",
5148 reqs
= lookup_req_list(file
, sec_name
, "reqs", disaster_rule_name(pdis
));
5153 requirement_vector_copy(&pdis
->reqs
, reqs
);
5155 pdis
->frequency
= secfile_lookup_int_default(file
, 10, "%s.frequency",
5158 svec
= secfile_lookup_str_vec(file
, &eff_count
, "%s.effects", sec_name
);
5160 BV_CLR_ALL(pdis
->effects
);
5161 for (j
= 0; j
< eff_count
; j
++) {
5162 const char *sval
= svec
[j
];
5163 enum disaster_effect_id effect
;
5165 effect
= disaster_effect_id_by_name(sval
, fc_strcasecmp
);
5167 if (!disaster_effect_id_is_valid(effect
)) {
5168 ruleset_error(LOG_ERROR
,
5169 "\"%s\" disaster \"%s\": unknown effect \"%s\".",
5171 disaster_rule_name(pdis
),
5176 BV_SET(pdis
->effects
, effect
);
5185 } disaster_type_iterate_end
;
5186 section_list_destroy(sec
);
5190 for (i
= 0; (name
= secfile_lookup_str_default(file
, NULL
,
5191 "trade.settings%d.type",
5193 enum trade_route_type type
= trade_route_type_by_name(name
);
5195 if (type
== TRT_LAST
) {
5196 ruleset_error(LOG_ERROR
,
5197 "\"%s\" unknown trade route type \"%s\".",
5201 struct trade_route_settings
*set
= trade_route_settings_by_type(type
);
5202 const char *cancelling
;
5204 set
->trade_pct
= secfile_lookup_int_default(file
, 100,
5205 "trade.settings%d.pct", i
);
5206 cancelling
= secfile_lookup_str_default(file
, "Active",
5207 "trade.settings%d.cancelling", i
);
5208 set
->cancelling
= traderoute_cancelling_type_by_name(cancelling
);
5209 if (set
->cancelling
== TRI_LAST
) {
5210 ruleset_error(LOG_ERROR
,
5211 "\"%s\" unknown traderoute cancelling type \"%s\".",
5212 filename
, cancelling
);
5219 settings_ruleset(file
, "settings", act
);
5222 secfile_check_unused(file
);
5224 secfile_destroy(file
);
5229 /**************************************************************************
5230 Send the units ruleset information (all individual unit classes) to the
5231 specified connections.
5232 **************************************************************************/
5233 static void send_ruleset_unit_classes(struct conn_list
*dest
)
5235 struct packet_ruleset_unit_class packet
;
5237 unit_class_iterate(c
) {
5238 packet
.id
= uclass_number(c
);
5239 sz_strlcpy(packet
.name
, untranslated_name(&c
->name
));
5240 sz_strlcpy(packet
.rule_name
, rule_name(&c
->name
));
5241 packet
.move_type
= c
->move_type
;
5242 packet
.min_speed
= c
->min_speed
;
5243 packet
.hp_loss_pct
= c
->hp_loss_pct
;
5244 packet
.hut_behavior
= c
->hut_behavior
;
5245 packet
.flags
= c
->flags
;
5247 lsend_packet_ruleset_unit_class(dest
, &packet
);
5248 } unit_class_iterate_end
;
5251 /**************************************************************************
5252 Send the units ruleset information (all individual units) to the
5253 specified connections.
5254 **************************************************************************/
5255 static void send_ruleset_units(struct conn_list
*dest
)
5257 struct packet_ruleset_unit packet
;
5258 struct packet_ruleset_unit_flag fpacket
;
5261 for (i
= 0; i
< MAX_NUM_USER_UNIT_FLAGS
; i
++) {
5262 const char *flagname
;
5263 const char *helptxt
;
5265 fpacket
.id
= i
+ UTYF_USER_FLAG_1
;
5267 flagname
= unit_type_flag_id_name(i
+ UTYF_USER_FLAG_1
);
5268 if (flagname
== NULL
) {
5269 fpacket
.name
[0] = '\0';
5271 sz_strlcpy(fpacket
.name
, flagname
);
5274 helptxt
= unit_type_flag_helptxt(i
+ UTYF_USER_FLAG_1
);
5275 if (helptxt
== NULL
) {
5276 fpacket
.helptxt
[0] = '\0';
5278 sz_strlcpy(fpacket
.helptxt
, helptxt
);
5281 lsend_packet_ruleset_unit_flag(dest
, &fpacket
);
5284 unit_type_iterate(u
) {
5285 packet
.id
= utype_number(u
);
5286 sz_strlcpy(packet
.name
, untranslated_name(&u
->name
));
5287 sz_strlcpy(packet
.rule_name
, rule_name(&u
->name
));
5288 sz_strlcpy(packet
.sound_move
, u
->sound_move
);
5289 sz_strlcpy(packet
.sound_move_alt
, u
->sound_move_alt
);
5290 sz_strlcpy(packet
.sound_fight
, u
->sound_fight
);
5291 sz_strlcpy(packet
.sound_fight_alt
, u
->sound_fight_alt
);
5292 sz_strlcpy(packet
.graphic_str
, u
->graphic_str
);
5293 sz_strlcpy(packet
.graphic_alt
, u
->graphic_alt
);
5294 packet
.unit_class_id
= uclass_number(utype_class(u
));
5295 packet
.build_cost
= u
->build_cost
;
5296 packet
.pop_cost
= u
->pop_cost
;
5297 packet
.attack_strength
= u
->attack_strength
;
5298 packet
.defense_strength
= u
->defense_strength
;
5299 packet
.move_rate
= u
->move_rate
;
5300 packet
.tech_requirement
= u
->require_advance
5301 ? advance_number(u
->require_advance
)
5303 packet
.impr_requirement
= u
->need_improvement
5304 ? improvement_number(u
->need_improvement
)
5305 : improvement_count();
5306 packet
.gov_requirement
= u
->need_government
5307 ? government_number(u
->need_government
)
5308 : government_count();
5309 packet
.vision_radius_sq
= u
->vision_radius_sq
;
5310 packet
.transport_capacity
= u
->transport_capacity
;
5312 packet
.firepower
= u
->firepower
;
5313 packet
.obsoleted_by
= u
->obsoleted_by
5314 ? utype_number(u
->obsoleted_by
)
5316 packet
.converted_to
= u
->converted_to
5317 ? utype_number(u
->converted_to
)
5319 packet
.convert_time
= u
->convert_time
;
5320 packet
.fuel
= u
->fuel
;
5321 packet
.flags
= u
->flags
;
5322 packet
.roles
= u
->roles
;
5323 packet
.happy_cost
= u
->happy_cost
;
5324 output_type_iterate(o
) {
5325 packet
.upkeep
[o
] = u
->upkeep
[o
];
5326 } output_type_iterate_end
;
5327 packet
.paratroopers_range
= u
->paratroopers_range
;
5328 packet
.paratroopers_mr_req
= u
->paratroopers_mr_req
;
5329 packet
.paratroopers_mr_sub
= u
->paratroopers_mr_sub
;
5330 packet
.bombard_rate
= u
->bombard_rate
;
5331 packet
.city_size
= u
->city_size
;
5332 packet
.cargo
= u
->cargo
;
5333 packet
.targets
= u
->targets
;
5334 packet
.embarks
= u
->embarks
;
5335 packet
.disembarks
= u
->disembarks
;
5337 if (u
->veteran
== NULL
) {
5338 /* Use the default veteran system. */
5339 packet
.veteran_levels
= 0;
5341 /* Per unit veteran system definition. */
5342 packet
.veteran_levels
= utype_veteran_levels(u
);
5344 for (i
= 0; i
< packet
.veteran_levels
; i
++) {
5345 const struct veteran_level
*vlevel
= utype_veteran_level(u
, i
);
5347 sz_strlcpy(packet
.veteran_name
[i
], untranslated_name(&vlevel
->name
));
5348 packet
.power_fact
[i
] = vlevel
->power_fact
;
5349 packet
.move_bonus
[i
] = vlevel
->move_bonus
;
5352 PACKET_STRVEC_COMPUTE(packet
.helptext
, u
->helptext
);
5354 lsend_packet_ruleset_unit(dest
, &packet
);
5356 combat_bonus_list_iterate(u
->bonuses
, pbonus
) {
5357 struct packet_ruleset_unit_bonus bonuspacket
;
5359 bonuspacket
.unit
= packet
.id
;
5360 bonuspacket
.flag
= pbonus
->flag
;
5361 bonuspacket
.type
= pbonus
->type
;
5362 bonuspacket
.value
= pbonus
->value
;
5364 lsend_packet_ruleset_unit_bonus(dest
, &bonuspacket
);
5365 } combat_bonus_list_iterate_end
;
5366 } unit_type_iterate_end
;
5369 /**************************************************************************
5370 Send the specialists ruleset information (all individual specialist
5371 types) to the specified connections.
5372 **************************************************************************/
5373 static void send_ruleset_specialists(struct conn_list
*dest
)
5375 struct packet_ruleset_specialist packet
;
5377 specialist_type_iterate(spec_id
) {
5378 struct specialist
*s
= specialist_by_number(spec_id
);
5381 packet
.id
= spec_id
;
5382 sz_strlcpy(packet
.plural_name
, untranslated_name(&s
->name
));
5383 sz_strlcpy(packet
.rule_name
, rule_name(&s
->name
));
5384 sz_strlcpy(packet
.short_name
, untranslated_name(&s
->abbreviation
));
5385 sz_strlcpy(packet
.graphic_alt
, s
->graphic_alt
);
5387 requirement_vector_iterate(&s
->reqs
, preq
) {
5388 packet
.reqs
[j
++] = *preq
;
5389 } requirement_vector_iterate_end
;
5390 packet
.reqs_count
= j
;
5392 PACKET_STRVEC_COMPUTE(packet
.helptext
, s
->helptext
);
5394 lsend_packet_ruleset_specialist(dest
, &packet
);
5395 } specialist_type_iterate_end
;
5398 /**************************************************************************
5399 Send the techs ruleset information (all individual advances) to the
5400 specified connections.
5401 **************************************************************************/
5402 static void send_ruleset_techs(struct conn_list
*dest
)
5404 struct packet_ruleset_tech packet
;
5405 struct packet_ruleset_tech_flag fpacket
;
5408 for (i
= 0; i
< MAX_NUM_USER_TECH_FLAGS
; i
++) {
5409 const char *flagname
;
5410 const char *helptxt
;
5412 fpacket
.id
= i
+ TECH_USER_1
;
5414 flagname
= tech_flag_id_name_cb(i
+ TECH_USER_1
);
5415 if (flagname
== NULL
) {
5416 fpacket
.name
[0] = '\0';
5418 sz_strlcpy(fpacket
.name
, flagname
);
5421 helptxt
= tech_flag_helptxt(i
+ TECH_USER_1
);
5422 if (helptxt
== NULL
) {
5423 fpacket
.helptxt
[0] = '\0';
5425 sz_strlcpy(fpacket
.helptxt
, helptxt
);
5428 lsend_packet_ruleset_tech_flag(dest
, &fpacket
);
5431 advance_iterate(A_NONE
, a
) {
5432 packet
.id
= advance_number(a
);
5433 sz_strlcpy(packet
.name
, untranslated_name(&a
->name
));
5434 sz_strlcpy(packet
.rule_name
, rule_name(&a
->name
));
5435 sz_strlcpy(packet
.graphic_str
, a
->graphic_str
);
5436 sz_strlcpy(packet
.graphic_alt
, a
->graphic_alt
);
5438 packet
.req
[AR_ONE
] = a
->require
[AR_ONE
]
5439 ? advance_number(a
->require
[AR_ONE
])
5441 packet
.req
[AR_TWO
] = a
->require
[AR_TWO
]
5442 ? advance_number(a
->require
[AR_TWO
])
5444 packet
.root_req
= a
->require
[AR_ROOT
]
5445 ? advance_number(a
->require
[AR_ROOT
])
5448 packet
.flags
= a
->flags
;
5449 packet
.preset_cost
= a
->preset_cost
;
5450 packet
.num_reqs
= a
->num_reqs
;
5451 PACKET_STRVEC_COMPUTE(packet
.helptext
, a
->helptext
);
5453 lsend_packet_ruleset_tech(dest
, &packet
);
5454 } advance_iterate_end
;
5457 /**************************************************************************
5458 Send the buildings ruleset information (all individual improvements and
5459 wonders) to the specified connections.
5460 **************************************************************************/
5461 static void send_ruleset_buildings(struct conn_list
*dest
)
5463 improvement_iterate(b
) {
5464 struct packet_ruleset_building packet
;
5467 packet
.id
= improvement_number(b
);
5468 packet
.genus
= b
->genus
;
5469 sz_strlcpy(packet
.name
, untranslated_name(&b
->name
));
5470 sz_strlcpy(packet
.rule_name
, rule_name(&b
->name
));
5471 sz_strlcpy(packet
.graphic_str
, b
->graphic_str
);
5472 sz_strlcpy(packet
.graphic_alt
, b
->graphic_alt
);
5474 requirement_vector_iterate(&b
->reqs
, preq
) {
5475 packet
.reqs
[j
++] = *preq
;
5476 } requirement_vector_iterate_end
;
5477 packet
.reqs_count
= j
;
5478 packet
.obsolete_by
= b
->obsolete_by
5479 ? advance_number(b
->obsolete_by
)
5481 packet
.replaced_by
= b
->replaced_by
5482 ? improvement_number(b
->replaced_by
)
5483 : improvement_count();
5484 packet
.build_cost
= b
->build_cost
;
5485 packet
.upkeep
= b
->upkeep
;
5486 packet
.sabotage
= b
->sabotage
;
5487 packet
.flags
= b
->flags
;
5488 sz_strlcpy(packet
.soundtag
, b
->soundtag
);
5489 sz_strlcpy(packet
.soundtag_alt
, b
->soundtag_alt
);
5490 PACKET_STRVEC_COMPUTE(packet
.helptext
, b
->helptext
);
5492 lsend_packet_ruleset_building(dest
, &packet
);
5493 } improvement_iterate_end
;
5496 /**************************************************************************
5497 Send the terrain ruleset information (terrain_control, and the individual
5498 terrain types) to the specified connections.
5499 **************************************************************************/
5500 static void send_ruleset_terrain(struct conn_list
*dest
)
5502 struct packet_ruleset_terrain packet
;
5503 struct packet_ruleset_terrain_flag fpacket
;
5506 lsend_packet_ruleset_terrain_control(dest
, &terrain_control
);
5508 for (i
= 0; i
< MAX_NUM_USER_TER_FLAGS
; i
++) {
5509 const char *flagname
;
5510 const char *helptxt
;
5512 fpacket
.id
= i
+ TER_USER_1
;
5514 flagname
= terrain_flag_id_name_cb(i
+ TER_USER_1
);
5515 if (flagname
== NULL
) {
5516 fpacket
.name
[0] = '\0';
5518 sz_strlcpy(fpacket
.name
, flagname
);
5521 helptxt
= terrain_flag_helptxt(i
+ TER_USER_1
);
5522 if (helptxt
== NULL
) {
5523 fpacket
.helptxt
[0] = '\0';
5525 sz_strlcpy(fpacket
.helptxt
, helptxt
);
5528 lsend_packet_ruleset_terrain_flag(dest
, &fpacket
);
5531 terrain_type_iterate(pterrain
) {
5532 struct resource
**r
;
5534 packet
.id
= terrain_number(pterrain
);
5535 packet
.tclass
= pterrain
->tclass
;
5536 packet
.native_to
= pterrain
->native_to
;
5538 sz_strlcpy(packet
.name
, untranslated_name(&pterrain
->name
));
5539 sz_strlcpy(packet
.rule_name
, rule_name(&pterrain
->name
));
5540 sz_strlcpy(packet
.graphic_str
, pterrain
->graphic_str
);
5541 sz_strlcpy(packet
.graphic_alt
, pterrain
->graphic_alt
);
5543 packet
.movement_cost
= pterrain
->movement_cost
;
5544 packet
.defense_bonus
= pterrain
->defense_bonus
;
5546 output_type_iterate(o
) {
5547 packet
.output
[o
] = pterrain
->output
[o
];
5548 } output_type_iterate_end
;
5550 packet
.num_resources
= 0;
5551 for (r
= pterrain
->resources
; *r
; r
++) {
5552 packet
.resources
[packet
.num_resources
++] = resource_number(*r
);
5555 output_type_iterate(o
) {
5556 packet
.road_output_incr_pct
[o
] = pterrain
->road_output_incr_pct
[o
];
5557 } output_type_iterate_end
;
5559 packet
.base_time
= pterrain
->base_time
;
5560 packet
.road_time
= pterrain
->road_time
;
5562 packet
.irrigation_result
= (pterrain
->irrigation_result
5563 ? terrain_number(pterrain
->irrigation_result
)
5565 packet
.irrigation_food_incr
= pterrain
->irrigation_food_incr
;
5566 packet
.irrigation_time
= pterrain
->irrigation_time
;
5568 packet
.mining_result
= (pterrain
->mining_result
5569 ? terrain_number(pterrain
->mining_result
)
5571 packet
.mining_shield_incr
= pterrain
->mining_shield_incr
;
5572 packet
.mining_time
= pterrain
->mining_time
;
5574 packet
.transform_result
= (pterrain
->transform_result
5575 ? terrain_number(pterrain
->transform_result
)
5577 packet
.transform_time
= pterrain
->transform_time
;
5578 packet
.clean_pollution_time
= pterrain
->clean_pollution_time
;
5579 packet
.clean_fallout_time
= pterrain
->clean_fallout_time
;
5581 packet
.flags
= pterrain
->flags
;
5583 packet
.color_red
= pterrain
->rgb
->r
;
5584 packet
.color_green
= pterrain
->rgb
->g
;
5585 packet
.color_blue
= pterrain
->rgb
->b
;
5587 PACKET_STRVEC_COMPUTE(packet
.helptext
, pterrain
->helptext
);
5589 lsend_packet_ruleset_terrain(dest
, &packet
);
5590 } terrain_type_iterate_end
;
5593 /****************************************************************************
5594 Send the resource ruleset information to the specified connections.
5595 ****************************************************************************/
5596 static void send_ruleset_resources(struct conn_list
*dest
)
5598 struct packet_ruleset_resource packet
;
5600 resource_type_iterate (presource
) {
5601 packet
.id
= resource_number(presource
);
5603 sz_strlcpy(packet
.name
, untranslated_name(&presource
->name
));
5604 sz_strlcpy(packet
.rule_name
, rule_name(&presource
->name
));
5605 sz_strlcpy(packet
.graphic_str
, presource
->graphic_str
);
5606 sz_strlcpy(packet
.graphic_alt
, presource
->graphic_alt
);
5608 output_type_iterate(o
) {
5609 packet
.output
[o
] = presource
->output
[o
];
5610 } output_type_iterate_end
;
5612 lsend_packet_ruleset_resource(dest
, &packet
);
5613 } resource_type_iterate_end
;
5616 /**************************************************************************
5617 Send the base ruleset information (all individual base types) to the
5618 specified connections.
5619 **************************************************************************/
5620 static void send_ruleset_bases(struct conn_list
*dest
)
5622 struct packet_ruleset_base packet
;
5624 base_type_iterate(b
) {
5627 packet
.id
= base_number(b
);
5628 sz_strlcpy(packet
.name
, untranslated_name(&b
->name
));
5629 sz_strlcpy(packet
.rule_name
, rule_name(&b
->name
));
5630 sz_strlcpy(packet
.graphic_str
, b
->graphic_str
);
5631 sz_strlcpy(packet
.graphic_alt
, b
->graphic_alt
);
5632 sz_strlcpy(packet
.activity_gfx
, b
->activity_gfx
);
5633 sz_strlcpy(packet
.act_gfx_alt
, b
->act_gfx_alt
);
5634 packet
.buildable
= b
->buildable
;
5635 packet
.pillageable
= b
->pillageable
;
5638 requirement_vector_iterate(&b
->reqs
, preq
) {
5639 packet
.reqs
[j
++] = *preq
;
5640 } requirement_vector_iterate_end
;
5641 packet
.reqs_count
= j
;
5642 packet
.native_to
= b
->native_to
;
5644 packet
.gui_type
= b
->gui_type
;
5645 packet
.build_time
= b
->build_time
;
5646 packet
.defense_bonus
= b
->defense_bonus
;
5647 packet
.border_sq
= b
->border_sq
;
5648 packet
.vision_main_sq
= b
->vision_main_sq
;
5649 packet
.vision_invis_sq
= b
->vision_invis_sq
;
5651 packet
.flags
= b
->flags
;
5652 packet
.conflicts
= b
->conflicts
;
5654 PACKET_STRVEC_COMPUTE(packet
.helptext
, b
->helptext
);
5656 lsend_packet_ruleset_base(dest
, &packet
);
5657 } base_type_iterate_end
;
5660 /**************************************************************************
5661 Send the road ruleset information (all individual road types) to the
5662 specified connections.
5663 **************************************************************************/
5664 static void send_ruleset_roads(struct conn_list
*dest
)
5666 struct packet_ruleset_road packet
;
5668 road_type_iterate(r
) {
5671 packet
.id
= road_number(r
);
5673 sz_strlcpy(packet
.name
, untranslated_name(&r
->name
));
5674 sz_strlcpy(packet
.rule_name
, rule_name(&r
->name
));
5676 sz_strlcpy(packet
.graphic_str
, r
->graphic_str
);
5677 sz_strlcpy(packet
.graphic_alt
, r
->graphic_alt
);
5678 sz_strlcpy(packet
.activity_gfx
, r
->activity_gfx
);
5679 sz_strlcpy(packet
.act_gfx_alt
, r
->act_gfx_alt
);
5681 packet
.move_cost
= r
->move_cost
;
5682 packet
.move_mode
= r
->move_mode
;
5683 packet
.build_time
= r
->build_time
;
5684 packet
.defense_bonus
= r
->defense_bonus
;
5685 packet
.buildable
= r
->buildable
;
5686 packet
.pillageable
= r
->pillageable
;
5688 output_type_iterate(o
) {
5689 packet
.tile_incr_const
[o
] = r
->tile_incr_const
[o
];
5690 packet
.tile_incr
[o
] = r
->tile_incr
[o
];
5691 packet
.tile_bonus
[o
] = r
->tile_bonus
[o
];
5692 } output_type_iterate_end
;
5695 requirement_vector_iterate(&r
->reqs
, preq
) {
5696 packet
.reqs
[j
++] = *preq
;
5697 } requirement_vector_iterate_end
;
5698 packet
.reqs_count
= j
;
5700 packet
.compat
= r
->compat
;
5702 packet
.native_to
= r
->native_to
;
5703 packet
.hidden_by
= r
->hidden_by
;
5704 packet
.flags
= r
->flags
;
5706 PACKET_STRVEC_COMPUTE(packet
.helptext
, r
->helptext
);
5708 lsend_packet_ruleset_road(dest
, &packet
);
5709 } road_type_iterate_end
;
5712 /**************************************************************************
5713 Send the disaster ruleset information (all individual disaster types) to the
5714 specified connections.
5715 **************************************************************************/
5716 static void send_ruleset_disasters(struct conn_list
*dest
)
5718 struct packet_ruleset_disaster packet
;
5720 disaster_type_iterate(d
) {
5722 packet
.id
= disaster_number(d
);
5724 sz_strlcpy(packet
.name
, untranslated_name(&d
->name
));
5725 sz_strlcpy(packet
.rule_name
, rule_name(&d
->name
));
5728 requirement_vector_iterate(&d
->reqs
, preq
) {
5729 packet
.reqs
[j
++] = *preq
;
5730 } requirement_vector_iterate_end
;
5731 packet
.reqs_count
= j
;
5733 packet
.frequency
= d
->frequency
;
5735 packet
.effects
= d
->effects
;
5737 lsend_packet_ruleset_disaster(dest
, &packet
);
5738 } disaster_type_iterate_end
;
5741 /**************************************************************************
5742 Send the disaster ruleset information (all individual disaster types) to the
5743 specified connections.
5744 **************************************************************************/
5745 static void send_ruleset_trade_routes(struct conn_list
*dest
)
5747 struct packet_ruleset_trade packet
;
5748 enum trade_route_type type
;
5750 for (type
= TRT_NATIONAL
; type
< TRT_LAST
; type
++) {
5751 struct trade_route_settings
*set
= trade_route_settings_by_type(type
);
5754 packet
.trade_pct
= set
->trade_pct
;
5755 packet
.cancelling
= set
->cancelling
;
5757 lsend_packet_ruleset_trade(dest
, &packet
);
5761 /**************************************************************************
5762 Send the government ruleset information to the specified connections.
5763 One packet per government type, and for each type one per ruler title.
5764 **************************************************************************/
5765 static void send_ruleset_governments(struct conn_list
*dest
)
5767 struct packet_ruleset_government gov
;
5768 struct packet_ruleset_government_ruler_title title
;
5771 governments_iterate(g
) {
5772 /* send one packet_government */
5773 gov
.id
= government_number(g
);
5776 requirement_vector_iterate(&g
->reqs
, preq
) {
5777 gov
.reqs
[j
++] = *preq
;
5778 } requirement_vector_iterate_end
;
5781 sz_strlcpy(gov
.name
, untranslated_name(&g
->name
));
5782 sz_strlcpy(gov
.rule_name
, rule_name(&g
->name
));
5783 sz_strlcpy(gov
.graphic_str
, g
->graphic_str
);
5784 sz_strlcpy(gov
.graphic_alt
, g
->graphic_alt
);
5785 PACKET_STRVEC_COMPUTE(gov
.helptext
, g
->helptext
);
5787 lsend_packet_ruleset_government(dest
, &gov
);
5789 /* Send one packet_government_ruler_title per ruler title. */
5790 ruler_titles_iterate(government_ruler_titles(g
), pruler_title
) {
5791 const struct nation_type
*pnation
= ruler_title_nation(pruler_title
);
5793 title
.gov
= government_number(g
);
5794 title
.nation
= pnation
? nation_number(pnation
) : nation_count();
5795 sz_strlcpy(title
.male_title
,
5796 ruler_title_male_untranslated_name(pruler_title
));
5797 sz_strlcpy(title
.female_title
,
5798 ruler_title_female_untranslated_name(pruler_title
));
5799 lsend_packet_ruleset_government_ruler_title(dest
, &title
);
5800 } ruler_titles_iterate_end
;
5801 } governments_iterate_end
;
5804 /**************************************************************************
5805 Send the nations ruleset information (info on each nation) to the
5806 specified connections.
5807 **************************************************************************/
5808 static void send_ruleset_nations(struct conn_list
*dest
)
5810 struct packet_ruleset_nation_sets sets_packet
;
5811 struct packet_ruleset_nation_groups groups_packet
;
5812 struct packet_ruleset_nation packet
;
5815 sets_packet
.nsets
= nation_set_count();
5817 nation_sets_iterate(pset
) {
5818 sz_strlcpy(sets_packet
.names
[i
], nation_set_untranslated_name(pset
));
5819 sz_strlcpy(sets_packet
.rule_names
[i
], nation_set_rule_name(pset
));
5820 sz_strlcpy(sets_packet
.descriptions
[i
], nation_set_description(pset
));
5822 } nation_sets_iterate_end
;
5823 lsend_packet_ruleset_nation_sets(dest
, &sets_packet
);
5825 groups_packet
.ngroups
= nation_group_count();
5827 nation_groups_iterate(pgroup
) {
5828 sz_strlcpy(groups_packet
.groups
[i
++],
5829 nation_group_untranslated_name(pgroup
));
5830 } nation_groups_iterate_end
;
5831 lsend_packet_ruleset_nation_groups(dest
, &groups_packet
);
5833 nations_iterate(n
) {
5834 packet
.id
= nation_number(n
);
5835 if (n
->translation_domain
== NULL
) {
5836 packet
.translation_domain
[0] = '\0';
5838 sz_strlcpy(packet
.translation_domain
, n
->translation_domain
);
5840 sz_strlcpy(packet
.adjective
, untranslated_name(&n
->adjective
));
5841 sz_strlcpy(packet
.rule_name
, rule_name(&n
->adjective
));
5842 sz_strlcpy(packet
.noun_plural
, untranslated_name(&n
->noun_plural
));
5843 sz_strlcpy(packet
.graphic_str
, n
->flag_graphic_str
);
5844 sz_strlcpy(packet
.graphic_alt
, n
->flag_graphic_alt
);
5847 nation_leader_list_iterate(nation_leaders(n
), pleader
) {
5848 sz_strlcpy(packet
.leader_name
[i
], nation_leader_name(pleader
));
5849 packet
.leader_is_male
[i
] = nation_leader_is_male(pleader
);
5851 } nation_leader_list_iterate_end
;
5852 packet
.leader_count
= i
;
5854 packet
.city_style
= n
->city_style
;
5855 packet
.is_playable
= n
->is_playable
;
5856 packet
.barbarian_type
= n
->barb_type
;
5858 sz_strlcpy(packet
.legend
, n
->legend
);
5861 nation_set_list_iterate(n
->sets
, pset
) {
5862 packet
.sets
[i
++] = nation_set_number(pset
);
5863 } nation_set_list_iterate_end
;
5867 nation_group_list_iterate(n
->groups
, pgroup
) {
5868 packet
.groups
[i
++] = nation_group_number(pgroup
);
5869 } nation_group_list_iterate_end
;
5872 packet
.init_government_id
= government_number(n
->init_government
);
5873 fc_assert(ARRAY_SIZE(packet
.init_techs
) == ARRAY_SIZE(n
->init_techs
));
5874 for (i
= 0; i
< MAX_NUM_TECH_LIST
; i
++) {
5875 packet
.init_techs
[i
] = n
->init_techs
[i
];
5877 fc_assert(ARRAY_SIZE(packet
.init_units
) == ARRAY_SIZE(n
->init_units
));
5878 for (i
= 0; i
< MAX_NUM_UNIT_LIST
; i
++) {
5879 const struct unit_type
*t
= n
->init_units
[i
];
5880 packet
.init_units
[i
] = t
? utype_number(t
) : U_LAST
;
5882 fc_assert(ARRAY_SIZE(packet
.init_buildings
)
5883 == ARRAY_SIZE(n
->init_buildings
));
5884 for (i
= 0; i
< MAX_NUM_BUILDING_LIST
; i
++) {
5885 /* Impr_type_id to int */
5886 packet
.init_buildings
[i
] = n
->init_buildings
[i
];
5889 lsend_packet_ruleset_nation(dest
, &packet
);
5890 } nations_iterate_end
;
5892 /* Send initial values of is_pickable */
5893 send_nation_availability(dest
, FALSE
);
5896 /**************************************************************************
5897 Send the city-style ruleset information (each style) to the specified
5899 **************************************************************************/
5900 static void send_ruleset_cities(struct conn_list
*dest
)
5902 struct packet_ruleset_city city_p
;
5905 for (k
= 0; k
< game
.control
.styles_count
; k
++) {
5906 city_p
.style_id
= k
;
5907 city_p
.replaced_by
= city_styles
[k
].replaced_by
;
5910 requirement_vector_iterate(&city_styles
[k
].reqs
, preq
) {
5911 city_p
.reqs
[j
++] = *preq
;
5912 } requirement_vector_iterate_end
;
5913 city_p
.reqs_count
= j
;
5915 sz_strlcpy(city_p
.name
, untranslated_name(&city_styles
[k
].name
));
5916 sz_strlcpy(city_p
.rule_name
, rule_name(&city_styles
[k
].name
));
5917 sz_strlcpy(city_p
.graphic
, city_styles
[k
].graphic
);
5918 sz_strlcpy(city_p
.graphic_alt
, city_styles
[k
].graphic_alt
);
5919 sz_strlcpy(city_p
.oceanic_graphic
, city_styles
[k
].oceanic_graphic
);
5920 sz_strlcpy(city_p
.oceanic_graphic_alt
, city_styles
[k
].oceanic_graphic_alt
);
5921 sz_strlcpy(city_p
.citizens_graphic
, city_styles
[k
].citizens_graphic
);
5922 sz_strlcpy(city_p
.citizens_graphic_alt
,
5923 city_styles
[k
].citizens_graphic_alt
);
5925 lsend_packet_ruleset_city(dest
, &city_p
);
5929 /**************************************************************************
5930 Send information in packet_ruleset_game (miscellaneous rules) to the
5931 specified connections.
5932 **************************************************************************/
5933 static void send_ruleset_game(struct conn_list
*dest
)
5935 struct packet_ruleset_game misc_p
;
5938 fc_assert_ret(game
.veteran
!= NULL
);
5940 /* Per unit veteran system definition. */
5941 misc_p
.veteran_levels
= game
.veteran
->levels
;
5943 for (i
= 0; i
< misc_p
.veteran_levels
; i
++) {
5944 const struct veteran_level
*vlevel
= game
.veteran
->definitions
+ i
;
5946 sz_strlcpy(misc_p
.veteran_name
[i
], untranslated_name(&vlevel
->name
));
5947 misc_p
.power_fact
[i
] = vlevel
->power_fact
;
5948 misc_p
.move_bonus
[i
] = vlevel
->move_bonus
;
5951 fc_assert(sizeof(misc_p
.global_init_techs
)
5952 == sizeof(game
.rgame
.global_init_techs
));
5953 fc_assert(ARRAY_SIZE(misc_p
.global_init_techs
)
5954 == ARRAY_SIZE(game
.rgame
.global_init_techs
));
5955 memcpy(misc_p
.global_init_techs
, game
.rgame
.global_init_techs
,
5956 sizeof(misc_p
.global_init_techs
));
5958 fc_assert(ARRAY_SIZE(misc_p
.global_init_buildings
)
5959 == ARRAY_SIZE(game
.rgame
.global_init_buildings
));
5960 for (i
= 0; i
< MAX_NUM_BUILDING_LIST
; i
++) {
5961 /* Impr_type_id to int */
5962 misc_p
.global_init_buildings
[i
] =
5963 game
.rgame
.global_init_buildings
[i
];
5966 misc_p
.default_specialist
= DEFAULT_SPECIALIST
;
5968 fc_assert_ret(game
.plr_bg_color
!= NULL
);
5970 misc_p
.background_red
= game
.plr_bg_color
->r
;
5971 misc_p
.background_green
= game
.plr_bg_color
->g
;
5972 misc_p
.background_blue
= game
.plr_bg_color
->b
;
5974 lsend_packet_ruleset_game(dest
, &misc_p
);
5977 /**************************************************************************
5978 Send all team names defined in the ruleset file(s) to the
5979 specified connections.
5980 **************************************************************************/
5981 static void send_ruleset_team_names(struct conn_list
*dest
)
5983 struct packet_team_name_info team_name_info_p
;
5985 team_slots_iterate(tslot
) {
5986 const char *name
= team_slot_defined_name(tslot
);
5989 /* End of defined names. */
5993 team_name_info_p
.team_id
= team_slot_index(tslot
);
5994 sz_strlcpy(team_name_info_p
.team_name
, name
);
5996 lsend_packet_team_name_info(dest
, &team_name_info_p
);
5997 } team_slots_iterate_end
;
6000 /**************************************************************************
6001 Make it clear to everyone that requested ruleset has not been loaded.
6002 **************************************************************************/
6003 static void notify_ruleset_fallback(const char *msg
)
6005 notify_conn(NULL
, NULL
, E_LOG_FATAL
, ftc_warning
, "%s", msg
);
6008 /**************************************************************************
6010 **************************************************************************/
6011 bool load_rulesets(const char *restore
, bool act
)
6013 if (load_rulesetdir(game
.server
.rulesetdir
, act
)) {
6017 /* Fallback to previous one. */
6018 if (restore
!= NULL
) {
6019 if (load_rulesetdir(restore
, act
)) {
6020 sz_strlcpy(game
.server
.rulesetdir
, restore
);
6022 notify_ruleset_fallback(_("Ruleset couldn't be loaded. Keeping previous one."));
6024 /* We're in sane state as restoring previous ruleset succeeded,
6025 * but return failure to indicate that this is not what caller
6031 /* Fallback to default one, but not if that's what we tried already */
6032 if (strcmp(GAME_DEFAULT_RULESETDIR
, game
.server
.rulesetdir
)
6033 && (restore
== NULL
|| strcmp(GAME_DEFAULT_RULESETDIR
, restore
))) {
6034 if (load_rulesetdir(GAME_DEFAULT_RULESETDIR
, act
)) {
6035 /* We're in sane state as fallback ruleset loading succeeded,
6036 * but return failure to indicate that this is not what caller
6038 sz_strlcpy(game
.server
.rulesetdir
, GAME_DEFAULT_RULESETDIR
);
6040 notify_ruleset_fallback(_("Ruleset couldn't be loaded. Switching to default one."));
6046 /* Cannot load even default ruleset, we're in completely unusable state */
6050 /**************************************************************************
6051 destroy secfile. Handle NULL parameter gracefully.
6052 **************************************************************************/
6053 static void nullcheck_secfile_destroy(struct section_file
*file
)
6056 secfile_destroy(file
);
6060 /**************************************************************************
6061 Completely deinitialize ruleset system. Server is not in usable
6063 **************************************************************************/
6064 void rulesets_deinit(void)
6066 script_server_free();
6069 /**************************************************************************
6070 Loads the rulesets from directory.
6071 This may be called more than once and it will free any stale data.
6072 **************************************************************************/
6073 static bool load_rulesetdir(const char *rsdir
, bool act
)
6075 struct section_file
*techfile
, *unitfile
, *buildfile
, *govfile
, *terrfile
;
6076 struct section_file
*cityfile
, *nationfile
, *effectfile
;
6079 log_normal(_("Loading rulesets."));
6081 game_ruleset_free();
6082 /* Reset the list of available player colors. */
6085 game_ruleset_init();
6087 server
.playable_nations
= 0;
6089 techfile
= openload_ruleset_file("techs", rsdir
);
6090 buildfile
= openload_ruleset_file("buildings", rsdir
);
6091 govfile
= openload_ruleset_file("governments", rsdir
);
6092 unitfile
= openload_ruleset_file("units", rsdir
);
6093 terrfile
= openload_ruleset_file("terrain", rsdir
);
6094 cityfile
= openload_ruleset_file("cities", rsdir
);
6095 nationfile
= openload_ruleset_file("nations", rsdir
);
6096 effectfile
= openload_ruleset_file("effects", rsdir
);
6098 if (techfile
== NULL
6099 || buildfile
== NULL
6104 || nationfile
== NULL
6105 || effectfile
== NULL
) {
6110 ok
= load_tech_names(techfile
)
6111 && load_building_names(buildfile
)
6112 && load_government_names(govfile
)
6113 && load_unit_names(unitfile
)
6114 && load_terrain_names(terrfile
)
6115 && load_citystyle_names(cityfile
)
6116 && load_nation_names(nationfile
);
6120 ok
= load_ruleset_techs(techfile
);
6123 ok
= load_ruleset_cities(cityfile
);
6126 ok
= load_ruleset_governments(govfile
);
6129 ok
= load_ruleset_terrain(terrfile
); /* terrain must precede nations and units */
6132 ok
= load_ruleset_units(unitfile
);
6135 ok
= load_ruleset_buildings(buildfile
);
6138 ok
= load_ruleset_nations(nationfile
);
6141 ok
= load_ruleset_effects(effectfile
);
6144 ok
= load_ruleset_game(rsdir
, act
);
6148 /* Init nations we just loaded. */
6149 update_nations_with_startpos();
6151 ok
= sanity_check_ruleset_data();
6154 nullcheck_secfile_destroy(techfile
);
6155 nullcheck_secfile_destroy(cityfile
);
6156 nullcheck_secfile_destroy(govfile
);
6157 nullcheck_secfile_destroy(terrfile
);
6158 nullcheck_secfile_destroy(unitfile
);
6159 nullcheck_secfile_destroy(buildfile
);
6160 nullcheck_secfile_destroy(nationfile
);
6161 nullcheck_secfile_destroy(effectfile
);
6163 if (base_sections
) {
6164 free(base_sections
);
6165 base_sections
= NULL
;
6167 if (road_sections
) {
6168 free(road_sections
);
6169 road_sections
= NULL
;
6171 if (resource_sections
) {
6172 free(resource_sections
);
6173 resource_sections
= NULL
;
6175 if (terrain_sections
) {
6176 free(terrain_sections
);
6177 terrain_sections
= NULL
;
6181 script_server_free();
6183 script_server_init();
6185 ok
= openload_script_file("script", rsdir
)
6186 && openload_script_file("default", rsdir
);
6190 precalc_tech_data();
6192 /* Build advisors unit class cache corresponding to loaded rulesets */
6193 adv_units_ruleset_init();
6194 CALL_FUNC_EACH_AI(units_ruleset_init
);
6196 /* We may need to adjust the number of AI players
6197 * if the number of available nations changed. */
6199 aifill(game
.info
.aifill
);
6206 /**************************************************************************
6207 Reload the game settings saved in the ruleset file.
6208 **************************************************************************/
6209 bool reload_rulesets_settings(void)
6211 struct section_file
*file
;
6214 file
= openload_ruleset_file("game", game
.server
.rulesetdir
);
6216 ruleset_error(LOG_ERROR
, "Could not load game.ruleset:\n%s",
6221 settings_ruleset(file
, "settings", TRUE
);
6222 secfile_destroy(file
);
6228 /**************************************************************************
6229 Send all ruleset information to the specified connections.
6230 **************************************************************************/
6231 void send_rulesets(struct conn_list
*dest
)
6233 conn_list_compression_freeze(dest
);
6235 /* ruleset_control also indicates to client that ruleset sending starts. */
6236 send_ruleset_control(dest
);
6238 send_ruleset_game(dest
);
6239 send_ruleset_disasters(dest
);
6240 send_ruleset_trade_routes(dest
);
6241 send_ruleset_team_names(dest
);
6242 send_ruleset_techs(dest
);
6243 send_ruleset_governments(dest
);
6244 send_ruleset_unit_classes(dest
);
6245 send_ruleset_units(dest
);
6246 send_ruleset_specialists(dest
);
6247 send_ruleset_resources(dest
);
6248 send_ruleset_terrain(dest
);
6249 send_ruleset_bases(dest
);
6250 send_ruleset_roads(dest
);
6251 send_ruleset_buildings(dest
);
6252 send_ruleset_nations(dest
);
6253 send_ruleset_cities(dest
);
6254 send_ruleset_cache(dest
);
6256 /* Indicate client that all rulesets have now been sent. */
6257 lsend_packet_rulesets_ready(dest
);
6259 /* changed game settings will be send in
6260 * connecthand.c:establish_new_connection() */
6262 conn_list_compression_thaw(dest
);