civ2civ3: improve README.civ2civ3 text.
[freeciv.git] / server / ruleset.c
blob9864259cf9c101daf8df2896d991ff297bd5614b
1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 #include <stdarg.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
23 /* utility */
24 #include "bitvector.h"
25 #include "deprecations.h"
26 #include "fcintl.h"
27 #include "log.h"
28 #include "mem.h"
29 #include "registry.h"
30 #include "shared.h"
31 #include "string_vector.h"
32 #include "support.h"
34 /* common */
35 #include "achievements.h"
36 #include "actions.h"
37 #include "ai.h"
38 #include "base.h"
39 #include "capability.h"
40 #include "city.h"
41 #include "effects.h"
42 #include "extras.h"
43 #include "fc_types.h"
44 #include "featured_text.h"
45 #include "game.h"
46 #include "government.h"
47 #include "map.h"
48 #include "movement.h"
49 #include "multipliers.h"
50 #include "name_translation.h"
51 #include "nation.h"
52 #include "packets.h"
53 #include "player.h"
54 #include "requirements.h"
55 #include "rgbcolor.h"
56 #include "road.h"
57 #include "specialist.h"
58 #include "style.h"
59 #include "tech.h"
60 #include "traderoutes.h"
61 #include "unit.h"
62 #include "unittype.h"
64 /* server */
65 #include "citytools.h"
66 #include "notify.h"
67 #include "plrhand.h"
68 #include "rscompat.h"
69 #include "rssanity.h"
70 #include "settings.h"
71 #include "srv_main.h"
73 /* server/advisors */
74 #include "advruleset.h"
76 /* server/scripting */
77 #include "script_server.h"
79 #include "ruleset.h"
81 /* RULESET_SUFFIX already used, no leading dot here */
82 #define RULES_SUFFIX "ruleset"
83 #define SCRIPT_SUFFIX "lua"
85 #define ADVANCE_SECTION_PREFIX "advance_"
86 #define TECH_CLASS_SECTION_PREFIX "techclass_"
87 #define BUILDING_SECTION_PREFIX "building_"
88 #define CITYSTYLE_SECTION_PREFIX "citystyle_"
89 #define MUSICSTYLE_SECTION_PREFIX "musicstyle_"
90 #define EFFECT_SECTION_PREFIX "effect_"
91 #define GOVERNMENT_SECTION_PREFIX "government_"
92 #define NATION_SET_SECTION_PREFIX "nset" /* without underscore? */
93 #define NATION_GROUP_SECTION_PREFIX "ngroup" /* without underscore? */
94 #define NATION_SECTION_PREFIX "nation" /* without underscore? */
95 #define STYLE_SECTION_PREFIX "style_"
96 #define EXTRA_SECTION_PREFIX "extra_"
97 #define BASE_SECTION_PREFIX "base_"
98 #define ROAD_SECTION_PREFIX "road_"
99 #define RESOURCE_SECTION_PREFIX "resource_"
100 #define GOODS_SECTION_PREFIX "goods_"
101 #define SPECIALIST_SECTION_PREFIX "specialist_"
102 #define TERRAIN_SECTION_PREFIX "terrain_"
103 #define UNIT_CLASS_SECTION_PREFIX "unitclass_"
104 #define UNIT_SECTION_PREFIX "unit_"
105 #define DISASTER_SECTION_PREFIX "disaster_"
106 #define ACHIEVEMENT_SECTION_PREFIX "achievement_"
107 #define ACTION_ENABLER_SECTION_PREFIX "actionenabler_"
108 #define MULTIPLIER_SECTION_PREFIX "multiplier_"
110 #define check_name(name) (check_strlen(name, MAX_LEN_NAME, NULL))
111 #define check_cityname(name) (check_strlen(name, MAX_LEN_CITYNAME, NULL))
113 /* avoid re-reading files */
114 static const char name_too_long[] = "Name \"%s\" too long; truncating.";
115 #define MAX_SECTION_LABEL 64
116 #define section_strlcpy(dst, src) \
117 (void) loud_strlcpy(dst, src, MAX_SECTION_LABEL, name_too_long)
118 static char *resource_sections = NULL;
119 static char *terrain_sections = NULL;
120 static char *extra_sections = NULL;
121 static char *base_sections = NULL;
122 static char *road_sections = NULL;
124 static struct requirement_vector reqs_list;
126 static bool load_rulesetdir(const char *rsdir, bool compat_mode,
127 bool act, bool buffer_script);
128 static struct section_file *openload_ruleset_file(const char *whichset,
129 const char *rsdir);
131 static bool load_game_names(struct section_file *file,
132 struct rscompat_info *compat);
133 static bool load_tech_names(struct section_file *file,
134 struct rscompat_info *compat);
135 static bool load_unit_names(struct section_file *file,
136 struct rscompat_info *compat);
137 static bool load_building_names(struct section_file *file,
138 struct rscompat_info *compat);
139 static bool load_government_names(struct section_file *file,
140 struct rscompat_info *compat);
141 static bool load_terrain_names(struct section_file *file,
142 struct rscompat_info *compat);
143 static bool load_style_names(struct section_file *file,
144 struct rscompat_info *compat);
145 static bool load_nation_names(struct section_file *file,
146 struct rscompat_info *compat);
147 static bool load_city_name_list(struct section_file *file,
148 struct nation_type *pnation,
149 const char *secfile_str1,
150 const char *secfile_str2,
151 const char **allowed_terrains,
152 size_t atcount);
154 static bool load_ruleset_techs(struct section_file *file,
155 struct rscompat_info *compat);
156 static bool load_ruleset_units(struct section_file *file,
157 struct rscompat_info *compat);
158 static bool load_ruleset_buildings(struct section_file *file,
159 struct rscompat_info *compat);
160 static bool load_ruleset_governments(struct section_file *file,
161 struct rscompat_info *compat);
162 static bool load_ruleset_terrain(struct section_file *file,
163 struct rscompat_info *compat);
164 static bool load_ruleset_styles(struct section_file *file,
165 struct rscompat_info *compat);
166 static bool load_ruleset_cities(struct section_file *file,
167 struct rscompat_info *compat);
168 static bool load_ruleset_effects(struct section_file *file,
169 struct rscompat_info *compat);
170 static bool load_ruleset_game(struct section_file *file, bool act,
171 struct rscompat_info *compat);
173 static void send_ruleset_tech_classes(struct conn_list *dest);
174 static void send_ruleset_techs(struct conn_list *dest);
175 static void send_ruleset_unit_classes(struct conn_list *dest);
176 static void send_ruleset_units(struct conn_list *dest);
177 static void send_ruleset_buildings(struct conn_list *dest);
178 static void send_ruleset_terrain(struct conn_list *dest);
179 static void send_ruleset_resources(struct conn_list *dest);
180 static void send_ruleset_extras(struct conn_list *dest);
181 static void send_ruleset_bases(struct conn_list *dest);
182 static void send_ruleset_roads(struct conn_list *dest);
183 static void send_ruleset_goods(struct conn_list *dest);
184 static void send_ruleset_governments(struct conn_list *dest);
185 static void send_ruleset_styles(struct conn_list *dest);
186 static void send_ruleset_musics(struct conn_list *dest);
187 static void send_ruleset_cities(struct conn_list *dest);
188 static void send_ruleset_game(struct conn_list *dest);
189 static void send_ruleset_team_names(struct conn_list *dest);
191 static bool load_ruleset_veteran(struct section_file *file,
192 const char *path,
193 struct veteran_system **vsystem, char *err,
194 size_t err_len);
196 char *script_buffer = NULL;
198 /**************************************************************************
199 Notifications about ruleset errors to clients. Especially important in
200 case of internal server crashing.
201 **************************************************************************/
202 void ruleset_error_real(const char *file, const char *function,
203 int line, enum log_level level,
204 const char *format, ...)
206 va_list args;
207 char buf[1024];
209 va_start(args, format);
210 vdo_log(file, function, line, FALSE, level, buf, sizeof(buf), format, args);
211 va_end(args);
213 if (LOG_FATAL >= level) {
214 exit(EXIT_FAILURE);
218 /**************************************************************************
219 datafilename() wrapper: tries to match in two ways.
220 Returns NULL on failure, the (statically allocated) filename on success.
221 **************************************************************************/
222 static const char *valid_ruleset_filename(const char *subdir,
223 const char *name,
224 const char *extension)
226 char filename[512];
227 const char *dfilename;
229 fc_assert_ret_val(subdir && name && extension, NULL);
231 fc_snprintf(filename, sizeof(filename), "%s" DIR_SEPARATOR "%s.%s",
232 subdir, name, extension);
233 log_verbose("Trying \"%s\".", filename);
234 dfilename = fileinfoname(get_data_dirs(), filename);
235 if (dfilename) {
236 return dfilename;
239 fc_snprintf(filename, sizeof(filename), "default" DIR_SEPARATOR "%s.%s", name, extension);
240 log_verbose("Trying \"%s\": default ruleset directory.", filename);
241 dfilename = fileinfoname(get_data_dirs(), filename);
242 if (dfilename) {
243 return dfilename;
246 fc_snprintf(filename, sizeof(filename), "%s_%s.%s",
247 subdir, name, extension);
248 log_verbose("Trying \"%s\": alternative ruleset filename syntax.",
249 filename);
250 dfilename = fileinfoname(get_data_dirs(), filename);
251 if (dfilename) {
252 return dfilename;
253 } else {
254 ruleset_error(LOG_ERROR,
255 /* TRANS: message about an installation error. */
256 _("Could not find a readable \"%s.%s\" ruleset file."),
257 name, extension);
260 return NULL;
263 /**************************************************************************
264 Return current script.lua buffer.
265 **************************************************************************/
266 char *get_script_buffer(void)
268 return script_buffer;
271 /**************************************************************************
272 Do initial section_file_load on a ruleset file.
273 "whichset" = "techs", "units", "buildings", "terrain", ...
274 **************************************************************************/
275 static struct section_file *openload_ruleset_file(const char *whichset,
276 const char *rsdir)
278 char sfilename[512];
279 const char *dfilename = valid_ruleset_filename(rsdir, whichset,
280 RULES_SUFFIX);
281 struct section_file *secfile;
283 if (dfilename == NULL) {
284 return NULL;
287 /* Need to save a copy of the filename for following message, since
288 section_file_load() may call datafilename() for includes. */
289 sz_strlcpy(sfilename, dfilename);
290 secfile = secfile_load(sfilename, FALSE);
292 if (secfile == NULL) {
293 ruleset_error(LOG_ERROR, "Could not load ruleset '%s':\n%s",
294 sfilename, secfile_error());
297 return secfile;
300 /**************************************************************************
301 Parse script file.
302 **************************************************************************/
303 static bool openload_script_file(const char *whichset, const char *rsdir,
304 char **buffer)
306 const char *dfilename = valid_ruleset_filename(rsdir, whichset,
307 SCRIPT_SUFFIX);
309 if (dfilename == NULL) {
310 return FALSE;
313 if (buffer == NULL) {
314 if (!script_server_do_file(NULL, dfilename)) {
315 ruleset_error(LOG_ERROR, "\"%s\": could not load ruleset script.",
316 dfilename);
318 return FALSE;
320 } else {
321 script_server_load_file(dfilename, buffer);
324 return TRUE;
327 /**************************************************************************
328 Load a requirement list. The list is returned as a static vector
329 (callers need not worry about freeing anything).
330 **************************************************************************/
331 static struct requirement_vector *lookup_req_list(struct section_file *file,
332 struct rscompat_info *compat,
333 const char *sec,
334 const char *sub,
335 const char *rfor)
337 const char *type, *name;
338 int j;
339 const char *filename;
341 filename = secfile_name(file);
343 requirement_vector_reserve(&reqs_list, 0);
345 for (j = 0; (type = secfile_lookup_str_default(file, NULL, "%s.%s%d.type",
346 sec, sub, j)); j++) {
347 char buf[MAX_LEN_NAME];
348 const char *range;
349 bool survives, present, quiet;
350 struct entry *pentry;
351 struct requirement req;
353 if (!(pentry = secfile_entry_lookup(file, "%s.%s%d.name",
354 sec, sub, j))) {
355 ruleset_error(LOG_ERROR, "%s", secfile_error());
357 return NULL;
359 name = NULL;
360 switch (entry_type(pentry)) {
361 case ENTRY_BOOL:
363 bool val;
365 if (entry_bool_get(pentry, &val)) {
366 fc_snprintf(buf, sizeof(buf), "%d", val);
367 name = buf;
370 break;
371 case ENTRY_INT:
373 int val;
375 if (entry_int_get(pentry, &val)) {
376 fc_snprintf(buf, sizeof(buf), "%d", val);
377 name = buf;
380 break;
381 case ENTRY_STR:
382 (void) entry_str_get(pentry, &name);
383 break;
384 case ENTRY_FLOAT:
385 fc_assert(entry_type(pentry) != ENTRY_FLOAT);
386 ruleset_error(LOG_ERROR,
387 "\"%s\": trying to have an floating point entry as a requirement name in '%s.%s%d'.",
388 filename, sec, sub, j);
389 break;
390 case ENTRY_FILEREFERENCE:
391 fc_assert(entry_type(pentry) != ENTRY_FILEREFERENCE);
393 if (NULL == name) {
394 ruleset_error(LOG_ERROR,
395 "\"%s\": error in handling requirement name for '%s.%s%d'.",
396 filename, sec, sub, j);
397 return NULL;
400 if (!(range = secfile_lookup_str(file, "%s.%s%d.range", sec, sub, j))) {
401 ruleset_error(LOG_ERROR, "%s", secfile_error());
403 return NULL;
406 survives = FALSE;
407 if ((pentry = secfile_entry_lookup(file, "%s.%s%d.survives",
408 sec, sub, j))
409 && !entry_bool_get(pentry, &survives)) {
410 ruleset_error(LOG_ERROR,
411 "\"%s\": invalid boolean value for survives for "
412 "'%s.%s%d'.", filename, sec, sub, j);
415 present = TRUE;
416 if ((pentry = secfile_entry_lookup(file, "%s.%s%d.present",
417 sec, sub, j))
418 && !entry_bool_get(pentry, &present)) {
419 ruleset_error(LOG_ERROR,
420 "\"%s\": invalid boolean value for present for "
421 "'%s.%s%d'.", filename, sec, sub, j);
423 quiet = FALSE;
424 if ((pentry = secfile_entry_lookup(file, "%s.%s%d.quiet",
425 sec, sub, j))
426 && !entry_bool_get(pentry, &quiet)) {
427 ruleset_error(LOG_ERROR,
428 "\"%s\": invalid boolean value for quiet for "
429 "'%s.%s%d'.", filename, sec, sub, j);
432 if (compat->compat_mode) {
433 if (!fc_strcasecmp(type, universals_n_name(VUT_UTFLAG))) {
434 name = rscompat_utype_flag_name_3_1(compat, name);
438 if (compat->compat_mode) {
439 name = rscompat_req_name_3_1(type, name);
442 req = req_from_str(type, range, survives, present, quiet, name);
443 if (req.source.kind == universals_n_invalid()) {
444 ruleset_error(LOG_ERROR, "\"%s\" [%s] has invalid or unknown req: "
445 "\"%s\" \"%s\".",
446 filename, sec, type, name);
448 return NULL;
451 requirement_vector_append(&reqs_list, req);
454 if (j > MAX_NUM_REQS) {
455 ruleset_error(LOG_ERROR, "Too many (%d) requirements for %s. Max is %d",
456 j, rfor, MAX_NUM_REQS);
458 return NULL;
461 return &reqs_list;
464 /**************************************************************************
465 Load combat bonus list
466 **************************************************************************/
467 static bool lookup_cbonus_list(struct rscompat_info *compat,
468 struct combat_bonus_list *list,
469 struct section_file *file,
470 const char *sec,
471 const char *sub)
473 const char *flag;
474 int j;
475 const char *filename;
476 bool success = TRUE;
478 filename = secfile_name(file);
480 for (j = 0; (flag = secfile_lookup_str_default(file, NULL, "%s.%s%d.flag",
481 sec, sub, j)); j++) {
482 struct combat_bonus *bonus = fc_malloc(sizeof(*bonus));
483 const char *type;
485 bonus->flag = unit_type_flag_id_by_name(rscompat_utype_flag_name_3_1(compat, flag),
486 fc_strcasecmp);
487 if (!unit_type_flag_id_is_valid(bonus->flag)) {
488 log_error("\"%s\": unknown flag name \"%s\" in '%s.%s'.",
489 filename, flag, sec, sub);
490 FC_FREE(bonus);
491 success = FALSE;
492 continue;
494 type = secfile_lookup_str(file, "%s.%s%d.type", sec, sub, j);
495 bonus->type = combat_bonus_type_by_name(type, fc_strcasecmp);
496 if (!combat_bonus_type_is_valid(bonus->type)) {
497 log_error("\"%s\": unknown bonus type \"%s\" in '%s.%s'.",
498 filename, type, sec, sub);
499 FC_FREE(bonus);
500 success = FALSE;
501 continue;
503 if (!secfile_lookup_int(file, &bonus->value, "%s.%s%d.value",
504 sec, sub, j)) {
505 log_error("\"%s\": failed to get value from '%s.%s%d'.",
506 filename, sec, sub, j);
507 FC_FREE(bonus);
508 success = FALSE;
509 continue;
511 bonus->quiet = secfile_lookup_bool_default(file, FALSE,
512 "%s.%s%d.quiet",
513 sec, sub, j);
514 combat_bonus_list_append(list, bonus);
517 return success;
520 /**************************************************************************
521 Lookup a string prefix.entry in the file and return the corresponding
522 advances pointer. If (!required), return A_NEVER for match "Never" or
523 can't match. If (required), die when can't match. Note the first tech
524 should have name "None" so that will always match.
525 If description is not NULL, it is used in the warning message
526 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
527 **************************************************************************/
528 static bool lookup_tech(struct section_file *file,
529 struct advance **result,
530 const char *prefix, const char *entry,
531 const char *filename,
532 const char *description)
534 const char *sval;
536 sval = secfile_lookup_str_default(file, NULL, "%s.%s", prefix, entry);
537 if (!sval || !strcmp(sval, "Never")) {
538 *result = A_NEVER;
539 } else {
540 *result = advance_by_rule_name(sval);
542 if (A_NEVER == *result) {
543 ruleset_error(LOG_ERROR,
544 "\"%s\" %s %s: couldn't match \"%s\".",
545 filename, (description ? description : prefix), entry, sval);
546 return FALSE;
550 return TRUE;
553 /**************************************************************************
554 Lookup a string prefix.entry in the file and return the corresponding
555 improvement pointer. Return B_NEVER for match "None" or
556 can't match.
557 If description is not NULL, it is used in the warning message
558 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
559 **************************************************************************/
560 static bool lookup_building(struct section_file *file,
561 const char *prefix, const char *entry,
562 struct impr_type **result,
563 const char *filename,
564 const char *description)
566 const char *sval;
567 bool ok = TRUE;
569 sval = secfile_lookup_str_default(file, NULL, "%s.%s", prefix, entry);
570 if (!sval || strcmp(sval, "None") == 0) {
571 *result = B_NEVER;
572 } else {
573 *result = improvement_by_rule_name(sval);
575 if (B_NEVER == *result) {
576 ruleset_error(LOG_ERROR,
577 "\"%s\" %s %s: couldn't match \"%s\".",
578 filename, (description ? description : prefix), entry, sval);
579 ok = FALSE;
583 return ok;
586 /**************************************************************************
587 Lookup a prefix.entry string vector in the file and fill in the
588 array, which should hold MAX_NUM_UNIT_LIST items. The output array is
589 either NULL terminated or full (contains MAX_NUM_UNIT_LIST
590 items). If the vector is not found and the required parameter is set,
591 we report it as an error, otherwise we just punt.
592 **************************************************************************/
593 static bool lookup_unit_list(struct section_file *file, const char *prefix,
594 const char *entry,
595 struct unit_type **output,
596 const char *filename)
598 const char **slist;
599 size_t nval;
600 int i;
601 bool ok = TRUE;
603 /* pre-fill with NULL: */
604 for (i = 0; i < MAX_NUM_UNIT_LIST; i++) {
605 output[i] = NULL;
607 slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
608 if (nval == 0) {
609 /* 'No vector' is considered same as empty vector */
610 if (slist != NULL) {
611 free(slist);
613 return TRUE;
615 if (nval > MAX_NUM_UNIT_LIST) {
616 ruleset_error(LOG_ERROR,
617 "\"%s\": string vector %s.%s too long (%d, max %d)",
618 filename, prefix, entry, (int) nval, MAX_NUM_UNIT_LIST);
619 ok = FALSE;
620 } else if (nval == 1 && strcmp(slist[0], "") == 0) {
621 free(slist);
622 return TRUE;
624 if (ok) {
625 for (i = 0; i < nval; i++) {
626 const char *sval = slist[i];
627 struct unit_type *punittype = unit_type_by_rule_name(sval);
629 if (!punittype) {
630 ruleset_error(LOG_ERROR,
631 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
632 filename, prefix, entry, i, sval);
633 ok = FALSE;
634 break;
636 output[i] = punittype;
637 log_debug("\"%s\" %s.%s (%d): %s (%d)", filename, prefix, entry, i, sval,
638 utype_number(punittype));
641 free(slist);
643 return ok;
646 /**************************************************************************
647 Lookup a prefix.entry string vector in the file and fill in the
648 array, which should hold MAX_NUM_TECH_LIST items. The output array is
649 either A_LAST terminated or full (contains MAX_NUM_TECH_LIST
650 items). All valid entries of the output array are guaranteed to
651 exist.
652 **************************************************************************/
653 static bool lookup_tech_list(struct section_file *file, const char *prefix,
654 const char *entry, int *output,
655 const char *filename)
657 const char **slist;
658 size_t nval;
659 int i;
660 bool ok = TRUE;
662 /* pre-fill with A_LAST: */
663 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
664 output[i] = A_LAST;
666 slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
667 if (slist == NULL || nval == 0) {
668 return TRUE;
669 } else if (nval > MAX_NUM_TECH_LIST) {
670 ruleset_error(LOG_ERROR,
671 "\"%s\": string vector %s.%s too long (%d, max %d)",
672 filename, prefix, entry, (int) nval, MAX_NUM_TECH_LIST);
673 ok = FALSE;
676 if (ok) {
677 if (nval == 1 && strcmp(slist[0], "") == 0) {
678 FC_FREE(slist);
679 return TRUE;
681 for (i = 0; i < nval && ok; i++) {
682 const char *sval = slist[i];
683 struct advance *padvance = advance_by_rule_name(sval);
685 if (NULL == padvance) {
686 ruleset_error(LOG_ERROR,
687 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
688 filename, prefix, entry, i, sval);
689 ok = FALSE;
691 if (!valid_advance(padvance)) {
692 ruleset_error(LOG_ERROR, "\"%s\" %s.%s (%d): \"%s\" is removed.",
693 filename, prefix, entry, i, sval);
694 ok = FALSE;
697 if (ok) {
698 output[i] = advance_number(padvance);
699 log_debug("\"%s\" %s.%s (%d): %s (%d)", filename, prefix, entry, i, sval,
700 advance_number(padvance));
704 FC_FREE(slist);
706 return ok;
709 /**************************************************************************
710 Lookup a prefix.entry string vector in the file and fill in the
711 array, which should hold MAX_NUM_BUILDING_LIST items. The output array is
712 either B_LAST terminated or full (contains MAX_NUM_BUILDING_LIST
713 items). [All valid entries of the output array are guaranteed to pass
714 improvement_exist()?]
715 **************************************************************************/
716 static bool lookup_building_list(struct section_file *file,
717 const char *prefix, const char *entry,
718 int *output, const char *filename)
720 const char **slist;
721 size_t nval;
722 int i;
723 bool ok = TRUE;
725 /* pre-fill with B_LAST: */
726 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
727 output[i] = B_LAST;
729 slist = secfile_lookup_str_vec(file, &nval, "%s.%s", prefix, entry);
730 if (nval > MAX_NUM_BUILDING_LIST) {
731 ruleset_error(LOG_ERROR,
732 "\"%s\": string vector %s.%s too long (%d, max %d)",
733 filename, prefix, entry, (int) nval, MAX_NUM_BUILDING_LIST);
734 ok = FALSE;
735 } else if (nval == 0 || (nval == 1 && strcmp(slist[0], "") == 0)) {
736 if (slist != NULL) {
737 FC_FREE(slist);
739 return TRUE;
741 if (ok) {
742 for (i = 0; i < nval; i++) {
743 const char *sval = slist[i];
744 struct impr_type *pimprove = improvement_by_rule_name(sval);
746 if (NULL == pimprove) {
747 ruleset_error(LOG_ERROR,
748 "\"%s\" %s.%s (%d): couldn't match \"%s\".",
749 filename, prefix, entry, i, sval);
750 ok = FALSE;
751 break;
753 output[i] = improvement_number(pimprove);
754 log_debug("%s.%s,%d %s %d", prefix, entry, i, sval, output[i]);
757 free(slist);
759 return ok;
762 /**************************************************************************
763 Lookup a string prefix.entry in the file and set result to the corresponding
764 unit_type.
765 If description is not NULL, it is used in the warning message
766 instead of prefix (eg pass unit->name instead of prefix="units2.u27")
767 **************************************************************************/
768 static bool lookup_unit_type(struct section_file *file,
769 const char *prefix,
770 const char *entry,
771 struct unit_type **result,
772 const char *filename,
773 const char *description)
775 const char *sval;
777 sval = secfile_lookup_str_default(file, "None", "%s.%s", prefix, entry);
779 if (strcmp(sval, "None") == 0) {
780 *result = NULL;
781 } else {
782 *result = unit_type_by_rule_name(sval);
783 if (*result == NULL) {
784 ruleset_error(LOG_ERROR,
785 "\"%s\" %s %s: couldn't match \"%s\".",
786 filename, (description ? description : prefix), entry, sval);
788 return FALSE;
792 return TRUE;
795 /**************************************************************************
796 Lookup entry in the file and return the corresponding government index.
797 filename is for error message.
798 **************************************************************************/
799 static struct government *lookup_government(struct section_file *file,
800 const char *entry,
801 const char *filename,
802 struct government *fallback)
804 const char *sval;
805 struct government *gov;
807 sval = secfile_lookup_str_default(file, NULL, "%s", entry);
808 if (!sval) {
809 gov = fallback;
810 } else {
811 gov = government_by_rule_name(sval);
813 if (!gov) {
814 ruleset_error(LOG_ERROR,
815 "\"%s\" %s: couldn't match \"%s\".",
816 filename, entry, sval);
818 return gov;
821 /****************************************************************************
822 Lookup optional string, returning allocated memory or NULL.
823 ****************************************************************************/
824 static char *lookup_string(struct section_file *file, const char *prefix,
825 const char *suffix)
827 const char *sval = secfile_lookup_str(file, "%s.%s", prefix, suffix);
829 if (NULL != sval) {
830 char copy[strlen(sval) + 1];
832 strcpy(copy, sval);
833 remove_leading_trailing_spaces(copy);
834 if (strlen(copy) > 0) {
835 return fc_strdup(copy);
838 return NULL;
841 /****************************************************************************
842 Lookup optional string vector, returning allocated memory or NULL.
843 ****************************************************************************/
844 static struct strvec *lookup_strvec(struct section_file *file,
845 const char *prefix, const char *suffix)
847 size_t dim;
848 const char **vec = secfile_lookup_str_vec(file, &dim,
849 "%s.%s", prefix, suffix);
851 if (NULL != vec) {
852 struct strvec *dest = strvec_new();
854 strvec_store(dest, vec, dim);
855 free(vec);
856 return dest;
858 return NULL;
861 /**************************************************************************
862 Look up the resource section name and return its pointer.
863 **************************************************************************/
864 static struct extra_type *lookup_resource(const char *filename,
865 const char *name,
866 const char *jsection)
868 struct extra_type *pres;
870 pres = extra_type_by_rule_name(name);
872 if (pres == NULL) {
873 ruleset_error(LOG_ERROR,
874 "\"%s\" [%s] has unknown \"%s\".",
875 filename,
876 jsection,
877 name);
880 return pres;
883 /**************************************************************************
884 Look up the terrain by name and return its pointer.
885 filename is for error message.
886 **************************************************************************/
887 static bool lookup_terrain(struct section_file *file,
888 const char *entry,
889 const char *filename,
890 struct terrain *pthis,
891 struct terrain **result)
893 const int j = terrain_index(pthis);
894 const char *jsection = &terrain_sections[j * MAX_SECTION_LABEL];
895 const char *name = secfile_lookup_str(file, "%s.%s", jsection, entry);
896 struct terrain *pterr;
898 if (NULL == name
899 || *name == '\0'
900 || (0 == strcmp(name, "none"))
901 || (0 == strcmp(name, "no"))) {
902 *result = T_NONE;
904 return TRUE;
906 if (0 == strcmp(name, "yes")) {
907 *result = pthis;
909 return TRUE;
912 pterr = terrain_by_rule_name(name);
913 *result = pterr;
915 if (pterr == NULL) {
916 ruleset_error(LOG_ERROR, "\"%s\" [%s] has unknown \"%s\".",
917 secfile_name(file), jsection, name);
918 return FALSE;
921 return TRUE;
924 /**************************************************************************
925 Look up a value comparable to activity_count (road_time, etc).
926 item_name describes the thing which has the time property, if non-NULL,
927 for any error message.
928 Returns FALSE if not found in secfile, but TRUE even if validation failed.
929 Sets *ok to FALSE if validation failed, leaves it alone otherwise.
930 **************************************************************************/
931 static bool lookup_time(const struct section_file *secfile, int *turns,
932 const char *sec_name, const char *property_name,
933 const char *filename, const char *item_name,
934 bool *ok)
936 /* Assumes that PACKET_UNIT_INFO.activity_count in packets.def is UINT16 */
937 const int max_turns = 65535 / ACTIVITY_FACTOR;
939 if (!secfile_lookup_int(secfile, turns, "%s.%s", sec_name, property_name)) {
940 return FALSE;
943 if (*turns > max_turns) {
944 ruleset_error(LOG_ERROR,
945 "\"%s\": \"%s\": \"%s\" value %d too large (max %d)",
946 filename, item_name ? item_name : sec_name,
947 property_name, *turns, max_turns);
948 *ok = FALSE;
951 return TRUE; /* we found _something */
954 /**************************************************************************
955 Load "name" and (optionally) "rule_name" into a struct name_translation.
956 **************************************************************************/
957 static bool ruleset_load_names(struct name_translation *pname,
958 const char *domain,
959 struct section_file *file,
960 const char *sec_name)
962 const char *name = secfile_lookup_str(file, "%s.name", sec_name);
963 const char *rule_name = secfile_lookup_str(file, "%s.rule_name", sec_name);
965 if (!name) {
966 ruleset_error(LOG_ERROR,
967 "\"%s\" [%s]: no \"name\" specified.",
968 secfile_name(file), sec_name);
969 return FALSE;
972 names_set(pname, domain, name, rule_name);
974 return TRUE;
977 /**************************************************************************
978 Load trait values to array.
979 **************************************************************************/
980 static void ruleset_load_traits(struct trait_limits *out,
981 struct section_file *file,
982 const char *secname, const char *field_prefix)
984 enum trait tr;
986 /* FIXME: Use specenum trait names without duplicating them here.
987 * Just needs to take care of case. */
988 const char *trait_names[] = {
989 "expansionist",
990 "trader",
991 "aggressive",
992 NULL
995 for (tr = trait_begin(); tr != trait_end() && trait_names[tr] != NULL; tr = trait_next(tr)) {
996 out[tr].min = secfile_lookup_int_default(file, -1, "%s.%s%s_min",
997 secname,
998 field_prefix,
999 trait_names[tr]);
1000 out[tr].max = secfile_lookup_int_default(file, -1, "%s.%s%s_max",
1001 secname,
1002 field_prefix,
1003 trait_names[tr]);
1004 out[tr].fixed = secfile_lookup_int_default(file, -1, "%s.%s%s_default",
1005 secname,
1006 field_prefix,
1007 trait_names[tr]);
1010 fc_assert(tr == trait_end()); /* number of trait_names correct */
1013 /**************************************************************************
1014 Load names from game.ruleset so other rulesets can refer to objects
1015 with their name.
1016 **************************************************************************/
1017 static bool load_game_names(struct section_file *file,
1018 struct rscompat_info *compat)
1020 struct section_list *sec;
1021 int nval;
1022 const char *filename = secfile_name(file);
1023 bool ok = TRUE;
1025 /* section: datafile */
1026 compat->ver_game = rscompat_check_capabilities(file, filename, compat);
1027 if (compat->ver_game <= 0) {
1028 return FALSE;
1031 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
1032 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
1034 sec = secfile_sections_by_name_prefix(file, ACHIEVEMENT_SECTION_PREFIX);
1035 nval = (NULL != sec ? section_list_size(sec) : 0);
1036 if (nval > MAX_ACHIEVEMENT_TYPES) {
1037 int num = nval; /* No "size_t" to printf */
1039 ruleset_error(LOG_ERROR, "\"%s\": Too many achievement types (%d, max %d)",
1040 filename, num, MAX_ACHIEVEMENT_TYPES);
1041 ok = FALSE;
1042 } else {
1043 game.control.num_achievement_types = nval;
1046 if (ok) {
1047 achievements_iterate(pach) {
1048 const char *sec_name = section_name(section_list_get(sec, achievement_index(pach)));
1050 if (!ruleset_load_names(&pach->name, NULL, file, sec_name)) {
1051 ruleset_error(LOG_ERROR, "\"%s\": Cannot load achievement names",
1052 filename);
1053 ok = FALSE;
1054 break;
1056 } achievements_iterate_end;
1059 section_list_destroy(sec);
1061 if (compat->ver_game >= 10) {
1062 if (ok) {
1063 sec = secfile_sections_by_name_prefix(file, GOODS_SECTION_PREFIX);
1065 nval = (NULL != sec ? section_list_size(sec) : 0);
1066 if (nval > MAX_GOODS_TYPES) {
1067 int num = nval; /* No "size_t" to printf */
1069 ruleset_error(LOG_ERROR,
1070 "\"%s\": Too many goods types (%d, max %d)",
1071 filename, num, MAX_GOODS_TYPES);
1072 section_list_destroy(sec);
1073 ok = FALSE;
1074 } else if (nval < 1) {
1075 ruleset_error(LOG_ERROR, "\"%s\": At least one goods type needed",
1076 filename);
1077 section_list_destroy(sec);
1078 ok = FALSE;
1079 } else {
1080 game.control.num_goods_types = nval;
1083 if (ok) {
1084 goods_type_iterate(pgood) {
1085 const char *sec_name
1086 = section_name(section_list_get(sec, goods_index(pgood)));
1088 if (!ruleset_load_names(&pgood->name, NULL, file, sec_name)) {
1089 ruleset_error(LOG_ERROR, "\"%s\": Cannot load goods names",
1090 filename);
1091 ok = FALSE;
1092 break;
1094 } goods_type_iterate_end;
1099 return ok;
1103 /**************************************************************************
1104 Load names of technologies so other rulesets can refer to techs with
1105 their name.
1106 **************************************************************************/
1107 static bool load_tech_names(struct section_file *file,
1108 struct rscompat_info *compat)
1110 struct section_list *sec = NULL;
1111 /* Number of techs in the ruleset (means without A_NONE). */
1112 int num_techs = 0;
1113 int i;
1114 const char *filename = secfile_name(file);
1115 bool ok = TRUE;
1116 const char *flag;
1118 compat->ver_techs = rscompat_check_capabilities(file, filename, compat);
1119 if (compat->ver_techs <= 0) {
1120 return FALSE;
1123 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
1124 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
1126 /* User tech flag names */
1127 for (i = 0; (flag = secfile_lookup_str_default(file, NULL, "control.flags%d.name", i)) ;
1128 i++) {
1129 const char *helptxt = secfile_lookup_str_default(file, NULL, "control.flags%d.helptxt",
1131 if (tech_flag_id_by_name(flag, fc_strcasecmp) != tech_flag_id_invalid()) {
1132 ruleset_error(LOG_ERROR, "\"%s\": Duplicate tech flag name '%s'",
1133 filename, flag);
1134 ok = FALSE;
1135 break;
1137 if (i > MAX_NUM_USER_TECH_FLAGS) {
1138 ruleset_error(LOG_ERROR, "\"%s\": Too many user tech flags!",
1139 filename);
1140 ok = FALSE;
1141 break;
1144 set_user_tech_flag_name(TECH_USER_1 + i, flag, helptxt);
1147 if (ok) {
1148 size_t nval;
1150 for (; i < MAX_NUM_USER_TECH_FLAGS; i++) {
1151 set_user_tech_flag_name(TECH_USER_1 + i, NULL, NULL);
1154 /* Tech classes */
1155 sec = secfile_sections_by_name_prefix(file, TECH_CLASS_SECTION_PREFIX);
1157 nval = (NULL != sec ? section_list_size(sec) : 0);
1158 if (nval > MAX_NUM_TECH_CLASSES) {
1159 int num = nval; /* No "size_t" to printf */
1161 ruleset_error(LOG_ERROR,
1162 "\"%s\": Too many tech classes (%d, max %d)",
1163 filename, num, MAX_NUM_TECH_CLASSES);
1164 section_list_destroy(sec);
1165 ok = FALSE;
1166 } else {
1167 game.control.num_tech_classes = nval;
1170 if (ok) {
1171 tech_class_iterate(ptclass) {
1172 const char *sec_name
1173 = section_name(section_list_get(sec, tech_class_index(ptclass)));
1175 if (!ruleset_load_names(&ptclass->name, NULL, file, sec_name)) {
1176 ruleset_error(LOG_ERROR, "\"%s\": Cannot load tech class names",
1177 filename);
1178 ok = FALSE;
1179 break;
1181 } tech_class_iterate_end;
1185 if (ok) {
1186 /* The techs: */
1187 sec = secfile_sections_by_name_prefix(file, ADVANCE_SECTION_PREFIX);
1188 if (NULL == sec || 0 == (num_techs = section_list_size(sec))) {
1189 ruleset_error(LOG_ERROR, "\"%s\": No Advances?!?", filename);
1190 ok = FALSE;
1191 } else {
1192 log_verbose("%d advances (including possibly unused)", num_techs);
1193 if (num_techs + A_FIRST > A_LAST) {
1194 ruleset_error(LOG_ERROR, "\"%s\": Too many advances (%d, max %d)",
1195 filename, num_techs, A_LAST - A_FIRST);
1196 ok = FALSE;
1201 if (ok) {
1202 game.control.num_tech_types = num_techs + A_FIRST; /* includes A_NONE */
1204 i = 0;
1205 advance_iterate(A_FIRST, a) {
1206 if (!ruleset_load_names(&a->name, NULL, file, section_name(section_list_get(sec, i)))) {
1207 ok = FALSE;
1208 break;
1210 i++;
1211 } advance_iterate_end;
1213 section_list_destroy(sec);
1215 return ok;
1218 /**************************************************************************
1219 Load technologies related ruleset data
1220 **************************************************************************/
1221 static bool load_ruleset_techs(struct section_file *file,
1222 struct rscompat_info *compat)
1224 struct section_list *sec;
1225 const char **slist;
1226 int i;
1227 size_t nval;
1228 struct advance *a_none = advance_by_number(A_NONE);
1229 const char *filename = secfile_name(file);
1230 bool ok = TRUE;
1232 sec = secfile_sections_by_name_prefix(file, TECH_CLASS_SECTION_PREFIX);
1234 i = 0;
1235 tech_class_iterate(ptclass) {
1236 const char *sec_name = section_name(section_list_get(sec, i));
1238 ptclass->cost_pct = secfile_lookup_int_default(file, 100, "%s.%s",
1239 sec_name, "cost_pct");
1241 i++;
1242 } tech_class_iterate_end;
1244 sec = secfile_sections_by_name_prefix(file, ADVANCE_SECTION_PREFIX);
1246 i = 0;
1247 advance_iterate(A_FIRST, a) {
1248 const char *sec_name = section_name(section_list_get(sec, i));
1249 const char *sval;
1250 int j, ival;
1251 struct requirement_vector *research_reqs;
1253 if (!lookup_tech(file, &a->require[AR_ONE], sec_name, "req1",
1254 filename, rule_name_get(&a->name))
1255 || !lookup_tech(file, &a->require[AR_TWO], sec_name, "req2",
1256 filename, rule_name_get(&a->name))
1257 || !lookup_tech(file, &a->require[AR_ROOT], sec_name, "root_req",
1258 filename, rule_name_get(&a->name))) {
1259 ok = FALSE;
1260 break;
1263 if ((A_NEVER == a->require[AR_ONE] && A_NEVER != a->require[AR_TWO])
1264 || (A_NEVER != a->require[AR_ONE] && A_NEVER == a->require[AR_TWO])) {
1265 ruleset_error(LOG_ERROR, "\"%s\" [%s] \"%s\": \"Never\" with non-\"Never\".",
1266 filename, sec_name, rule_name_get(&a->name));
1267 ok = FALSE;
1268 break;
1270 if (a_none == a->require[AR_ONE] && a_none != a->require[AR_TWO]) {
1271 ruleset_error(LOG_ERROR, "\"%s\" [%s] \"%s\": should have \"None\" second.",
1272 filename, sec_name, rule_name_get(&a->name));
1273 ok = FALSE;
1274 break;
1277 if (game.control.num_tech_classes == 0) {
1278 a->tclass = NULL;
1279 } else {
1280 const char *classname;
1282 classname = lookup_string(file, sec_name, "class");
1283 if (classname != NULL) {
1284 classname = Q_(classname);
1285 a->tclass = tech_class_by_rule_name(classname);
1286 if (a->tclass == NULL) {
1287 ruleset_error(LOG_ERROR, "\"%s\" [%s] \"%s\": Uknown tech class \"%s\".",
1288 filename, sec_name, rule_name_get(&a->name), classname);
1289 ok = FALSE;
1290 break;
1292 } else {
1293 a->tclass = NULL; /* Default */
1297 research_reqs = lookup_req_list(file, compat, sec_name, "research_reqs",
1298 rule_name_get(&a->name));
1299 if (research_reqs == NULL) {
1300 ok = FALSE;
1301 break;
1304 requirement_vector_copy(&a->research_reqs, research_reqs);
1306 BV_CLR_ALL(a->flags);
1308 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name);
1309 for (j = 0; j < nval; j++) {
1310 sval = slist[j];
1311 if (strcmp(sval, "") == 0) {
1312 continue;
1314 ival = tech_flag_id_by_name(sval, fc_strcasecmp);
1315 if (!tech_flag_id_is_valid(ival)) {
1316 ruleset_error(LOG_ERROR, "\"%s\" [%s] \"%s\": bad flag name \"%s\".",
1317 filename, sec_name, rule_name_get(&a->name), sval);
1318 ok = FALSE;
1319 break;
1320 } else {
1321 BV_SET(a->flags, ival);
1324 free(slist);
1326 if (!ok) {
1327 break;
1330 sz_strlcpy(a->graphic_str,
1331 secfile_lookup_str_default(file, "-", "%s.graphic", sec_name));
1332 sz_strlcpy(a->graphic_alt,
1333 secfile_lookup_str_default(file, "-",
1334 "%s.graphic_alt", sec_name));
1336 a->helptext = lookup_strvec(file, sec_name, "helptext");
1337 a->bonus_message = lookup_string(file, sec_name, "bonus_message");
1338 a->cost = secfile_lookup_int_default(file, -1, "%s.%s",
1339 sec_name, "cost");
1340 a->num_reqs = 0;
1342 i++;
1343 } advance_iterate_end;
1345 /* Propagate a root tech up into the tech tree. Thus if a technology
1346 * X has Y has a root tech, then any technology requiring X also has
1347 * Y as a root tech. */
1348 restart:
1350 if (ok) {
1351 advance_iterate(A_FIRST, a) {
1352 if (valid_advance(a)
1353 && A_NEVER != a->require[AR_ROOT]) {
1354 bool out_of_order = FALSE;
1356 /* Now find any tech depending on this technology and update its
1357 * root_req. */
1358 advance_iterate(A_FIRST, b) {
1359 if (valid_advance(b)
1360 && A_NEVER == b->require[AR_ROOT]
1361 && (a == b->require[AR_ONE] || a == b->require[AR_TWO])) {
1362 b->require[AR_ROOT] = a->require[AR_ROOT];
1363 if (b < a) {
1364 out_of_order = TRUE;
1367 } advance_iterate_end;
1369 if (out_of_order) {
1370 /* HACK: If we just changed the root_tech of a lower-numbered
1371 * technology, we need to go back so that we can propagate the
1372 * root_tech up to that technology's parents... */
1373 goto restart;
1376 } advance_iterate_end;
1378 /* Now rename A_NEVER to A_NONE for consistency */
1379 advance_iterate(A_NONE, a) {
1380 if (A_NEVER == a->require[AR_ROOT]) {
1381 a->require[AR_ROOT] = a_none;
1383 } advance_iterate_end;
1385 /* Some more consistency checking:
1386 Non-removed techs depending on removed techs is too
1387 broken to fix by default, so die.
1389 advance_iterate(A_FIRST, a) {
1390 if (valid_advance(a)) {
1391 /* We check for recursive tech loops later,
1392 * in build_required_techs_helper. */
1393 if (!valid_advance(a->require[AR_ONE])) {
1394 ruleset_error(LOG_ERROR,
1395 "\"%s\" tech \"%s\": req1 leads to removed tech.",
1396 filename,
1397 advance_rule_name(a));
1398 ok = FALSE;
1399 break;
1401 if (!valid_advance(a->require[AR_TWO])) {
1402 ruleset_error(LOG_ERROR,
1403 "\"%s\" tech \"%s\": req2 leads to removed tech.",
1404 filename,
1405 advance_rule_name(a));
1406 ok = FALSE;
1407 break;
1410 } advance_iterate_end;
1413 section_list_destroy(sec);
1414 if (ok) {
1415 secfile_check_unused(file);
1418 return ok;
1421 /**************************************************************************
1422 Load names of units so other rulesets can refer to units with
1423 their name.
1424 **************************************************************************/
1425 static bool load_unit_names(struct section_file *file,
1426 struct rscompat_info *compat)
1428 struct section_list *sec = NULL;
1429 int nval = 0;
1430 int i;
1431 const char *filename = secfile_name(file);
1432 const char *flag;
1433 bool ok = TRUE;
1435 compat->ver_units = rscompat_check_capabilities(file, filename, compat);
1436 if (compat->ver_units <= 0) {
1437 return FALSE;
1440 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
1441 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
1443 /* User unit flag names */
1444 for (i = 0; (flag = secfile_lookup_str_default(file, NULL, "control.flags%d.name", i)) ;
1445 i++) {
1446 const char *helptxt = secfile_lookup_str_default(file, NULL, "control.flags%d.helptxt",
1449 if (unit_type_flag_id_by_name(rscompat_utype_flag_name_3_1(compat, flag),
1450 fc_strcasecmp)
1451 != unit_type_flag_id_invalid()) {
1452 ruleset_error(LOG_ERROR, "\"%s\": Duplicate unit flag name '%s'",
1453 filename, flag);
1454 ok = FALSE;
1455 break;
1457 if (i > MAX_NUM_USER_UNIT_FLAGS) {
1458 ruleset_error(LOG_ERROR, "\"%s\": Too many user unit type flags!",
1459 filename);
1460 ok = FALSE;
1461 break;
1464 set_user_unit_type_flag_name(UTYF_USER_FLAG_1 + i, flag, helptxt);
1467 if (ok) {
1468 /* Blank the remaining unit type user flags. */
1469 for (; i < MAX_NUM_USER_UNIT_FLAGS; i++) {
1470 set_user_unit_type_flag_name(UTYF_USER_FLAG_1 + i, NULL, NULL);
1474 if (ok) {
1475 /* User unit class flag names */
1476 for (i = 0;
1477 (flag = secfile_lookup_str_default(file, NULL,
1478 "control.class_flags%d.name",
1479 i));
1480 i++) {
1481 const char *helptxt = secfile_lookup_str_default(file, NULL,
1482 "control.class_flags%d.helptxt", i);
1484 if (unit_class_flag_id_by_name(flag, fc_strcasecmp)
1485 != unit_class_flag_id_invalid()) {
1486 ruleset_error(LOG_ERROR, "\"%s\": Duplicate unit class flag name "
1487 "'%s'",
1488 filename, flag);
1489 ok = FALSE;
1490 break;
1492 if (i > MAX_NUM_USER_UCLASS_FLAGS) {
1493 ruleset_error(LOG_ERROR, "\"%s\": Too many user unit class flags!",
1494 filename);
1495 ok = FALSE;
1496 break;
1499 set_user_unit_class_flag_name(UCF_USER_FLAG_1 + i, flag, helptxt);
1503 if (ok) {
1504 /* Blank the remaining unit class user flags. */
1505 for (; i < MAX_NUM_USER_UCLASS_FLAGS; i++) {
1506 set_user_unit_class_flag_name(UCF_USER_FLAG_1 + i, NULL, NULL);
1510 if (ok) {
1511 /* Unit classes */
1512 sec = secfile_sections_by_name_prefix(file, UNIT_CLASS_SECTION_PREFIX);
1513 if (NULL == sec || 0 == (nval = section_list_size(sec))) {
1514 ruleset_error(LOG_ERROR, "\"%s\": No unit classes?!?", filename);
1515 ok = FALSE;
1516 } else {
1517 log_verbose("%d unit classes", nval);
1518 if (nval > UCL_LAST) {
1519 ruleset_error(LOG_ERROR, "\"%s\": Too many unit classes (%d, max %d)",
1520 filename, nval, UCL_LAST);
1521 ok = FALSE;
1526 if (ok) {
1527 game.control.num_unit_classes = nval;
1529 unit_class_iterate(punitclass) {
1530 const int pci = uclass_index(punitclass);
1532 if (!ruleset_load_names(&punitclass->name, NULL, file,
1533 section_name(section_list_get(sec, pci)))) {
1534 ok = FALSE;
1535 break;
1537 } unit_class_iterate_end;
1539 section_list_destroy(sec);
1540 sec = NULL;
1542 /* The names: */
1543 if (ok) {
1544 sec = secfile_sections_by_name_prefix(file, UNIT_SECTION_PREFIX);
1545 if (NULL == sec || 0 == (nval = section_list_size(sec))) {
1546 ruleset_error(LOG_ERROR, "\"%s\": No unit types?!?", filename);
1547 ok = FALSE;
1548 } else {
1549 log_verbose("%d unit types (including possibly unused)", nval);
1550 if (nval > U_LAST) {
1551 ruleset_error(LOG_ERROR, "\"%s\": Too many unit types (%d, max %d)",
1552 filename, nval, U_LAST);
1553 ok = FALSE;
1558 if (ok) {
1559 game.control.num_unit_types = nval;
1561 unit_type_iterate(punittype) {
1562 const int utypei = utype_index(punittype);
1563 if (!ruleset_load_names(&punittype->name, NULL, file,
1564 section_name(section_list_get(sec, utypei)))) {
1565 ok = FALSE;
1566 break;
1568 } unit_type_iterate_end;
1570 section_list_destroy(sec);
1572 return ok;
1575 /**************************************************************************
1576 Load veteran levels.
1577 **************************************************************************/
1578 static bool load_ruleset_veteran(struct section_file *file,
1579 const char *path,
1580 struct veteran_system **vsystem, char *err,
1581 size_t err_len)
1583 const char **vlist_name;
1584 int *vlist_power, *vlist_raise, *vlist_wraise, *vlist_move;
1585 size_t count_name, count_power, count_raise, count_wraise, count_move;
1586 int i;
1587 bool ret = TRUE;
1589 /* The pointer should be uninitialised. */
1590 if (*vsystem != NULL) {
1591 fc_snprintf(err, err_len, "Veteran system is defined?!");
1592 return FALSE;
1595 /* Load data. */
1596 vlist_name = secfile_lookup_str_vec(file, &count_name,
1597 "%s.veteran_names", path);
1598 vlist_power = secfile_lookup_int_vec(file, &count_power,
1599 "%s.veteran_power_fact", path);
1600 vlist_raise = secfile_lookup_int_vec(file, &count_raise,
1601 "%s.veteran_raise_chance", path);
1602 vlist_wraise = secfile_lookup_int_vec(file, &count_wraise,
1603 "%s.veteran_work_raise_chance",
1604 path);
1605 vlist_move = secfile_lookup_int_vec(file, &count_move,
1606 "%s.veteran_move_bonus", path);
1608 if (count_name > MAX_VET_LEVELS) {
1609 ret = FALSE;
1610 fc_snprintf(err, err_len, "\"%s\": Too many veteran levels (section "
1611 "'%s': %lu, max %d)", secfile_name(file), path,
1612 (long unsigned)count_name, MAX_VET_LEVELS);
1613 } else if (count_name != count_power
1614 || count_name != count_raise
1615 || count_name != count_wraise
1616 || count_name != count_move) {
1617 ret = FALSE;
1618 fc_snprintf(err, err_len, "\"%s\": Different lengths for the veteran "
1619 "settings in section '%s'", secfile_name(file),
1620 path);
1621 } else if (count_name == 0) {
1622 /* Nothing defined. */
1623 *vsystem = NULL;
1624 } else {
1625 /* Generate the veteran system. */
1626 *vsystem = veteran_system_new((int)count_name);
1628 #define rs_sanity_veteran(_path, _entry, _i, _condition, _action) \
1629 if (_condition) { \
1630 log_error("Invalid veteran definition '%s.%s[%d]'!", \
1631 _path, _entry, _i); \
1632 log_debug("Failed check: '%s'. Update value: '%s'.", \
1633 #_condition, #_action); \
1634 _action; \
1636 for (i = 0; i < count_name; i++) {
1637 /* Some sanity checks. */
1638 rs_sanity_veteran(path, "veteran_power_fact", i,
1639 (vlist_power[i] < 0), vlist_power[i] = 0);
1640 rs_sanity_veteran(path, "veteran_raise_chance", i,
1641 (vlist_raise[i] < 0), vlist_raise[i] = 0);
1642 rs_sanity_veteran(path, "veteran_work_raise_chance", i,
1643 (vlist_wraise[i] < 0), vlist_wraise[i] = 0);
1644 rs_sanity_veteran(path, "veteran_move_bonus", i,
1645 (vlist_move[i] < 0), vlist_move[i] = 0);
1646 if (i == 0) {
1647 /* First element.*/
1648 rs_sanity_veteran(path, "veteran_power_fact", i,
1649 (vlist_power[i] != 100), vlist_power[i] = 100);
1650 } else if (i == count_name - 1) {
1651 /* Last element. */
1652 rs_sanity_veteran(path, "veteran_power_fact", i,
1653 (vlist_power[i] < vlist_power[i - 1]),
1654 vlist_power[i] = vlist_power[i - 1]);
1655 rs_sanity_veteran(path, "veteran_raise_chance", i,
1656 (vlist_raise[i] != 0), vlist_raise[i] = 0);
1657 rs_sanity_veteran(path, "veteran_work_raise_chance", i,
1658 (vlist_wraise[i] != 0), vlist_wraise[i] = 0);
1659 } else {
1660 /* All elements inbetween. */
1661 rs_sanity_veteran(path, "veteran_power_fact", i,
1662 (vlist_power[i] < vlist_power[i - 1]),
1663 vlist_power[i] = vlist_power[i - 1]);
1664 rs_sanity_veteran(path, "veteran_raise_chance", i,
1665 (vlist_raise[i] > 100), vlist_raise[i] = 100);
1666 rs_sanity_veteran(path, "veteran_work_raise_chance", i,
1667 (vlist_wraise[i] > 100), vlist_wraise[i] = 100);
1670 veteran_system_definition(*vsystem, i, vlist_name[i], vlist_power[i],
1671 vlist_move[i], vlist_raise[i],
1672 vlist_wraise[i]);
1674 #undef rs_sanity_veteran
1677 if (vlist_name) {
1678 free(vlist_name);
1680 if (vlist_power) {
1681 free(vlist_power);
1683 if (vlist_raise) {
1684 free(vlist_raise);
1686 if (vlist_wraise) {
1687 free(vlist_wraise);
1689 if (vlist_move) {
1690 free(vlist_move);
1693 return ret;
1696 /**************************************************************************
1697 Load units related ruleset data.
1698 **************************************************************************/
1699 static bool load_ruleset_units(struct section_file *file,
1700 struct rscompat_info *compat)
1702 int j, ival;
1703 size_t nval;
1704 struct section_list *sec, *csec;
1705 const char *sval, **slist;
1706 const char *filename = secfile_name(file);
1707 char msg[MAX_LEN_MSG];
1708 bool ok = TRUE;
1710 if (!load_ruleset_veteran(file, "veteran_system", &game.veteran, msg,
1711 sizeof(msg)) || game.veteran == NULL) {
1712 ruleset_error(LOG_ERROR, "Error loading the default veteran system: %s",
1713 msg);
1714 ok = FALSE;
1717 sec = secfile_sections_by_name_prefix(file, UNIT_SECTION_PREFIX);
1718 nval = (NULL != sec ? section_list_size(sec) : 0);
1720 csec = secfile_sections_by_name_prefix(file, UNIT_CLASS_SECTION_PREFIX);
1721 nval = (NULL != csec ? section_list_size(csec) : 0);
1723 if (ok) {
1724 unit_class_iterate(uc) {
1725 int i = uclass_index(uc);
1726 const char *hut_str;
1727 const char *sec_name = section_name(section_list_get(csec, i));
1729 if (secfile_lookup_int(file, &uc->min_speed, "%s.min_speed", sec_name)) {
1730 uc->min_speed *= SINGLE_MOVE;
1731 } else {
1732 ruleset_error(LOG_ERROR, "%s", secfile_error());
1733 ok = FALSE;
1734 break;
1736 if (!secfile_lookup_int(file, &uc->hp_loss_pct,
1737 "%s.hp_loss_pct", sec_name)) {
1738 ruleset_error(LOG_ERROR, "%s", secfile_error());
1739 ok = FALSE;
1740 break;
1743 uc->non_native_def_pct = secfile_lookup_int_default(file, 100,
1744 "%s.non_native_def_pct",
1745 sec_name);
1747 hut_str = secfile_lookup_str_default(file, "Normal", "%s.hut_behavior", sec_name);
1748 if (fc_strcasecmp(hut_str, "Normal") == 0) {
1749 uc->hut_behavior = HUT_NORMAL;
1750 } else if (fc_strcasecmp(hut_str, "Nothing") == 0) {
1751 uc->hut_behavior = HUT_NOTHING;
1752 } else if (fc_strcasecmp(hut_str, "Frighten") == 0) {
1753 uc->hut_behavior = HUT_FRIGHTEN;
1754 } else {
1755 ruleset_error(LOG_ERROR,
1756 "\"%s\" unit_class \"%s\":"
1757 " Illegal hut behavior \"%s\".",
1758 filename,
1759 uclass_rule_name(uc),
1760 hut_str);
1761 ok = FALSE;
1762 break;
1765 BV_CLR_ALL(uc->flags);
1766 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name);
1767 for (j = 0; j < nval; j++) {
1768 sval = slist[j];
1769 if (strcmp(sval, "") == 0) {
1770 continue;
1772 ival = unit_class_flag_id_by_name(sval, fc_strcasecmp);
1773 if (!unit_class_flag_id_is_valid(ival)) {
1774 ok = FALSE;
1775 ival = unit_type_flag_id_by_name(rscompat_utype_flag_name_3_1(compat, sval),
1776 fc_strcasecmp);
1777 if (unit_type_flag_id_is_valid(ival)) {
1778 ruleset_error(LOG_ERROR,
1779 "\"%s\" unit_class \"%s\": unit_type flag \"%s\"!",
1780 filename, uclass_rule_name(uc), sval);
1781 } else {
1782 ruleset_error(LOG_ERROR,
1783 "\"%s\" unit_class \"%s\": bad flag name \"%s\".",
1784 filename, uclass_rule_name(uc), sval);
1786 break;
1787 } else {
1788 BV_SET(uc->flags, ival);
1791 free(slist);
1793 uc->helptext = lookup_strvec(file, sec_name, "helptext");
1795 if (!ok) {
1796 break;
1798 } unit_class_iterate_end;
1801 if (ok) {
1802 /* Tech and Gov requirements; per unit veteran system */
1803 unit_type_iterate(u) {
1804 const int i = utype_index(u);
1805 const struct section *psection = section_list_get(sec, i);
1806 const char *sec_name = section_name(psection);
1808 if (!lookup_tech(file, &u->require_advance, sec_name,
1809 "tech_req", filename,
1810 rule_name_get(&u->name))) {
1811 ok = FALSE;
1812 break;
1814 if (NULL != section_entry_by_name(psection, "gov_req")) {
1815 char tmp[200] = "\0";
1816 fc_strlcat(tmp, section_name(psection), sizeof(tmp));
1817 fc_strlcat(tmp, ".gov_req", sizeof(tmp));
1818 u->need_government = lookup_government(file, tmp, filename, NULL);
1819 if (u->need_government == NULL) {
1820 ok = FALSE;
1821 break;
1823 } else {
1824 u->need_government = NULL; /* no requirement */
1827 if (!load_ruleset_veteran(file, sec_name, &u->veteran,
1828 msg, sizeof(msg))) {
1829 ruleset_error(LOG_ERROR, "Error loading the veteran system: %s",
1830 msg);
1831 ok = FALSE;
1832 break;
1835 if (!lookup_unit_type(file, sec_name, "obsolete_by",
1836 &u->obsoleted_by, filename,
1837 rule_name_get(&u->name))
1838 || !lookup_unit_type(file, sec_name, "convert_to",
1839 &u->converted_to, filename,
1840 rule_name_get(&u->name))) {
1841 ok = FALSE;
1842 break;
1844 u->convert_time = 1; /* default */
1845 lookup_time(file, &u->convert_time, sec_name, "convert_time",
1846 filename, rule_name_get(&u->name), &ok);
1847 } unit_type_iterate_end;
1850 if (ok) {
1851 /* main stats: */
1852 unit_type_iterate(u) {
1853 const int i = utype_index(u);
1854 struct unit_class *pclass;
1855 const char *sec_name = section_name(section_list_get(sec, i));
1856 const char *string;
1858 if (!lookup_building(file, sec_name, "impr_req",
1859 &u->need_improvement, filename,
1860 rule_name_get(&u->name))) {
1861 ok = FALSE;
1862 break;
1865 sval = secfile_lookup_str(file, "%s.class", sec_name);
1866 pclass = unit_class_by_rule_name(sval);
1867 if (!pclass) {
1868 ruleset_error(LOG_ERROR,
1869 "\"%s\" unit_type \"%s\":"
1870 " bad class \"%s\".",
1871 filename,
1872 utype_rule_name(u),
1873 sval);
1874 ok = FALSE;
1875 break;
1877 u->uclass = pclass;
1879 sz_strlcpy(u->sound_move,
1880 secfile_lookup_str_default(file, "-", "%s.sound_move",
1881 sec_name));
1882 sz_strlcpy(u->sound_move_alt,
1883 secfile_lookup_str_default(file, "-", "%s.sound_move_alt",
1884 sec_name));
1885 sz_strlcpy(u->sound_fight,
1886 secfile_lookup_str_default(file, "-", "%s.sound_fight",
1887 sec_name));
1888 sz_strlcpy(u->sound_fight_alt,
1889 secfile_lookup_str_default(file, "-", "%s.sound_fight_alt",
1890 sec_name));
1892 if ((string = secfile_lookup_str(file, "%s.graphic", sec_name))) {
1893 sz_strlcpy(u->graphic_str, string);
1894 } else {
1895 ruleset_error(LOG_ERROR, "%s", secfile_error());
1896 ok = FALSE;
1897 break;
1899 sz_strlcpy(u->graphic_alt,
1900 secfile_lookup_str_default(file, "-", "%s.graphic_alt",
1901 sec_name));
1903 if (!secfile_lookup_int(file, &u->build_cost,
1904 "%s.build_cost", sec_name)
1905 || !secfile_lookup_int(file, &u->pop_cost,
1906 "%s.pop_cost", sec_name)
1907 || !secfile_lookup_int(file, &u->attack_strength,
1908 "%s.attack", sec_name)
1909 || !secfile_lookup_int(file, &u->defense_strength,
1910 "%s.defense", sec_name)
1911 || !secfile_lookup_int(file, &u->move_rate,
1912 "%s.move_rate", sec_name)
1913 || !secfile_lookup_int(file, &u->vision_radius_sq,
1914 "%s.vision_radius_sq", sec_name)
1915 || !secfile_lookup_int(file, &u->transport_capacity,
1916 "%s.transport_cap", sec_name)
1917 || !secfile_lookup_int(file, &u->hp,
1918 "%s.hitpoints", sec_name)
1919 || !secfile_lookup_int(file, &u->firepower,
1920 "%s.firepower", sec_name)
1921 || !secfile_lookup_int(file, &u->fuel,
1922 "%s.fuel", sec_name)
1923 || !secfile_lookup_int(file, &u->happy_cost,
1924 "%s.uk_happy", sec_name)) {
1925 ruleset_error(LOG_ERROR, "%s", secfile_error());
1926 ok = FALSE;
1927 break;
1929 u->move_rate *= SINGLE_MOVE;
1931 if (u->firepower <= 0) {
1932 ruleset_error(LOG_ERROR,
1933 "\"%s\" unit_type \"%s\":"
1934 " firepower is %d,"
1935 " but must be at least 1. "
1936 " If you want no attack ability,"
1937 " set the unit's attack strength to 0.",
1938 filename,
1939 utype_rule_name(u),
1940 u->firepower);
1941 ok = FALSE;
1942 break;
1945 lookup_cbonus_list(compat, u->bonuses, file, sec_name, "bonuses");
1947 output_type_iterate(o) {
1948 u->upkeep[o] = secfile_lookup_int_default(file, 0, "%s.uk_%s",
1949 sec_name,
1950 get_output_identifier(o));
1951 } output_type_iterate_end;
1953 slist = secfile_lookup_str_vec(file, &nval, "%s.cargo", sec_name);
1954 BV_CLR_ALL(u->cargo);
1955 for (j = 0; j < nval; j++) {
1956 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
1958 if (!uclass) {
1959 ruleset_error(LOG_ERROR,
1960 "\"%s\" unit_type \"%s\":"
1961 "has unknown unit class %s as cargo.",
1962 filename,
1963 utype_rule_name(u),
1964 slist[j]);
1965 ok = FALSE;
1966 break;
1969 BV_SET(u->cargo, uclass_index(uclass));
1971 free(slist);
1973 if (!ok) {
1974 break;
1977 slist = secfile_lookup_str_vec(file, &nval, "%s.targets", sec_name);
1978 BV_CLR_ALL(u->targets);
1979 for (j = 0; j < nval; j++) {
1980 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
1982 if (!uclass) {
1983 ruleset_error(LOG_ERROR,
1984 "\"%s\" unit_type \"%s\":"
1985 "has unknown unit class %s as target.",
1986 filename,
1987 utype_rule_name(u),
1988 slist[j]);
1989 ok = FALSE;
1990 break;
1993 BV_SET(u->targets, uclass_index(uclass));
1995 free(slist);
1997 if (!ok) {
1998 break;
2001 slist = secfile_lookup_str_vec(file, &nval, "%s.embarks", sec_name);
2002 BV_CLR_ALL(u->embarks);
2003 for (j = 0; j < nval; j++) {
2004 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
2006 if (!uclass) {
2007 ruleset_error(LOG_ERROR,
2008 "\"%s\" unit_type \"%s\":"
2009 "has unknown unit class %s as embarkable.",
2010 filename,
2011 utype_rule_name(u),
2012 slist[j]);
2013 ok = FALSE;
2014 break;
2017 BV_SET(u->embarks, uclass_index(uclass));
2019 free(slist);
2021 if (!ok) {
2022 break;
2025 slist = secfile_lookup_str_vec(file, &nval, "%s.disembarks", sec_name);
2026 BV_CLR_ALL(u->disembarks);
2027 for (j = 0; j < nval; j++) {
2028 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
2030 if (!uclass) {
2031 ruleset_error(LOG_ERROR,
2032 "\"%s\" unit_type \"%s\":"
2033 "has unknown unit class %s as disembarkable.",
2034 filename,
2035 utype_rule_name(u),
2036 slist[j]);
2037 ok = FALSE;
2038 break;
2041 BV_SET(u->disembarks, uclass_index(uclass));
2043 free(slist);
2045 if (!ok) {
2046 break;
2049 /* Set also all classes that are never unreachable as targets,
2050 * embarks, and disembarks. */
2051 unit_class_iterate(preachable) {
2052 if (!uclass_has_flag(preachable, UCF_UNREACHABLE)) {
2053 BV_SET(u->targets, uclass_index(preachable));
2054 BV_SET(u->embarks, uclass_index(preachable));
2055 BV_SET(u->disembarks, uclass_index(preachable));
2057 } unit_class_iterate_end;
2059 u->helptext = lookup_strvec(file, sec_name, "helptext");
2061 u->paratroopers_range = secfile_lookup_int_default(file,
2062 0, "%s.paratroopers_range", sec_name);
2063 u->paratroopers_mr_req = SINGLE_MOVE * secfile_lookup_int_default(file,
2064 0, "%s.paratroopers_mr_req", sec_name);
2065 u->paratroopers_mr_sub = SINGLE_MOVE * secfile_lookup_int_default(file,
2066 0, "%s.paratroopers_mr_sub", sec_name);
2067 u->bombard_rate = secfile_lookup_int_default(file, 0,
2068 "%s.bombard_rate", sec_name);
2069 u->city_slots = secfile_lookup_int_default(file, 0,
2070 "%s.city_slots", sec_name);
2071 u->city_size = secfile_lookup_int_default(file, 1,
2072 "%s.city_size", sec_name);
2073 } unit_type_iterate_end;
2076 if (ok) {
2077 /* flags */
2078 unit_type_iterate(u) {
2079 const int i = utype_index(u);
2081 BV_CLR_ALL(u->flags);
2082 fc_assert(!utype_has_flag(u, UTYF_LAST_USER_FLAG - 1));
2084 slist = secfile_lookup_str_vec(file, &nval, "%s.flags",
2085 section_name(section_list_get(sec, i)));
2086 for (j = 0; j < nval; j++) {
2087 sval = slist[j];
2088 if (0 == strcmp(sval, "")) {
2089 continue;
2091 ival = unit_type_flag_id_by_name(rscompat_utype_flag_name_3_1(compat, sval),
2092 fc_strcasecmp);
2093 if (!unit_type_flag_id_is_valid(ival)) {
2094 ok = FALSE;
2095 ival = unit_class_flag_id_by_name(sval, fc_strcasecmp);
2096 if (unit_class_flag_id_is_valid(ival)) {
2097 ruleset_error(LOG_ERROR, "\"%s\" unit_type \"%s\": unit_class flag!",
2098 filename, utype_rule_name(u));
2099 } else {
2100 ruleset_error(LOG_ERROR,
2101 "\"%s\" unit_type \"%s\": bad flag name \"%s\".",
2102 filename, utype_rule_name(u), sval);
2104 break;
2105 } else {
2106 BV_SET(u->flags, ival);
2108 fc_assert(utype_has_flag(u, ival));
2110 free(slist);
2112 if (!ok) {
2113 break;
2115 } unit_type_iterate_end;
2118 /* roles */
2119 if (ok) {
2120 unit_type_iterate(u) {
2121 const int i = utype_index(u);
2123 BV_CLR_ALL(u->roles);
2125 slist = secfile_lookup_str_vec(file, &nval, "%s.roles",
2126 section_name(section_list_get(sec, i)));
2127 for (j = 0; j < nval; j++) {
2128 sval = slist[j];
2129 if (strcmp(sval, "") == 0) {
2130 continue;
2132 ival = unit_role_id_by_name(sval, fc_strcasecmp);
2133 if (!unit_role_id_is_valid(ival)) {
2134 ruleset_error(LOG_ERROR, "\"%s\" unit_type \"%s\": bad role name \"%s\".",
2135 filename, utype_rule_name(u), sval);
2136 ok = FALSE;
2137 break;
2138 } else {
2139 BV_SET(u->roles, ival - L_FIRST);
2141 fc_assert(utype_has_role(u, ival));
2143 free(slist);
2144 } unit_type_iterate_end;
2147 if (ok) {
2148 /* Some more consistency checking: */
2149 unit_type_iterate(u) {
2150 if (!valid_advance(u->require_advance)) {
2151 ruleset_error(LOG_ERROR, "\"%s\" unit_type \"%s\": depends on removed tech \"%s\".",
2152 filename, utype_rule_name(u),
2153 advance_rule_name(u->require_advance));
2154 u->require_advance = A_NEVER;
2155 ok = FALSE;
2156 break;
2159 if (utype_has_flag(u, UTYF_SETTLERS)
2160 && u->city_size <= 0) {
2161 ruleset_error(LOG_ERROR, "\"%s\": Unit %s would build size %d cities",
2162 filename, utype_rule_name(u), u->city_size);
2163 u->city_size = 1;
2164 ok = FALSE;
2165 break;
2167 } unit_type_iterate_end;
2170 section_list_destroy(csec);
2171 section_list_destroy(sec);
2173 if (ok) {
2174 secfile_check_unused(file);
2177 return ok;
2180 /**************************************************************************
2181 Load names of buildings so other rulesets can refer to buildings with
2182 their name.
2183 **************************************************************************/
2184 static bool load_building_names(struct section_file *file,
2185 struct rscompat_info *compat)
2187 struct section_list *sec;
2188 int i, nval = 0;
2189 const char *filename = secfile_name(file);
2190 bool ok = TRUE;
2192 compat->ver_buildings = rscompat_check_capabilities(file, filename,
2193 compat);
2194 if (compat->ver_buildings <= 0) {
2195 return FALSE;
2198 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
2199 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
2201 /* The names: */
2202 sec = secfile_sections_by_name_prefix(file, BUILDING_SECTION_PREFIX);
2203 if (NULL == sec || 0 == (nval = section_list_size(sec))) {
2204 ruleset_error(LOG_ERROR, "\"%s\": No improvements?!?", filename);
2205 ok = FALSE;
2206 } else {
2207 log_verbose("%d improvement types (including possibly unused)", nval);
2208 if (nval > B_LAST) {
2209 ruleset_error(LOG_ERROR, "\"%s\": Too many improvements (%d, max %d)",
2210 filename, nval, B_LAST);
2211 ok = FALSE;
2215 if (ok) {
2216 game.control.num_impr_types = nval;
2218 for (i = 0; i < nval; i++) {
2219 struct impr_type *b = improvement_by_number(i);
2221 if (!ruleset_load_names(&b->name, NULL, file, section_name(section_list_get(sec, i)))) {
2222 ok = FALSE;
2223 break;
2228 section_list_destroy(sec);
2230 return ok;
2233 /**************************************************************************
2234 Load buildings related ruleset data
2235 **************************************************************************/
2236 static bool load_ruleset_buildings(struct section_file *file,
2237 struct rscompat_info *compat)
2239 struct section_list *sec;
2240 const char *item;
2241 int i, nval;
2242 const char *filename = secfile_name(file);
2243 bool ok = TRUE;
2245 sec = secfile_sections_by_name_prefix(file, BUILDING_SECTION_PREFIX);
2246 nval = (NULL != sec ? section_list_size(sec) : 0);
2248 for (i = 0; i < nval && ok; i++) {
2249 struct impr_type *b = improvement_by_number(i);
2250 const char *sec_name = section_name(section_list_get(sec, i));
2251 struct requirement_vector *reqs =
2252 lookup_req_list(file, compat, sec_name, "reqs",
2253 improvement_rule_name(b));
2255 if (reqs == NULL) {
2256 ok = FALSE;
2257 break;
2258 } else {
2259 const char *sval, **slist;
2260 int j, ival;
2261 size_t nflags;
2263 item = secfile_lookup_str(file, "%s.genus", sec_name);
2264 b->genus = impr_genus_id_by_name(item, fc_strcasecmp);
2265 if (!impr_genus_id_is_valid(b->genus)) {
2266 ruleset_error(LOG_ERROR, "\"%s\" improvement \"%s\": couldn't match "
2267 "genus \"%s\".", filename,
2268 improvement_rule_name(b), item);
2269 ok = FALSE;
2270 break;
2273 slist = secfile_lookup_str_vec(file, &nflags, "%s.flags", sec_name);
2274 BV_CLR_ALL(b->flags);
2276 for (j = 0; j < nflags; j++) {
2277 sval = slist[j];
2278 if (strcmp(sval,"") == 0) {
2279 continue;
2281 ival = impr_flag_id_by_name(sval, fc_strcasecmp);
2282 if (!impr_flag_id_is_valid(ival)) {
2283 ruleset_error(LOG_ERROR,
2284 "\"%s\" improvement \"%s\": bad flag name \"%s\".",
2285 filename, improvement_rule_name(b), sval);
2286 ok = FALSE;
2287 break;
2288 } else {
2289 BV_SET(b->flags, ival);
2292 free(slist);
2294 if (!ok) {
2295 break;
2298 requirement_vector_copy(&b->reqs, reqs);
2301 struct requirement_vector *obs_reqs =
2302 lookup_req_list(file, compat, sec_name, "obsolete_by",
2303 improvement_rule_name(b));
2305 if (obs_reqs == NULL) {
2306 ok = FALSE;
2307 break;
2308 } else {
2309 requirement_vector_copy(&b->obsolete_by, obs_reqs);
2313 if (!secfile_lookup_int(file, &b->build_cost,
2314 "%s.build_cost", sec_name)
2315 || !secfile_lookup_int(file, &b->upkeep,
2316 "%s.upkeep", sec_name)
2317 || !secfile_lookup_int(file, &b->sabotage,
2318 "%s.sabotage", sec_name)) {
2319 ruleset_error(LOG_ERROR, "%s", secfile_error());
2320 ok = FALSE;
2321 break;
2324 sz_strlcpy(b->graphic_str,
2325 secfile_lookup_str_default(file, "-",
2326 "%s.graphic", sec_name));
2327 sz_strlcpy(b->graphic_alt,
2328 secfile_lookup_str_default(file, "-",
2329 "%s.graphic_alt", sec_name));
2331 sz_strlcpy(b->soundtag,
2332 secfile_lookup_str_default(file, "-",
2333 "%s.sound", sec_name));
2334 sz_strlcpy(b->soundtag_alt,
2335 secfile_lookup_str_default(file, "-",
2336 "%s.sound_alt", sec_name));
2337 b->helptext = lookup_strvec(file, sec_name, "helptext");
2341 section_list_destroy(sec);
2342 if (ok) {
2343 secfile_check_unused(file);
2346 return ok;
2349 /**************************************************************************
2350 Load names of terrain types so other rulesets can refer to terrains with
2351 their name.
2352 **************************************************************************/
2353 static bool load_terrain_names(struct section_file *file,
2354 struct rscompat_info *compat)
2356 int nval = 0;
2357 struct section_list *sec = NULL;
2358 const char *flag;
2359 int i;
2360 const char *filename = secfile_name(file);
2361 bool ok = TRUE;
2363 compat->ver_terrain = rscompat_check_capabilities(file, filename,
2364 compat);
2365 if (compat->ver_terrain <= 0) {
2366 return FALSE;
2369 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
2370 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
2372 /* User terrain flag names */
2373 for (i = 0; (flag = secfile_lookup_str_default(file, NULL, "control.flags%d.name", i)) ;
2374 i++) {
2375 const char *helptxt = secfile_lookup_str_default(file, NULL, "control.flags%d.helptxt",
2378 if (terrain_flag_id_by_name(flag, fc_strcasecmp)
2379 != terrain_flag_id_invalid()) {
2380 ruleset_error(LOG_ERROR, "\"%s\": Duplicate terrain flag name '%s'",
2381 filename, flag);
2382 ok = FALSE;
2383 break;
2385 if (i > MAX_NUM_USER_TER_FLAGS) {
2386 ruleset_error(LOG_ERROR, "\"%s\": Too many user terrain flags!",
2387 filename);
2388 ok = FALSE;
2389 break;
2392 set_user_terrain_flag_name(TER_USER_1 + i, flag, helptxt);
2395 if (ok) {
2396 /* Blank the remaining terrain user flag slots. */
2397 for (; i < MAX_NUM_USER_TER_FLAGS; i++) {
2398 set_user_terrain_flag_name(TER_USER_1 + i, NULL, NULL);
2402 /* User extra flag names */
2403 for (i = 0;
2404 (flag = secfile_lookup_str_default(file, NULL,
2405 "control.extra_flags%d.name",
2406 i));
2407 i++) {
2408 const char *helptxt = secfile_lookup_str_default(file, NULL,
2409 "control.extra_flags%d.helptxt", i);
2411 if (extra_flag_id_by_name(flag, fc_strcasecmp)
2412 != extra_flag_id_invalid()) {
2413 ruleset_error(LOG_ERROR, "\"%s\": Duplicate extra flag name '%s'",
2414 filename, flag);
2415 ok = FALSE;
2416 break;
2418 if (i > MAX_NUM_USER_EXTRA_FLAGS) {
2419 ruleset_error(LOG_ERROR, "\"%s\": Too many user extra flags!",
2420 filename);
2421 ok = FALSE;
2422 break;
2425 set_user_extra_flag_name(EF_USER_FLAG_1 + i, flag, helptxt);
2428 if (ok) {
2429 /* Blank the remaining extra user flag slots. */
2430 for (; i < MAX_NUM_USER_EXTRA_FLAGS; i++) {
2431 set_user_extra_flag_name(EF_USER_FLAG_1 + i, NULL, NULL);
2434 /* terrain names */
2436 sec = secfile_sections_by_name_prefix(file, TERRAIN_SECTION_PREFIX);
2437 if (NULL == sec || 0 == (nval = section_list_size(sec))) {
2438 ruleset_error(LOG_ERROR, "\"%s\": ruleset doesn't have any terrains.",
2439 filename);
2440 ok = FALSE;
2441 } else {
2442 if (nval > MAX_NUM_TERRAINS) {
2443 ruleset_error(LOG_ERROR, "\"%s\": Too many terrains (%d, max %d)",
2444 filename, nval, MAX_NUM_TERRAINS);
2445 ok = FALSE;
2450 if (ok) {
2451 game.control.terrain_count = nval;
2453 /* avoid re-reading files */
2454 if (terrain_sections) {
2455 free(terrain_sections);
2457 terrain_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2459 terrain_type_iterate(pterrain) {
2460 const int terri = terrain_index(pterrain);
2461 const char *sec_name = section_name(section_list_get(sec, terri));
2463 if (!ruleset_load_names(&pterrain->name, NULL, file, sec_name)) {
2464 ok = FALSE;
2465 break;
2468 if (0 == strcmp(rule_name_get(&pterrain->name), "unused")) {
2469 name_set(&pterrain->name, NULL, "");
2472 section_strlcpy(&terrain_sections[terri * MAX_SECTION_LABEL], sec_name);
2473 } terrain_type_iterate_end;
2476 section_list_destroy(sec);
2477 sec = NULL;
2479 /* extra names */
2481 if (ok) {
2482 sec = secfile_sections_by_name_prefix(file, EXTRA_SECTION_PREFIX);
2483 nval = (NULL != sec ? section_list_size(sec) : 0);
2484 if (nval > MAX_EXTRA_TYPES) {
2485 ruleset_error(LOG_ERROR, "\"%s\": Too many extra types (%d, max %d)",
2486 filename, nval, MAX_EXTRA_TYPES);
2487 ok = FALSE;
2491 if (ok) {
2492 int idx;
2494 game.control.num_extra_types = nval;
2496 if (extra_sections) {
2497 free(extra_sections);
2499 extra_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2501 if (ok) {
2502 for (idx = 0; idx < nval; idx++) {
2503 const char *sec_name = section_name(section_list_get(sec, idx));
2504 struct extra_type *pextra = extra_by_number(idx);
2506 if (!ruleset_load_names(&pextra->name, NULL, file, sec_name)) {
2507 ok = FALSE;
2508 break;
2510 section_strlcpy(&extra_sections[idx * MAX_SECTION_LABEL], sec_name);
2515 section_list_destroy(sec);
2516 sec = NULL;
2518 /* base names */
2520 if (ok) {
2521 sec = secfile_sections_by_name_prefix(file, BASE_SECTION_PREFIX);
2522 nval = (NULL != sec ? section_list_size(sec) : 0);
2523 if (nval > MAX_BASE_TYPES) {
2524 ruleset_error(LOG_ERROR, "\"%s\": Too many base types (%d, max %d)",
2525 filename, nval, MAX_BASE_TYPES);
2526 ok = FALSE;
2529 game.control.num_base_types = nval;
2532 if (ok) {
2533 int idx;
2535 if (base_sections) {
2536 free(base_sections);
2538 base_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2540 /* Cannot use base_type_iterate() before bases are added to
2541 * EC_BASE caused_by list. Have to get them by extra_type_by_rule_name() */
2542 for (idx = 0; idx < nval; idx++) {
2543 const char *sec_name = section_name(section_list_get(sec, idx));
2544 const char *base_name = secfile_lookup_str(file, "%s.extra", sec_name);
2546 if (base_name != NULL) {
2547 struct extra_type *pextra = extra_type_by_rule_name(base_name);
2549 if (pextra != NULL) {
2550 base_type_init(pextra, idx);
2551 section_strlcpy(&base_sections[idx * MAX_SECTION_LABEL], sec_name);
2552 } else {
2553 ruleset_error(LOG_ERROR,
2554 "No extra definition matching base definition \"%s\"",
2555 base_name);
2556 ok = FALSE;
2558 } else {
2559 ruleset_error(LOG_ERROR,
2560 "Base section \"%s\" does not associate base with any extra",
2561 sec_name);
2562 ok = FALSE;
2567 section_list_destroy(sec);
2568 sec = NULL;
2570 /* road names */
2572 if (ok) {
2573 sec = secfile_sections_by_name_prefix(file, ROAD_SECTION_PREFIX);
2574 nval = (NULL != sec ? section_list_size(sec) : 0);
2575 if (nval > MAX_ROAD_TYPES) {
2576 ruleset_error(LOG_ERROR, "\"%s\": Too many road types (%d, max %d)",
2577 filename, nval, MAX_ROAD_TYPES);
2578 ok = FALSE;
2581 game.control.num_road_types = nval;
2584 if (ok) {
2585 int idx;
2587 if (road_sections) {
2588 free(road_sections);
2590 road_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2592 /* Cannot use extra_type_by_cause_iterate(EC_ROAD) before roads are added to
2593 * EC_ROAD caused_by list. Have to get them by extra_type_by_rule_name() */
2594 for (idx = 0; idx < nval; idx++) {
2595 const char *sec_name = section_name(section_list_get(sec, idx));
2596 const char *road_name = secfile_lookup_str(file, "%s.extra", sec_name);
2598 if (road_name != NULL) {
2599 struct extra_type *pextra = extra_type_by_rule_name(road_name);
2601 if (pextra != NULL) {
2602 road_type_init(pextra, idx);
2603 section_strlcpy(&road_sections[idx * MAX_SECTION_LABEL], sec_name);
2604 } else {
2605 ruleset_error(LOG_ERROR,
2606 "No extra definition matching road definition \"%s\"",
2607 road_name);
2608 ok = FALSE;
2610 } else {
2611 ruleset_error(LOG_ERROR,
2612 "Road section \"%s\" does not associate road with any extra",
2613 sec_name);
2614 ok = FALSE;
2619 section_list_destroy(sec);
2620 sec = NULL;
2622 /* resource names */
2624 if (ok) {
2625 sec = secfile_sections_by_name_prefix(file, RESOURCE_SECTION_PREFIX);
2626 nval = (NULL != sec ? section_list_size(sec) : 0);
2627 if (nval > MAX_RESOURCE_TYPES) {
2628 ruleset_error(LOG_ERROR, "\"%s\": Too many resource types (%d, max %d)",
2629 filename, nval, MAX_RESOURCE_TYPES);
2630 ok = FALSE;
2633 game.control.num_resource_types = nval;
2636 if (ok) {
2637 int idx;
2639 if (resource_sections) {
2640 free(resource_sections);
2642 resource_sections = fc_calloc(nval, MAX_SECTION_LABEL);
2644 /* Cannot use resource_type_iterate() before resource are added to
2645 * EC_RESOURCE caused_by list. Have to get them by extra_type_by_rule_name() */
2646 for (idx = 0; idx < nval; idx++) {
2647 const char *sec_name = section_name(section_list_get(sec, idx));
2648 const char *resource_name;
2649 struct extra_type *pextra = NULL;
2651 resource_name = secfile_lookup_str_default(file, NULL, "%s.extra", sec_name);
2653 if (resource_name != NULL) {
2654 pextra = extra_type_by_rule_name(resource_name);
2656 if (pextra != NULL) {
2657 resource_type_init(pextra);
2658 section_strlcpy(&resource_sections[idx * MAX_SECTION_LABEL], sec_name);
2659 } else {
2660 ruleset_error(LOG_ERROR,
2661 "No extra definition matching resource definition \"%s\"",
2662 resource_name);
2663 ok = FALSE;
2665 } else {
2666 ruleset_error(LOG_ERROR,
2667 "Resource section %s does not list extra this resource belongs to.",
2668 sec_name);
2669 ok = FALSE;
2674 section_list_destroy(sec);
2676 return ok;
2679 /**************************************************************************
2680 Load terrain types related ruleset data
2681 **************************************************************************/
2682 static bool load_ruleset_terrain(struct section_file *file,
2683 struct rscompat_info *compat)
2685 size_t nval;
2686 int j;
2687 bool compat_road = FALSE;
2688 bool compat_rail = FALSE;
2689 bool compat_river = FALSE;
2690 const char **res;
2691 const char *filename = secfile_name(file);
2692 const char *text;
2693 bool ok = TRUE;
2695 /* parameters */
2697 terrain_control.ocean_reclaim_requirement_pct
2698 = secfile_lookup_int_default(file, 101,
2699 "parameters.ocean_reclaim_requirement");
2700 terrain_control.land_channel_requirement_pct
2701 = secfile_lookup_int_default(file, 101,
2702 "parameters.land_channel_requirement");
2703 terrain_control.terrain_thaw_requirement_pct
2704 = secfile_lookup_int_default(file, 101,
2705 "parameters.thaw_requirement");
2706 terrain_control.terrain_freeze_requirement_pct
2707 = secfile_lookup_int_default(file, 101,
2708 "parameters.freeze_requirement");
2709 terrain_control.lake_max_size
2710 = secfile_lookup_int_default(file, 0,
2711 "parameters.lake_max_size");
2712 terrain_control.min_start_native_area
2713 = secfile_lookup_int_default(file, 0,
2714 "parameters.min_start_native_area");
2715 terrain_control.move_fragments
2716 = secfile_lookup_int_default(file, 3,
2717 "parameters.move_fragments");
2718 if (terrain_control.move_fragments < 1) {
2719 ruleset_error(LOG_ERROR, "\"%s\": move_fragments must be at least 1",
2720 filename);
2721 ok = FALSE;
2723 init_move_fragments();
2724 terrain_control.igter_cost
2725 = secfile_lookup_int_default(file, 1,
2726 "parameters.igter_cost");
2727 if (terrain_control.igter_cost < 1) {
2728 ruleset_error(LOG_ERROR, "\"%s\": igter_cost must be at least 1",
2729 filename);
2730 ok = FALSE;
2732 terrain_control.pythagorean_diagonal
2733 = secfile_lookup_bool_default(file, RS_DEFAULT_PYTHAGOREAN_DIAGONAL,
2734 "parameters.pythagorean_diagonal");
2736 wld.map.server.ocean_resources
2737 = secfile_lookup_bool_default(file, FALSE,
2738 "parameters.ocean_resources");
2740 text = secfile_lookup_str_default(file,
2741 N_("?gui_type:Build Type A Base"),
2742 "extraui.ui_name_base_fortress");
2743 sz_strlcpy(terrain_control.gui_type_base0, text);
2745 text = secfile_lookup_str_default(file,
2746 N_("?gui_type:Build Type B Base"),
2747 "extraui.ui_name_base_airbase");
2748 sz_strlcpy(terrain_control.gui_type_base1, text);
2750 if (ok) {
2751 /* terrain details */
2753 terrain_type_iterate(pterrain) {
2754 const char **slist;
2755 const int i = terrain_index(pterrain);
2756 const char *tsection = &terrain_sections[i * MAX_SECTION_LABEL];
2757 const char *cstr;
2759 sz_strlcpy(pterrain->graphic_str,
2760 secfile_lookup_str(file,"%s.graphic", tsection));
2761 sz_strlcpy(pterrain->graphic_alt,
2762 secfile_lookup_str(file,"%s.graphic_alt", tsection));
2764 pterrain->identifier
2765 = secfile_lookup_str(file, "%s.identifier", tsection)[0];
2766 if ('\0' == pterrain->identifier) {
2767 ruleset_error(LOG_ERROR, "\"%s\" [%s] identifier missing value.",
2768 filename, tsection);
2769 ok = FALSE;
2770 break;
2772 if (TERRAIN_UNKNOWN_IDENTIFIER == pterrain->identifier) {
2773 ruleset_error(LOG_ERROR,
2774 "\"%s\" [%s] cannot use '%c' as an identifier;"
2775 " it is reserved for unknown terrain.",
2776 filename, tsection, pterrain->identifier);
2777 ok = FALSE;
2778 break;
2780 for (j = T_FIRST; j < i; j++) {
2781 if (pterrain->identifier == terrain_by_number(j)->identifier) {
2782 ruleset_error(LOG_ERROR,
2783 "\"%s\" [%s] has the same identifier as [%s].",
2784 filename,
2785 tsection,
2786 &terrain_sections[j * MAX_SECTION_LABEL]);
2787 ok = FALSE;
2788 break;
2792 if (!ok) {
2793 break;
2796 cstr = secfile_lookup_str(file, "%s.class", tsection);
2797 pterrain->tclass = terrain_class_by_name(cstr, fc_strcasecmp);
2798 if (!terrain_class_is_valid(pterrain->tclass)) {
2799 ruleset_error(LOG_ERROR, "\"%s\": [%s] unknown class \"%s\"",
2800 filename, tsection, cstr);
2801 ok = FALSE;
2802 break;
2805 if (!secfile_lookup_int(file, &pterrain->movement_cost,
2806 "%s.movement_cost", tsection)
2807 || !secfile_lookup_int(file, &pterrain->defense_bonus,
2808 "%s.defense_bonus", tsection)) {
2809 ruleset_error(LOG_ERROR, "%s", secfile_error());
2810 ok = FALSE;
2811 break;
2814 output_type_iterate(o) {
2815 pterrain->output[o]
2816 = secfile_lookup_int_default(file, 0, "%s.%s", tsection,
2817 get_output_identifier(o));
2818 } output_type_iterate_end;
2820 res = secfile_lookup_str_vec(file, &nval, "%s.resources", tsection);
2821 pterrain->resources = fc_calloc(nval + 1, sizeof(*pterrain->resources));
2822 for (j = 0; j < nval; j++) {
2823 pterrain->resources[j] = lookup_resource(filename, res[j], tsection);
2824 if (pterrain->resources[j] == NULL) {
2825 ok = FALSE;
2826 break;
2829 pterrain->resources[nval] = NULL;
2830 free(res);
2831 res = NULL;
2833 if (!ok) {
2834 break;
2837 output_type_iterate(o) {
2838 pterrain->road_output_incr_pct[o]
2839 = secfile_lookup_int_default(file, 0, "%s.road_%s_incr_pct",
2840 tsection, get_output_identifier(o));
2841 } output_type_iterate_end;
2843 if (!lookup_time(file, &pterrain->base_time, tsection, "base_time",
2844 filename, NULL, &ok)
2845 || !lookup_time(file, &pterrain->road_time, tsection, "road_time",
2846 filename, NULL, &ok)) {
2847 ruleset_error(LOG_ERROR, "%s", secfile_error());
2848 ok = FALSE;
2849 break;
2852 if (!lookup_terrain(file, "irrigation_result", filename, pterrain,
2853 &pterrain->irrigation_result)) {
2854 ok = FALSE;
2855 break;
2857 if (!secfile_lookup_int(file, &pterrain->irrigation_food_incr,
2858 "%s.irrigation_food_incr", tsection)
2859 || !lookup_time(file, &pterrain->irrigation_time,
2860 tsection, "irrigation_time", filename, NULL, &ok)) {
2861 ruleset_error(LOG_ERROR, "%s", secfile_error());
2862 ok = FALSE;
2863 break;
2866 if (!lookup_terrain(file, "mining_result", filename, pterrain,
2867 &pterrain->mining_result)) {
2868 ok = FALSE;
2869 break;
2871 if (!secfile_lookup_int(file, &pterrain->mining_shield_incr,
2872 "%s.mining_shield_incr", tsection)
2873 || !lookup_time(file, &pterrain->mining_time,
2874 tsection, "mining_time", filename, NULL, &ok)) {
2875 ruleset_error(LOG_ERROR, "%s", secfile_error());
2876 ok = FALSE;
2877 break;
2880 if (!lookup_unit_type(file, tsection, "animal",
2881 &pterrain->animal, filename,
2882 rule_name_get(&pterrain->name))) {
2883 ok = FALSE;
2884 break;
2887 if (!lookup_terrain(file, "transform_result", filename, pterrain,
2888 &pterrain->transform_result)) {
2889 ok = FALSE;
2890 break;
2892 if (!lookup_time(file, &pterrain->transform_time,
2893 tsection, "transform_time", filename, NULL, &ok)) {
2894 ruleset_error(LOG_ERROR, "%s", secfile_error());
2895 ok = FALSE;
2896 break;
2898 pterrain->pillage_time = 1; /* default */
2899 lookup_time(file, &pterrain->pillage_time,
2900 tsection, "pillage_time", filename, NULL, &ok);
2901 pterrain->clean_pollution_time = 3; /* default */
2902 lookup_time(file, &pterrain->clean_pollution_time,
2903 tsection, "clean_pollution_time", filename, NULL, &ok);
2904 pterrain->clean_fallout_time = 3; /* default */
2905 lookup_time(file, &pterrain->clean_fallout_time,
2906 tsection, "clean_fallout_time", filename, NULL, &ok);
2908 if (!lookup_terrain(file, "warmer_wetter_result", filename, pterrain,
2909 &pterrain->warmer_wetter_result)
2910 || !lookup_terrain(file, "warmer_drier_result", filename, pterrain,
2911 &pterrain->warmer_drier_result)
2912 || !lookup_terrain(file, "cooler_wetter_result", filename, pterrain,
2913 &pterrain->cooler_wetter_result)
2914 || !lookup_terrain(file, "cooler_drier_result", filename, pterrain,
2915 &pterrain->cooler_drier_result)) {
2916 ok = FALSE;
2917 break;
2920 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", tsection);
2921 BV_CLR_ALL(pterrain->flags);
2922 for (j = 0; j < nval; j++) {
2923 const char *sval = slist[j];
2924 enum terrain_flag_id flag
2925 = terrain_flag_id_by_name(sval, fc_strcasecmp);
2927 if (!terrain_flag_id_is_valid(flag)) {
2928 ruleset_error(LOG_ERROR, "\"%s\" [%s] has unknown flag \"%s\".",
2929 filename, tsection, sval);
2930 ok = FALSE;
2931 break;
2932 } else {
2933 BV_SET(pterrain->flags, flag);
2936 free(slist);
2938 if (!ok) {
2939 break;
2943 enum mapgen_terrain_property mtp;
2944 for (mtp = mapgen_terrain_property_begin();
2945 mtp != mapgen_terrain_property_end();
2946 mtp = mapgen_terrain_property_next(mtp)) {
2947 pterrain->property[mtp]
2948 = secfile_lookup_int_default(file, 0, "%s.property_%s", tsection,
2949 mapgen_terrain_property_name(mtp));
2953 slist = secfile_lookup_str_vec(file, &nval, "%s.native_to", tsection);
2954 BV_CLR_ALL(pterrain->native_to);
2955 for (j = 0; j < nval; j++) {
2956 struct unit_class *class = unit_class_by_rule_name(slist[j]);
2958 if (!class) {
2959 ruleset_error(LOG_ERROR,
2960 "\"%s\" [%s] is native to unknown unit class \"%s\".",
2961 filename, tsection, slist[j]);
2962 ok = FALSE;
2963 break;
2964 } else {
2965 BV_SET(pterrain->native_to, uclass_index(class));
2968 free(slist);
2970 if (!ok) {
2971 break;
2974 /* get terrain color */
2976 fc_assert_ret_val(pterrain->rgb == NULL, FALSE);
2977 if (!rgbcolor_load(file, &pterrain->rgb, "%s.color", tsection)) {
2978 ruleset_error(LOG_ERROR, "Missing terrain color definition: %s",
2979 secfile_error());
2980 ok = FALSE;
2981 break;
2985 pterrain->helptext = lookup_strvec(file, tsection, "helptext");
2986 } terrain_type_iterate_end;
2989 if (ok) {
2990 /* extra details */
2991 extra_type_iterate(pextra) {
2992 BV_CLR_ALL(pextra->conflicts);
2993 } extra_type_iterate_end;
2995 extra_type_iterate(pextra) {
2996 if (!compat->compat_mode || compat->ver_terrain >= 10 || pextra->category != ECAT_RESOURCE) {
2997 const char *section = &extra_sections[extra_index(pextra) * MAX_SECTION_LABEL];
2998 const char **slist;
2999 struct requirement_vector *reqs;
3000 const char *catname;
3001 int cj;
3002 enum extra_cause cause;
3003 enum extra_rmcause rmcause;
3004 const char *eus_name;
3005 const char *vis_req_name;
3006 const struct advance *vis_req;
3008 catname = secfile_lookup_str(file, "%s.category", section);
3009 if (catname == NULL) {
3010 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\" has no category.",
3011 filename,
3012 extra_rule_name(pextra));
3013 ok = FALSE;
3014 break;
3016 pextra->category = extra_category_by_name(catname, fc_strcasecmp);
3017 if (!extra_category_is_valid(pextra->category)) {
3018 ruleset_error(LOG_ERROR,
3019 "\"%s\" extra \"%s\" has invalid category \"%s\".",
3020 filename, extra_rule_name(pextra), catname);
3021 ok = FALSE;
3022 break;
3025 slist = secfile_lookup_str_vec(file, &nval, "%s.causes", section);
3026 pextra->causes = 0;
3027 for (cj = 0; cj < nval; cj++) {
3028 const char *sval = slist[cj];
3029 cause = extra_cause_by_name(sval, fc_strcasecmp);
3031 if (!extra_cause_is_valid(cause)) {
3032 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\": unknown cause \"%s\".",
3033 filename,
3034 extra_rule_name(pextra),
3035 sval);
3036 ok = FALSE;
3037 break;
3038 } else {
3039 pextra->causes |= (1 << cause);
3040 extra_to_caused_by_list(pextra, cause);
3044 extra_to_category_list(pextra, pextra->category);
3046 if (pextra->causes == 0) {
3047 /* Extras that do not have any causes added to EC_NONE list */
3048 extra_to_caused_by_list(pextra, EC_NONE);
3051 if (!is_extra_caused_by(pextra, EC_BASE)
3052 && !is_extra_caused_by(pextra, EC_ROAD)
3053 && !is_extra_caused_by(pextra, EC_RESOURCE)) {
3054 /* Not a base, road, nor resource, so special */
3055 pextra->data.special_idx = extra_type_list_size(extra_type_list_by_cause(EC_SPECIAL));
3056 extra_to_caused_by_list(pextra, EC_SPECIAL);
3059 free(slist);
3061 slist = secfile_lookup_str_vec(file, &nval, "%s.rmcauses", section);
3062 pextra->rmcauses = 0;
3063 for (j = 0; j < nval; j++) {
3064 const char *sval = slist[j];
3065 rmcause = extra_rmcause_by_name(sval, fc_strcasecmp);
3067 if (!extra_rmcause_is_valid(rmcause)) {
3068 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\": unknown rmcause \"%s\".",
3069 filename,
3070 extra_rule_name(pextra),
3071 sval);
3072 ok = FALSE;
3073 break;
3074 } else {
3075 pextra->rmcauses |= (1 << rmcause);
3076 extra_to_removed_by_list(pextra, rmcause);
3080 free(slist);
3082 sz_strlcpy(pextra->activity_gfx,
3083 secfile_lookup_str_default(file, "-",
3084 "%s.activity_gfx", section));
3085 sz_strlcpy(pextra->act_gfx_alt,
3086 secfile_lookup_str_default(file, "-",
3087 "%s.act_gfx_alt", section));
3088 sz_strlcpy(pextra->act_gfx_alt2,
3089 secfile_lookup_str_default(file, "-",
3090 "%s.act_gfx_alt2", section));
3091 sz_strlcpy(pextra->rmact_gfx,
3092 secfile_lookup_str_default(file, "-",
3093 "%s.rmact_gfx", section));
3094 sz_strlcpy(pextra->rmact_gfx_alt,
3095 secfile_lookup_str_default(file, "-",
3096 "%s.rmact_gfx_alt", section));
3097 sz_strlcpy(pextra->graphic_str,
3098 secfile_lookup_str_default(file, "-", "%s.graphic", section));
3099 sz_strlcpy(pextra->graphic_alt,
3100 secfile_lookup_str_default(file, "-",
3101 "%s.graphic_alt", section));
3103 reqs = lookup_req_list(file, compat, section, "reqs", extra_rule_name(pextra));
3104 if (reqs == NULL) {
3105 ok = FALSE;
3106 break;
3108 requirement_vector_copy(&pextra->reqs, reqs);
3110 reqs = lookup_req_list(file, compat, section, "rmreqs", extra_rule_name(pextra));
3111 if (reqs == NULL) {
3112 ok = FALSE;
3113 break;
3115 requirement_vector_copy(&pextra->rmreqs, reqs);
3117 reqs = lookup_req_list(file, compat, section, "appearance_reqs", extra_rule_name(pextra));
3118 if (reqs == NULL) {
3119 ok = FALSE;
3120 break;
3122 requirement_vector_copy(&pextra->appearance_reqs, reqs);
3124 reqs = lookup_req_list(file, compat, section, "disappearance_reqs", extra_rule_name(pextra));
3125 if (reqs == NULL) {
3126 ok = FALSE;
3127 break;
3129 requirement_vector_copy(&pextra->disappearance_reqs, reqs);
3131 pextra->buildable = secfile_lookup_bool_default(file,
3132 is_extra_caused_by_worker_action(pextra),
3133 "%s.buildable", section);
3135 pextra->build_time = 0; /* default */
3136 lookup_time(file, &pextra->build_time, section, "build_time",
3137 filename, extra_rule_name(pextra), &ok);
3138 pextra->build_time_factor = secfile_lookup_int_default(file, 1,
3139 "%s.build_time_factor", section);
3140 pextra->removal_time = 0; /* default */
3141 lookup_time(file, &pextra->removal_time, section, "removal_time",
3142 filename, extra_rule_name(pextra), &ok);
3143 pextra->removal_time_factor = secfile_lookup_int_default(file, 1,
3144 "%s.removal_time_factor", section);
3146 pextra->defense_bonus = secfile_lookup_int_default(file, 0,
3147 "%s.defense_bonus",
3148 section);
3149 if (pextra->defense_bonus != 0) {
3150 if (extra_has_flag(pextra, EF_NATURAL_DEFENSE)) {
3151 extra_to_caused_by_list(pextra, EC_NATURAL_DEFENSIVE);
3152 } else {
3153 extra_to_caused_by_list(pextra, EC_DEFENSIVE);
3157 eus_name = secfile_lookup_str_default(file, "Normal", "%s.unit_seen", section);
3158 pextra->eus = extra_unit_seen_type_by_name(eus_name, fc_strcasecmp);
3159 if (!extra_unit_seen_type_is_valid(pextra->eus)) {
3160 ruleset_error(LOG_ERROR,
3161 "\"%s\" extra \"%s\" has illegal unit_seen value \"%s\".",
3162 filename, extra_rule_name(pextra),
3163 eus_name);
3164 ok = FALSE;
3165 break;
3167 if (pextra->eus == EUS_HIDDEN) {
3168 extra_type_list_append(extra_type_list_of_unit_hiders(), pextra);
3171 pextra->appearance_chance = secfile_lookup_int_default(file, RS_DEFAULT_EXTRA_APPEARANCE,
3172 "%s.appearance_chance",
3173 section);
3174 pextra->disappearance_chance = secfile_lookup_int_default(file,
3175 RS_DEFAULT_EXTRA_DISAPPEARANCE,
3176 "%s.disappearance_chance",
3177 section);
3179 slist = secfile_lookup_str_vec(file, &nval, "%s.native_to", section);
3180 BV_CLR_ALL(pextra->native_to);
3181 for (j = 0; j < nval; j++) {
3182 struct unit_class *uclass = unit_class_by_rule_name(slist[j]);
3184 if (uclass == NULL) {
3185 ruleset_error(LOG_ERROR,
3186 "\"%s\" extra \"%s\" is native to unknown unit class \"%s\".",
3187 filename,
3188 extra_rule_name(pextra),
3189 slist[j]);
3190 ok = FALSE;
3191 break;
3192 } else {
3193 BV_SET(pextra->native_to, uclass_index(uclass));
3196 free(slist);
3198 if (!ok) {
3199 break;
3202 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
3203 BV_CLR_ALL(pextra->flags);
3204 for (j = 0; j < nval; j++) {
3205 const char *sval = slist[j];
3206 enum extra_flag_id flag = extra_flag_id_by_name(sval, fc_strcasecmp);
3208 if (!extra_flag_id_is_valid(flag)) {
3209 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\": unknown flag \"%s\".",
3210 filename,
3211 extra_rule_name(pextra),
3212 sval);
3213 ok = FALSE;
3214 break;
3215 } else {
3216 BV_SET(pextra->flags, flag);
3219 free(slist);
3221 if (!ok) {
3222 break;
3225 slist = secfile_lookup_str_vec(file, &nval, "%s.conflicts", section);
3226 for (j = 0; j < nval; j++) {
3227 const char *sval = slist[j];
3228 struct extra_type *pextra2 = extra_type_by_rule_name(sval);
3230 if (pextra2 == NULL) {
3231 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\": unknown conflict extra \"%s\".",
3232 filename,
3233 extra_rule_name(pextra),
3234 sval);
3235 ok = FALSE;
3236 break;
3237 } else {
3238 BV_SET(pextra->conflicts, extra_index(pextra2));
3239 BV_SET(pextra2->conflicts, extra_index(pextra));
3243 free(slist);
3245 if (!ok) {
3246 break;
3249 slist = secfile_lookup_str_vec(file, &nval, "%s.hidden_by", section);
3250 BV_CLR_ALL(pextra->hidden_by);
3251 for (j = 0; j < nval; j++) {
3252 const char *sval = slist[j];
3253 const struct extra_type *top = extra_type_by_rule_name(sval);
3255 if (top == NULL) {
3256 ruleset_error(LOG_ERROR, "\"%s\" extra \"%s\" hidden by unknown extra \"%s\".",
3257 filename,
3258 extra_rule_name(pextra),
3259 sval);
3260 ok = FALSE;
3261 break;
3262 } else {
3263 BV_SET(pextra->hidden_by, extra_index(top));
3266 free(slist);
3268 if (!ok) {
3269 break;
3272 vis_req_name = secfile_lookup_str_default(file, "None",
3273 "%s.visibility_req", section);
3274 vis_req = advance_by_rule_name(vis_req_name);
3276 if (vis_req == NULL) {
3277 ruleset_error(LOG_ERROR, "\%s\" %s: unkniwn visibility_req %s.",
3278 filename, section, vis_req_name);
3279 ok = FALSE;
3280 break;
3283 pextra->visibility_req = advance_number(vis_req);
3285 pextra->helptext = lookup_strvec(file, section, "helptext");
3287 } extra_type_iterate_end;
3290 if (ok) {
3291 int i = 0;
3292 /* resource details */
3294 extra_type_by_cause_iterate(EC_RESOURCE, presource) {
3295 char identifier[MAX_LEN_NAME];
3296 const char *rsection = &resource_sections[i * MAX_SECTION_LABEL];
3298 output_type_iterate (o) {
3299 presource->data.resource->output[o] =
3300 secfile_lookup_int_default(file, 0, "%s.%s", rsection,
3301 get_output_identifier(o));
3302 } output_type_iterate_end;
3304 sz_strlcpy(identifier,
3305 secfile_lookup_str(file,"%s.identifier", rsection));
3306 presource->data.resource->id_old_save = identifier[0];
3307 if (RESOURCE_NULL_IDENTIFIER == presource->data.resource->id_old_save) {
3308 ruleset_error(LOG_ERROR, "\"%s\" [%s] identifier missing value.",
3309 filename, rsection);
3310 ok = FALSE;
3311 break;
3313 if (RESOURCE_NONE_IDENTIFIER == presource->data.resource->id_old_save) {
3314 ruleset_error(LOG_ERROR,
3315 "\"%s\" [%s] cannot use '%c' as an identifier;"
3316 " it is reserved.",
3317 filename, rsection, presource->data.resource->id_old_save);
3318 ok = FALSE;
3319 break;
3322 if (!ok) {
3323 break;
3326 i++;
3327 } extra_type_by_cause_iterate_end;
3330 if (ok) {
3331 /* This can't be part of previous loop as we don't want random data from previous
3332 * ruleset to play havoc on us when we have only some resource identifiers loaded
3333 * from the new ruleset. */
3334 extra_type_by_cause_iterate(EC_RESOURCE, pres) {
3335 extra_type_by_cause_iterate(EC_RESOURCE, pres2) {
3336 if (pres->data.resource->id_old_save == pres2->data.resource->id_old_save
3337 && pres != pres2) {
3338 ruleset_error(LOG_ERROR,
3339 "\"%s\" [%s] has the same identifier as [%s].",
3340 filename,
3341 extra_rule_name(pres),
3342 extra_rule_name(pres2));
3343 ok = FALSE;
3344 break;
3346 } extra_type_by_cause_iterate_end;
3348 if (!ok) {
3349 break;
3351 } extra_type_by_cause_iterate_end;
3354 if (ok) {
3355 /* base details */
3356 extra_type_by_cause_iterate(EC_BASE, pextra) {
3357 struct base_type *pbase = extra_base_get(pextra);
3358 const char *section = &base_sections[base_number(pbase) * MAX_SECTION_LABEL];
3359 int bj;
3360 const char **slist;
3361 const char *gui_str;
3363 gui_str = secfile_lookup_str(file,"%s.gui_type", section);
3364 pbase->gui_type = base_gui_type_by_name(gui_str, fc_strcasecmp);
3365 if (!base_gui_type_is_valid(pbase->gui_type)) {
3366 ruleset_error(LOG_ERROR, "\"%s\" base \"%s\": unknown gui_type \"%s\".",
3367 filename,
3368 extra_rule_name(pextra),
3369 gui_str);
3370 ok = FALSE;
3371 break;
3374 pbase->border_sq = secfile_lookup_int_default(file, -1, "%s.border_sq",
3375 section);
3376 pbase->vision_main_sq = secfile_lookup_int_default(file, -1,
3377 "%s.vision_main_sq",
3378 section);
3379 pbase->vision_invis_sq = secfile_lookup_int_default(file, -1,
3380 "%s.vision_invis_sq",
3381 section);
3383 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
3384 BV_CLR_ALL(pbase->flags);
3385 for (bj = 0; bj < nval; bj++) {
3386 const char *sval = slist[bj];
3387 enum base_flag_id flag = base_flag_id_by_name(sval, fc_strcasecmp);
3389 if (!base_flag_id_is_valid(flag)) {
3390 ruleset_error(LOG_ERROR, "\"%s\" base \"%s\": unknown flag \"%s\".",
3391 filename,
3392 extra_rule_name(pextra),
3393 sval);
3394 ok = FALSE;
3395 break;
3396 } else if ((!compat->compat_mode || compat->ver_terrain >= 10)
3397 && base_flag_is_retired(flag)) {
3398 ruleset_error(LOG_ERROR, "\"%s\" base \"%s\": retired flag "
3399 "\"%s\". Please update the ruleset.",
3400 filename,
3401 extra_rule_name(pextra),
3402 sval);
3403 ok = FALSE;
3404 } else {
3405 BV_SET(pbase->flags, flag);
3409 free(slist);
3411 if (!ok) {
3412 break;
3415 if (territory_claiming_base(pbase)) {
3416 extra_type_by_cause_iterate(EC_BASE, pextra2) {
3417 struct base_type *pbase2;
3419 if (pextra == pextra2) {
3420 /* End of the fully initialized bases iteration. */
3421 break;
3424 pbase2 = extra_base_get(pextra2);
3425 if (territory_claiming_base(pbase2)) {
3426 BV_SET(pextra->conflicts, extra_index(pextra2));
3427 BV_SET(pextra2->conflicts, extra_index(pextra));
3429 } extra_type_by_cause_iterate_end;
3431 } extra_type_by_cause_iterate_end;
3434 if (ok) {
3435 extra_type_by_cause_iterate(EC_ROAD, pextra) {
3436 struct road_type *proad = extra_road_get(pextra);
3437 const char *section = &road_sections[road_number(proad) * MAX_SECTION_LABEL];
3438 const char **slist;
3439 const char *special;
3440 const char *modestr;
3441 struct requirement_vector *reqs;
3443 reqs = lookup_req_list(file, compat, section, "first_reqs", extra_rule_name(pextra));
3444 if (reqs == NULL) {
3445 ok = FALSE;
3446 break;
3448 requirement_vector_copy(&proad->first_reqs, reqs);
3450 if (!secfile_lookup_int(file, &proad->move_cost,
3451 "%s.move_cost", section)) {
3452 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3453 ok = FALSE;
3454 break;
3457 modestr = secfile_lookup_str_default(file, "FastAlways", "%s.move_mode",
3458 section);
3459 proad->move_mode = road_move_mode_by_name(modestr, fc_strcasecmp);
3460 if (!road_move_mode_is_valid(proad->move_mode)) {
3461 ruleset_error(LOG_ERROR, "Illegal move_mode \"%s\" for road \"%s\"",
3462 modestr, extra_rule_name(pextra));
3463 ok = FALSE;
3464 break;
3467 output_type_iterate(o) {
3468 proad->tile_incr_const[o] =
3469 secfile_lookup_int_default(file, 0, "%s.%s_incr_const",
3470 section, get_output_identifier(o));
3471 proad->tile_incr[o] =
3472 secfile_lookup_int_default(file, 0, "%s.%s_incr",
3473 section, get_output_identifier(o));
3474 proad->tile_bonus[o] =
3475 secfile_lookup_int_default(file, 0, "%s.%s_bonus",
3476 section, get_output_identifier(o));
3477 } output_type_iterate_end;
3479 special = secfile_lookup_str_default(file, "None", "%s.compat_special", section);
3480 if (!fc_strcasecmp(special, "Road")) {
3481 if (compat_road) {
3482 ruleset_error(LOG_ERROR, "Multiple roads marked as compatibility \"Road\"");
3483 ok = FALSE;
3485 compat_road = TRUE;
3486 proad->compat = ROCO_ROAD;
3487 } else if (!fc_strcasecmp(special, "Railroad")) {
3488 if (compat_rail) {
3489 ruleset_error(LOG_ERROR, "Multiple roads marked as compatibility \"Railroad\"");
3490 ok = FALSE;
3492 compat_rail = TRUE;
3493 proad->compat = ROCO_RAILROAD;
3494 } else if (!fc_strcasecmp(special, "River")) {
3495 if (compat_river) {
3496 ruleset_error(LOG_ERROR, "Multiple roads marked as compatibility \"River\"");
3497 ok = FALSE;
3499 compat_river = TRUE;
3500 proad->compat = ROCO_RIVER;
3501 } else if (!fc_strcasecmp(special, "None")) {
3502 proad->compat = ROCO_NONE;
3503 } else {
3504 ruleset_error(LOG_ERROR, "Illegal compatibility special \"%s\" for road %s",
3505 special, extra_rule_name(pextra));
3506 ok = FALSE;
3509 if (!ok) {
3510 break;
3513 slist = secfile_lookup_str_vec(file, &nval, "%s.integrates", section);
3514 BV_CLR_ALL(proad->integrates);
3515 for (j = 0; j < nval; j++) {
3516 const char *sval = slist[j];
3517 struct extra_type *textra = extra_type_by_rule_name(sval);
3518 struct road_type *top = NULL;
3520 if (textra != NULL) {
3521 top = extra_road_get(textra);
3524 if (top == NULL) {
3525 ruleset_error(LOG_ERROR, "\"%s\" road \"%s\" integrates with unknown road \"%s\".",
3526 filename,
3527 extra_rule_name(pextra),
3528 sval);
3529 ok = FALSE;
3530 break;
3531 } else {
3532 BV_SET(proad->integrates, road_number(top));
3535 free(slist);
3537 if (!ok) {
3538 break;
3541 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", section);
3542 BV_CLR_ALL(proad->flags);
3543 for (j = 0; j < nval; j++) {
3544 const char *sval = slist[j];
3545 enum road_flag_id flag = road_flag_id_by_name(sval, fc_strcasecmp);
3547 if (!road_flag_id_is_valid(flag)) {
3548 ruleset_error(LOG_ERROR, "\"%s\" road \"%s\": unknown flag \"%s\".",
3549 filename,
3550 extra_rule_name(pextra),
3551 sval);
3552 ok = FALSE;
3553 break;
3554 } else {
3555 BV_SET(proad->flags, flag);
3558 free(slist);
3560 if (!ok) {
3561 break;
3563 } extra_type_by_cause_iterate_end;
3566 if (ok) {
3567 secfile_check_unused(file);
3570 return ok;
3573 /**************************************************************************
3574 Load names of governments so other rulesets can refer to governments with
3575 their name. Also load multiplier names/count from governments.ruleset.
3576 **************************************************************************/
3577 static bool load_government_names(struct section_file *file,
3578 struct rscompat_info *compat)
3580 int nval = 0;
3581 struct section_list *sec;
3582 const char *filename = secfile_name(file);
3583 bool ok = TRUE;
3585 compat->ver_governments = rscompat_check_capabilities(file, filename,
3586 compat);
3587 if (compat->ver_governments <= 0) {
3588 return FALSE;
3591 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
3592 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
3594 sec = secfile_sections_by_name_prefix(file, GOVERNMENT_SECTION_PREFIX);
3595 if (NULL == sec || 0 == (nval = section_list_size(sec))) {
3596 ruleset_error(LOG_ERROR, "\"%s\": No governments?!?", filename);
3597 ok = FALSE;
3598 } else if (nval > G_LAST) {
3599 ruleset_error(LOG_ERROR, "\"%s\": Too many governments (%d, max %d)",
3600 filename, nval, G_LAST);
3601 ok = FALSE;
3604 if (ok) {
3605 governments_alloc(nval);
3607 /* Government names are needed early so that get_government_by_name will
3608 * work. */
3609 governments_iterate(gov) {
3610 const char *sec_name =
3611 section_name(section_list_get(sec, government_index(gov)));
3613 if (!ruleset_load_names(&gov->name, NULL, file, sec_name)) {
3614 ok = FALSE;
3615 break;
3617 } governments_iterate_end;
3620 section_list_destroy(sec);
3622 if (ok) {
3623 sec = secfile_sections_by_name_prefix(file, MULTIPLIER_SECTION_PREFIX);
3624 nval = (NULL != sec ? section_list_size(sec) : 0);
3626 if (nval > MAX_NUM_MULTIPLIERS) {
3627 ruleset_error(LOG_ERROR, "\"%s\": Too many multipliers (%d, max %d)",
3628 filename, nval, MAX_NUM_MULTIPLIERS);
3630 ok = FALSE;
3631 } else {
3632 game.control.num_multipliers = nval;
3635 if (ok) {
3636 multipliers_iterate(pmul) {
3637 const char *sec_name =
3638 section_name(section_list_get(sec, multiplier_index(pmul)));
3640 if (!ruleset_load_names(&pmul->name, NULL, file, sec_name)) {
3641 ruleset_error(LOG_ERROR, "\"%s\": Cannot load multiplier names",
3642 filename);
3643 ok = FALSE;
3644 break;
3646 } multipliers_iterate_end;
3650 section_list_destroy(sec);
3652 return ok;
3655 /**************************************************************************
3656 This loads information from given governments.ruleset
3657 **************************************************************************/
3658 static bool load_ruleset_governments(struct section_file *file,
3659 struct rscompat_info *compat)
3661 struct section_list *sec;
3662 const char *filename = secfile_name(file);
3663 bool ok = TRUE;
3665 sec = secfile_sections_by_name_prefix(file, GOVERNMENT_SECTION_PREFIX);
3667 game.government_during_revolution
3668 = lookup_government(file, "governments.during_revolution", filename, NULL);
3669 if (game.government_during_revolution == NULL) {
3670 ok = FALSE;
3673 if (ok) {
3674 game.info.government_during_revolution_id =
3675 government_number(game.government_during_revolution);
3677 /* easy ones: */
3678 governments_iterate(g) {
3679 const int i = government_index(g);
3680 const char *sec_name = section_name(section_list_get(sec, i));
3681 struct requirement_vector *reqs =
3682 lookup_req_list(file, compat, sec_name, "reqs", government_rule_name(g));
3684 if (reqs == NULL) {
3685 ok = FALSE;
3686 break;
3689 if (NULL != secfile_entry_lookup(file, "%s.ai_better", sec_name)) {
3690 char entry[100];
3692 fc_snprintf(entry, sizeof(entry), "%s.ai_better", sec_name);
3693 g->ai.better = lookup_government(file, entry, filename, NULL);
3694 if (g->ai.better == NULL) {
3695 ok = FALSE;
3696 break;
3698 } else {
3699 g->ai.better = NULL;
3701 requirement_vector_copy(&g->reqs, reqs);
3703 sz_strlcpy(g->graphic_str,
3704 secfile_lookup_str(file, "%s.graphic", sec_name));
3705 sz_strlcpy(g->graphic_alt,
3706 secfile_lookup_str(file, "%s.graphic_alt", sec_name));
3708 g->helptext = lookup_strvec(file, sec_name, "helptext");
3709 } governments_iterate_end;
3713 if (ok) {
3714 /* titles */
3715 governments_iterate(g) {
3716 const char *sec_name =
3717 section_name(section_list_get(sec, government_index(g)));
3718 const char *male, *female;
3720 if (!(male = secfile_lookup_str(file, "%s.ruler_male_title", sec_name))
3721 || !(female = secfile_lookup_str(file, "%s.ruler_female_title",
3722 sec_name))) {
3723 ruleset_error(LOG_ERROR, "Lack of default ruler titles for "
3724 "government \"%s\" (nb %d): %s",
3725 government_rule_name(g), government_number(g),
3726 secfile_error());
3727 ok = FALSE;
3728 break;
3729 } else if (NULL == government_ruler_title_new(g, NULL, male, female)) {
3730 ruleset_error(LOG_ERROR, "Lack of default ruler titles for "
3731 "government \"%s\" (nb %d).",
3732 government_rule_name(g), government_number(g));
3733 ok = FALSE;
3734 break;
3736 } governments_iterate_end;
3739 section_list_destroy(sec);
3741 if (ok) {
3742 sec = secfile_sections_by_name_prefix(file, MULTIPLIER_SECTION_PREFIX);
3743 multipliers_iterate(pmul) {
3744 int id = multiplier_index(pmul);
3745 const char *sec_name = section_name(section_list_get(sec, id));
3747 if (!secfile_lookup_int(file, &pmul->start, "%s.start", sec_name)) {
3748 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3749 ok = FALSE;
3750 break;
3752 if (!secfile_lookup_int(file, &pmul->stop, "%s.stop", sec_name)) {
3753 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3754 ok = FALSE;
3755 break;
3757 if (pmul->stop <= pmul->start) {
3758 ruleset_error(LOG_ERROR, "Multiplier \"%s\" stop (%d) must be greater "
3759 "than start (%d)", multiplier_rule_name(pmul),
3760 pmul->stop, pmul->start);
3761 ok = FALSE;
3762 break;
3764 if (!secfile_lookup_int(file, &pmul->step, "%s.step", sec_name)) {
3765 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3766 ok = FALSE;
3767 break;
3769 if (((pmul->stop - pmul->start) % pmul->step) != 0) {
3770 ruleset_error(LOG_ERROR, "Multiplier \"%s\" step (%d) does not fit "
3771 "exactly into interval start-stop (%d to %d)",
3772 multiplier_rule_name(pmul), pmul->step,
3773 pmul->start, pmul->stop);
3774 ok = FALSE;
3775 break;
3777 if (!secfile_lookup_int(file, &pmul->def, "%s.default", sec_name)) {
3778 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
3779 ok = FALSE;
3780 break;
3782 if (pmul->def < pmul->start || pmul->def > pmul->stop) {
3783 ruleset_error(LOG_ERROR, "Multiplier \"%s\" default (%d) not within "
3784 "legal range (%d to %d)", multiplier_rule_name(pmul),
3785 pmul->def, pmul->start, pmul->stop);
3786 ok = FALSE;
3787 break;
3789 if (((pmul->def - pmul->start) % pmul->step) != 0) {
3790 ruleset_error(LOG_ERROR, "Multiplier \"%s\" default (%d) not legal "
3791 "with respect to step size %d",
3792 multiplier_rule_name(pmul), pmul->def, pmul->step);
3793 ok = FALSE;
3794 break;
3796 pmul->offset = secfile_lookup_int_default(file, 0,
3797 "%s.offset", sec_name);
3798 pmul->factor = secfile_lookup_int_default(file, 100,
3799 "%s.factor", sec_name);
3800 if (pmul->factor == 0) {
3801 ruleset_error(LOG_ERROR, "Multiplier \"%s\" scaling factor must "
3802 "not be zero", multiplier_rule_name(pmul));
3803 ok = FALSE;
3804 break;
3807 pmul->helptext = lookup_strvec(file, sec_name, "helptext");
3808 } multipliers_iterate_end;
3809 section_list_destroy(sec);
3812 if (ok) {
3813 secfile_check_unused(file);
3816 return ok;
3819 /**************************************************************************
3820 Send information in packet_ruleset_control (numbers of units etc, and
3821 other miscellany) to specified connections.
3823 The client assumes that exactly one ruleset control packet is sent as
3824 a part of each ruleset send. So after sending this packet we have to
3825 resend every other part of the rulesets (and none of them should be
3826 is-info in the network code!). The client frees ruleset data when
3827 receiving this packet and then re-initializes as it receives the
3828 individual ruleset packets. See packhand.c.
3829 **************************************************************************/
3830 static void send_ruleset_control(struct conn_list *dest)
3832 int desc_left = game.control.desc_length;
3833 int idx = 0;
3835 lsend_packet_ruleset_control(dest, &(game.control));
3837 if (game.ruleset_summary != NULL) {
3838 struct packet_ruleset_summary summary;
3840 strncpy(summary.text, game.ruleset_summary, MAX_LEN_CONTENT);
3842 lsend_packet_ruleset_summary(dest, &summary);
3845 while (desc_left > 0) {
3846 struct packet_ruleset_description_part part;
3847 int this_len = desc_left;
3849 if (this_len > MAX_LEN_CONTENT - 21) {
3850 this_len = MAX_LEN_CONTENT - 1;
3853 part.text[this_len] = '\0';
3855 strncpy(part.text, &game.ruleset_description[idx], this_len);
3856 idx += this_len;
3857 desc_left -= this_len;
3859 lsend_packet_ruleset_description_part(dest, &part);
3863 /****************************************************************************
3864 Check for duplicate leader names in nation.
3865 If no duplicates return NULL; if yes return pointer to name which is
3866 repeated.
3867 ****************************************************************************/
3868 static const char *check_leader_names(struct nation_type *pnation)
3870 nation_leader_list_iterate(nation_leaders(pnation), pleader) {
3871 const char *name = nation_leader_name(pleader);
3873 nation_leader_list_iterate(nation_leaders(pnation), prev_leader) {
3874 if (prev_leader == pleader) {
3875 break;
3876 } else if (0 == fc_strcasecmp(name, nation_leader_name(prev_leader))) {
3877 return name;
3879 } nation_leader_list_iterate_end;
3880 } nation_leader_list_iterate_end;
3881 return NULL;
3884 /**************************************************************************
3885 Load names of nations so other rulesets can refer to nations with
3886 their name.
3887 **************************************************************************/
3888 static bool load_nation_names(struct section_file *file,
3889 struct rscompat_info *compat)
3891 struct section_list *sec;
3892 int j;
3893 bool ok = TRUE;
3894 const char *filename = secfile_name(file);
3896 compat->ver_nations = rscompat_check_capabilities(file, filename,
3897 compat);
3898 if (compat->ver_nations <= 0) {
3899 return FALSE;
3902 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
3903 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
3905 sec = secfile_sections_by_name_prefix(file, NATION_SECTION_PREFIX);
3906 if (NULL == sec) {
3907 ruleset_error(LOG_ERROR, "No available nations in this ruleset!");
3908 ok = FALSE;
3909 } else if (section_list_size(sec) > MAX_NUM_NATIONS) {
3910 ruleset_error(LOG_ERROR, "Too many nations (max %d, we have %d)!",
3911 MAX_NUM_NATIONS, section_list_size(sec));
3912 ok = FALSE;
3913 } else {
3914 game.control.nation_count = section_list_size(sec);
3915 nations_alloc(game.control.nation_count);
3917 nations_iterate(pl) {
3918 const int i = nation_index(pl);
3919 const char *sec_name = section_name(section_list_get(sec, i));
3920 const char *domain = secfile_lookup_str_default(file, NULL,
3921 "%s.translation_domain", sec_name);
3922 const char *noun_plural = secfile_lookup_str(file,
3923 "%s.plural", sec_name);
3926 if (domain == NULL) {
3927 domain = "freeciv-nations";
3930 if (!strcmp("freeciv", domain)) {
3931 pl->translation_domain = NULL;
3932 } else if (!strcmp("freeciv-nations", domain)) {
3933 pl->translation_domain = fc_malloc(strlen(domain) + 1);
3934 strcpy(pl->translation_domain, domain);
3935 } else {
3936 ruleset_error(LOG_ERROR, "Unsupported translation domain \"%s\" for %s",
3937 domain, sec_name);
3938 ok = FALSE;
3939 break;
3942 if (!ruleset_load_names(&pl->adjective, domain, file, sec_name)) {
3943 ok = FALSE;
3944 break;
3946 name_set(&pl->noun_plural, domain, noun_plural);
3948 /* Check if nation name is already defined. */
3949 for (j = 0; j < i && ok; j++) {
3950 struct nation_type *n2 = nation_by_number(j);
3952 /* Compare strings after stripping off qualifiers -- we don't want
3953 * two nations to end up with identical adjectives displayed to users.
3954 * (This check only catches English, not localisations, of course.) */
3955 if (0 == strcmp(Qn_(untranslated_name(&n2->adjective)),
3956 Qn_(untranslated_name(&pl->adjective)))) {
3957 ruleset_error(LOG_ERROR,
3958 "Two nations defined with the same adjective \"%s\": "
3959 "in section \'%s\' and section \'%s\'",
3960 Qn_(untranslated_name(&pl->adjective)),
3961 section_name(section_list_get(sec, j)), sec_name);
3962 ok = FALSE;
3963 } else if (!strcmp(rule_name_get(&n2->adjective),
3964 rule_name_get(&pl->adjective))) {
3965 /* We cannot have the same rule name, as the game needs them to be
3966 * distinct. */
3967 ruleset_error(LOG_ERROR,
3968 "Two nations defined with the same rule_name \"%s\": "
3969 "in section \'%s\' and section \'%s\'",
3970 rule_name_get(&pl->adjective),
3971 section_name(section_list_get(sec, j)), sec_name);
3972 ok = FALSE;
3973 } else if (0 == strcmp(Qn_(untranslated_name(&n2->noun_plural)),
3974 Qn_(untranslated_name(&pl->noun_plural)))) {
3975 /* We don't want identical English plural names either. */
3976 ruleset_error(LOG_ERROR,
3977 "Two nations defined with the same plural name \"%s\": "
3978 "in section \'%s\' and section \'%s\'",
3979 Qn_(untranslated_name(&pl->noun_plural)),
3980 section_name(section_list_get(sec, j)), sec_name);
3981 ok = FALSE;
3984 if (!ok) {
3985 break;
3987 } nations_iterate_end;
3990 section_list_destroy(sec);
3992 if (ok) {
3993 sec = secfile_sections_by_name_prefix(file, NATION_GROUP_SECTION_PREFIX);
3994 if (sec) {
3995 section_list_iterate(sec, psection) {
3996 struct nation_group *pgroup;
3997 const char *name;
3999 name = secfile_lookup_str(file, "%s.name", section_name(psection));
4000 if (NULL == name) {
4001 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
4002 ok = FALSE;
4003 break;
4005 pgroup = nation_group_new(name);
4006 if (pgroup == NULL) {
4007 ok = FALSE;
4008 break;
4010 } section_list_iterate_end;
4011 section_list_destroy(sec);
4012 sec = NULL;
4016 return ok;
4019 /**************************************************************************
4020 Check if a string is in a vector (case-insensitively).
4021 **************************************************************************/
4022 static bool is_on_allowed_list(const char *name, const char **list, size_t len)
4024 int i;
4026 for (i = 0; i < len; i++) {
4027 if (!fc_strcasecmp(name, list[i])) {
4028 return TRUE;
4031 return FALSE;
4034 /****************************************************************************
4035 This function loads a city name list from a section file. The file and
4036 two section names (which will be concatenated) are passed in.
4037 ****************************************************************************/
4038 static bool load_city_name_list(struct section_file *file,
4039 struct nation_type *pnation,
4040 const char *secfile_str1,
4041 const char *secfile_str2,
4042 const char **allowed_terrains,
4043 size_t atcount)
4045 size_t dim, j;
4046 bool ok = TRUE;
4047 const char **cities = secfile_lookup_str_vec(file, &dim, "%s.%s",
4048 secfile_str1, secfile_str2);
4050 /* Each string will be of the form "<cityname> (<label>, <label>, ...)".
4051 * The cityname is just the name for this city, while each "label" matches
4052 * a terrain type for the city (or "river"), with a preceeding ! to negate
4053 * it. The parentheses are optional (but necessary to have the settings,
4054 * of course). Our job is now to parse it. */
4055 for (j = 0; j < dim; j++) {
4056 size_t len = strlen(cities[j]);
4057 char city_name[len + 1], *p, *next, *end;
4058 struct nation_city *pncity;
4060 sz_strlcpy(city_name, cities[j]);
4062 /* Now we wish to determine values for all of the city labels. A value
4063 * of NCP_NONE means no preference (which is necessary so that the use
4064 * of this is optional); NCP_DISLIKE means the label is negated and
4065 * NCP_LIKE means it's labelled. Mostly the parsing just involves
4066 * a lot of ugly string handling... */
4067 if ((p = strchr(city_name, '('))) {
4068 *p++ = '\0';
4070 if (!(end = strchr(p, ')'))) {
4071 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city name \"%s\" "
4072 "unmatched parenthesis.", secfile_name(file),
4073 secfile_str1, secfile_str2, cities[j]);
4074 ok = FALSE;
4075 } else {
4076 for (*end++ = '\0'; '\0' != *end; end++) {
4077 if (!fc_isspace(*end)) {
4078 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city name \"%s\" "
4079 "contains characters after last parenthesis.",
4080 secfile_name(file), secfile_str1, secfile_str2,
4081 cities[j]);
4082 ok = FALSE;
4083 break;
4089 /* Build the nation_city. */
4090 remove_leading_trailing_spaces(city_name);
4091 if (check_cityname(city_name)) {
4092 /* The ruleset contains a name that is too long. This shouldn't
4093 * happen - if it does, the author should get immediate feedback. */
4094 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city name \"%s\" "
4095 "is too long.", secfile_name(file),
4096 secfile_str1, secfile_str2, city_name);
4097 ok = FALSE;
4098 city_name[MAX_LEN_CITYNAME - 1] = '\0';
4100 pncity = nation_city_new(pnation, city_name);
4102 if (NULL != p) {
4103 /* Handle the labels one at a time. */
4104 do {
4105 enum nation_city_preference prefer;
4107 if ((next = strchr(p, ','))) {
4108 *next = '\0';
4110 remove_leading_trailing_spaces(p);
4112 /* The ! is used to mark a negative, which is recorded with
4113 * NCP_DISLIKE. Otherwise we use a NCP_LIKE.
4115 if (*p == '!') {
4116 p++;
4117 prefer = NCP_DISLIKE;
4118 } else {
4119 prefer = NCP_LIKE;
4122 if (0 == fc_strcasecmp(p, "river")) {
4123 if (game.server.ruledit.allowed_terrains != NULL
4124 && !is_on_allowed_list(p,
4125 game.server.ruledit.allowed_terrains, atcount)) {
4126 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city \"%s\" "
4127 "has terrain hint \"%s\" not in allowed_terrains.",
4128 secfile_name(file), secfile_str1, secfile_str2,
4129 city_name, p);
4130 ok = FALSE;
4131 } else {
4132 nation_city_set_river_preference(pncity, prefer);
4134 } else {
4135 const struct terrain *pterrain = terrain_by_rule_name(p);
4137 if (NULL == pterrain) {
4138 /* Try with removing frequent trailing 's'. */
4139 size_t l = strlen(p);
4141 if (0 < l && 's' == fc_tolower(p[l - 1])) {
4142 p[l - 1] = '\0';
4144 pterrain = terrain_by_rule_name(p);
4147 /* Nationset may have been devised with a specific set of terrains
4148 * in mind which don't quite match this ruleset, in which case we
4149 * (a) quietly ignore any hints mentioned that don't happen to be in
4150 * the current ruleset, (b) enforce that terrains mentioned by nations
4151 * must be on the list */
4152 if (pterrain != NULL && game.server.ruledit.allowed_terrains != NULL) {
4153 if (!is_on_allowed_list(p,
4154 game.server.ruledit.allowed_terrains, atcount)) {
4155 /* Terrain exists, but not intended for these nations */
4156 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city \"%s\" "
4157 "has terrain hint \"%s\" not in allowed_terrains.",
4158 secfile_name(file), secfile_str1, secfile_str2,
4159 city_name, p);
4160 ok = FALSE;
4161 break;
4163 } else if (!pterrain) {
4164 /* Terrain doesn't exist; only complain if it's not on any list */
4165 if (game.server.ruledit.allowed_terrains == NULL
4166 || !is_on_allowed_list(p,
4167 game.server.ruledit.allowed_terrains, atcount)) {
4168 ruleset_error(LOG_ERROR, "\"%s\" [%s] %s: city \"%s\" "
4169 "has unknown terrain hint \"%s\".",
4170 secfile_name(file), secfile_str1, secfile_str2,
4171 city_name, p);
4172 ok = FALSE;
4173 break;
4176 if (NULL != pterrain) {
4177 nation_city_set_terrain_preference(pncity, pterrain, prefer);
4181 p = next ? next + 1 : NULL;
4182 } while (NULL != p && '\0' != *p);
4186 if (NULL != cities) {
4187 free(cities);
4190 return ok;
4193 /**************************************************************************
4194 Load nations.ruleset file
4195 **************************************************************************/
4196 static bool load_ruleset_nations(struct section_file *file,
4197 struct rscompat_info *compat)
4199 struct government *gov;
4200 int j;
4201 size_t dim;
4202 char temp_name[MAX_LEN_NAME];
4203 const char **vec;
4204 const char *name, *bad_leader;
4205 const char *sval;
4206 int default_set;
4207 const char *filename = secfile_name(file);
4208 struct section_list *sec;
4209 enum trait tr;
4210 bool ok = TRUE;
4212 name = secfile_lookup_str_default(file, NULL, "ruledit.nationlist");
4213 if (name != NULL) {
4214 game.server.ruledit.nationlist = fc_strdup(name);
4216 vec = secfile_lookup_str_vec(file, &game.server.ruledit.embedded_nations_count,
4217 "ruledit.embedded_nations");
4219 if (vec != NULL) {
4220 /* Copy to persistent vector */
4221 game.server.ruledit.embedded_nations
4222 = fc_malloc(game.server.ruledit.embedded_nations_count * sizeof(char *));
4224 for (j = 0; j < game.server.ruledit.embedded_nations_count; j++) {
4225 game.server.ruledit.embedded_nations[j] = fc_strdup(vec[j]);
4228 free(vec);
4231 game.default_government = NULL;
4233 ruleset_load_traits(game.server.default_traits, file, "default_traits", "");
4234 for (tr = trait_begin(); tr != trait_end(); tr = trait_next(tr)) {
4235 if (game.server.default_traits[tr].min < 0) {
4236 game.server.default_traits[tr].min = TRAIT_DEFAULT_VALUE;
4238 if (game.server.default_traits[tr].max < 0) {
4239 game.server.default_traits[tr].max = TRAIT_DEFAULT_VALUE;
4241 if (game.server.default_traits[tr].fixed < 0) {
4242 int diff = game.server.default_traits[tr].max - game.server.default_traits[tr].min;
4244 /* TODO: Should sometimes round the a / 2 = x.5 results up */
4245 game.server.default_traits[tr].fixed = diff / 2 + game.server.default_traits[tr].min;
4247 if (game.server.default_traits[tr].max < game.server.default_traits[tr].min) {
4248 ruleset_error(LOG_ERROR, "Default values for trait %s not sane.",
4249 trait_name(tr));
4250 ok = FALSE;
4251 break;
4255 if (ok) {
4256 vec = secfile_lookup_str_vec(file, &game.server.ruledit.ag_count,
4257 "compatibility.allowed_govs");
4258 if (vec != NULL) {
4259 /* Copy to persistent vector */
4260 game.server.ruledit.nc_agovs
4261 = fc_malloc(game.server.ruledit.ag_count * sizeof(char *));
4262 game.server.ruledit.allowed_govs =
4263 (const char **)game.server.ruledit.nc_agovs;
4265 for (j = 0; j < game.server.ruledit.ag_count; j++) {
4266 game.server.ruledit.allowed_govs[j] = fc_strdup(vec[j]);
4269 free(vec);
4272 vec = secfile_lookup_str_vec(file, &game.server.ruledit.at_count,
4273 "compatibility.allowed_terrains");
4274 if (vec != NULL) {
4275 /* Copy to persistent vector */
4276 game.server.ruledit.nc_aterrs
4277 = fc_malloc(game.server.ruledit.at_count * sizeof(char *));
4278 game.server.ruledit.allowed_terrains =
4279 (const char **)game.server.ruledit.nc_aterrs;
4281 for (j = 0; j < game.server.ruledit.at_count; j++) {
4282 game.server.ruledit.allowed_terrains[j] = fc_strdup(vec[j]);
4285 free(vec);
4288 vec = secfile_lookup_str_vec(file, &game.server.ruledit.as_count,
4289 "compatibility.allowed_styles");
4290 if (vec != NULL) {
4291 /* Copy to persistent vector */
4292 game.server.ruledit.nc_astyles
4293 = fc_malloc(game.server.ruledit.as_count * sizeof(char *));
4294 game.server.ruledit.allowed_styles =
4295 (const char **)game.server.ruledit.nc_astyles;
4297 for (j = 0; j < game.server.ruledit.as_count; j++) {
4298 game.server.ruledit.allowed_styles[j] = fc_strdup(vec[j]);
4301 free(vec);
4304 sval = secfile_lookup_str_default(file, NULL,
4305 "compatibility.default_government");
4306 /* We deliberately don't check this against allowed_govs. It's only
4307 * specified once so not vulnerable to typos, and may usefully be set in
4308 * a specific ruleset to a gov not explicitly known by the nation set. */
4309 if (sval != NULL) {
4310 game.default_government = government_by_rule_name(sval);
4311 if (game.default_government == NULL) {
4312 ruleset_error(LOG_ERROR,
4313 "Tried to set unknown government type \"%s\" as default_government!",
4314 sval);
4315 ok = FALSE;
4316 } else {
4317 game.info.default_government_id
4318 = government_number(game.default_government);
4323 if (ok) {
4324 sec = secfile_sections_by_name_prefix(file, NATION_SET_SECTION_PREFIX);
4325 if (sec) {
4326 section_list_iterate(sec, psection) {
4327 const char *set_name, *set_rule_name, *set_description;
4329 set_name = secfile_lookup_str(file, "%s.name", section_name(psection));
4330 set_rule_name =
4331 secfile_lookup_str(file, "%s.rule_name", section_name(psection));
4332 set_description = secfile_lookup_str_default(file, "", "%s.description",
4333 section_name(psection));
4334 if (NULL == set_name || NULL == set_rule_name) {
4335 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
4336 ok = FALSE;
4337 break;
4339 if (nation_set_new(set_name, set_rule_name, set_description) == NULL) {
4340 ok = FALSE;
4341 break;
4343 } section_list_iterate_end;
4344 section_list_destroy(sec);
4345 sec = NULL;
4346 } else {
4347 ruleset_error(LOG_ERROR,
4348 "At least one nation set [" NATION_SET_SECTION_PREFIX "_*] "
4349 "must be defined.");
4350 ok = FALSE;
4354 if (ok) {
4355 /* Default set that every nation is a member of. */
4356 sval = secfile_lookup_str_default(file, NULL,
4357 "compatibility.default_nationset");
4358 if (sval != NULL) {
4359 const struct nation_set *pset = nation_set_by_rule_name(sval);
4360 if (pset != NULL) {
4361 default_set = nation_set_number(pset);
4362 } else {
4363 ruleset_error(LOG_ERROR,
4364 "Unknown default_nationset \"%s\".", sval);
4365 ok = FALSE;
4367 } else if (nation_set_count() == 1) {
4368 /* If there's only one set defined, every nation is implicitly a
4369 * member of that set. */
4370 default_set = 0;
4371 } else {
4372 /* No default nation set; every nation must explicitly specify at
4373 * least one set to be a member of. */
4374 default_set = -1;
4378 if (ok) {
4379 sec = secfile_sections_by_name_prefix(file, NATION_GROUP_SECTION_PREFIX);
4380 if (sec) {
4381 section_list_iterate(sec, psection) {
4382 struct nation_group *pgroup;
4383 bool hidden;
4385 name = secfile_lookup_str(file, "%s.name", section_name(psection));
4386 pgroup = nation_group_by_rule_name(name);
4387 if (pgroup == NULL) {
4388 ok = FALSE;
4389 break;
4392 hidden = secfile_lookup_bool_default(file, FALSE, "%s.hidden",
4393 section_name(psection));
4394 nation_group_set_hidden(pgroup, hidden);
4396 if (!secfile_lookup_int(file, &j, "%s.match", section_name(psection))) {
4397 ruleset_error(LOG_ERROR, "Error: %s", secfile_error());
4398 ok = FALSE;
4399 break;
4401 nation_group_set_match(pgroup, j);
4402 } section_list_iterate_end;
4403 section_list_destroy(sec);
4404 sec = NULL;
4408 if (ok) {
4409 sec = secfile_sections_by_name_prefix(file, NATION_SECTION_PREFIX);
4410 nations_iterate(pnation) {
4411 struct nation_type *pconflict;
4412 const int i = nation_index(pnation);
4413 char tmp[200] = "\0";
4414 const char *barb_type;
4415 const char *sec_name = section_name(section_list_get(sec, i));
4416 const char *legend;
4418 /* Nation sets and groups. */
4419 if (default_set >= 0) {
4420 nation_set_list_append(pnation->sets,
4421 nation_set_by_number(default_set));
4423 vec = secfile_lookup_str_vec(file, &dim, "%s.groups", sec_name);
4424 for (j = 0; j < dim; j++) {
4425 struct nation_set *pset = nation_set_by_rule_name(vec[j]);
4426 struct nation_group *pgroup = nation_group_by_rule_name(vec[j]);
4428 fc_assert(pset == NULL || pgroup == NULL);
4430 if (NULL != pset) {
4431 nation_set_list_append(pnation->sets, pset);
4432 } else if (NULL != pgroup) {
4433 nation_group_list_append(pnation->groups, pgroup);
4434 } else {
4435 /* For nation authors, this would probably be considered an error.
4436 * But it can happen normally. The civ1 compatibility ruleset only
4437 * uses the nations that were in civ1, so not all of the links will
4438 * exist. */
4439 log_verbose("Nation %s: Unknown set/group \"%s\".",
4440 nation_rule_name(pnation), vec[j]);
4443 if (NULL != vec) {
4444 free(vec);
4446 if (nation_set_list_size(pnation->sets) < 1) {
4447 ruleset_error(LOG_ERROR,
4448 "Nation %s is not a member of any nation set",
4449 nation_rule_name(pnation));
4450 ok = FALSE;
4451 break;
4454 /* Nation conflicts. */
4455 vec = secfile_lookup_str_vec(file, &dim, "%s.conflicts_with", sec_name);
4456 for (j = 0; j < dim; j++) {
4457 pconflict = nation_by_rule_name(vec[j]);
4459 if (pnation == pconflict) {
4460 ruleset_error(LOG_ERROR, "Nation %s conflicts with itself",
4461 nation_rule_name(pnation));
4462 ok = FALSE;
4463 break;
4464 } else if (NULL != pconflict) {
4465 nation_list_append(pnation->server.conflicts_with, pconflict);
4466 } else {
4467 /* For nation authors, this would probably be considered an error.
4468 * But it can happen normally. The civ1 compatibility ruleset only
4469 * uses the nations that were in civ1, so not all of the links will
4470 * exist. */
4471 log_verbose("Nation %s: conflicts_with nation \"%s\" is unknown.",
4472 nation_rule_name(pnation), vec[j]);
4475 if (NULL != vec) {
4476 free(vec);
4478 if (!ok) {
4479 break;
4482 /* Nation leaders. */
4483 for (j = 0; j < MAX_NUM_LEADERS; j++) {
4484 const char *sex;
4485 bool is_male = FALSE;
4487 name = secfile_lookup_str(file, "%s.leaders%d.name", sec_name, j);
4488 if (NULL == name) {
4489 /* No more to read. */
4490 break;
4493 if (check_name(name)) {
4494 /* The ruleset contains a name that is too long. This shouldn't
4495 * happen - if it does, the author should get immediate feedback */
4496 sz_strlcpy(temp_name, name);
4497 ruleset_error(LOG_ERROR, "Nation %s: leader name \"%s\" "
4498 "is too long.",
4499 nation_rule_name(pnation), name);
4500 ok = FALSE;
4501 break;
4504 sex = secfile_lookup_str(file, "%s.leaders%d.sex", sec_name, j);
4505 if (NULL == sex) {
4506 ruleset_error(LOG_ERROR, "Nation %s: leader \"%s\": %s.",
4507 nation_rule_name(pnation), name, secfile_error());
4508 ok = FALSE;
4509 break;
4510 } else if (0 == fc_strcasecmp("Male", sex)) {
4511 is_male = TRUE;
4512 } else if (0 != fc_strcasecmp("Female", sex)) {
4513 ruleset_error(LOG_ERROR, "Nation %s: leader \"%s\" has unsupported "
4514 "sex variant \"%s\".",
4515 nation_rule_name(pnation), name, sex);
4516 ok = FALSE;
4517 break;
4519 (void) nation_leader_new(pnation, name, is_male);
4521 if (!ok) {
4522 break;
4525 /* Check the number of leaders. */
4526 if (MAX_NUM_LEADERS == j) {
4527 /* Too much leaders, get the real number defined in the ruleset. */
4528 while (NULL != secfile_entry_lookup(file, "%s.leaders%d.name",
4529 sec_name, j)) {
4530 j++;
4532 ruleset_error(LOG_ERROR, "Nation %s: Too many leaders; max is %d",
4533 nation_rule_name(pnation), MAX_NUM_LEADERS);
4534 ok = FALSE;
4535 break;
4536 } else if (0 == j) {
4537 ruleset_error(LOG_ERROR,
4538 "Nation %s: no leaders; at least one is required.",
4539 nation_rule_name(pnation));
4540 ok = FALSE;
4541 break;
4544 /* Check if leader name is not already defined in this nation. */
4545 if ((bad_leader = check_leader_names(pnation))) {
4546 ruleset_error(LOG_ERROR,
4547 "Nation %s: leader \"%s\" defined more than once.",
4548 nation_rule_name(pnation), bad_leader);
4549 ok = FALSE;
4550 break;
4553 /* Nation player color preference, if any */
4554 fc_assert_ret_val(pnation->server.rgb == NULL, FALSE);
4555 (void) rgbcolor_load(file, &pnation->server.rgb, "%s.color", sec_name);
4557 /* Load nation traits */
4558 ruleset_load_traits(pnation->server.traits, file, sec_name, "trait_");
4559 for (tr = trait_begin(); tr != trait_end(); tr = trait_next(tr)) {
4560 bool server_traits_used = TRUE;
4562 if (pnation->server.traits[tr].min < 0) {
4563 pnation->server.traits[tr].min = game.server.default_traits[tr].min;
4564 } else {
4565 server_traits_used = FALSE;
4567 if (pnation->server.traits[tr].max < 0) {
4568 pnation->server.traits[tr].max = game.server.default_traits[tr].max;
4569 } else {
4570 server_traits_used = FALSE;
4572 if (pnation->server.traits[tr].fixed < 0) {
4573 if (server_traits_used) {
4574 pnation->server.traits[tr].fixed = game.server.default_traits[tr].fixed;
4575 } else {
4576 int diff = pnation->server.traits[tr].max - pnation->server.traits[tr].min;
4578 /* TODO: Should sometimes round the a / 2 = x.5 results up */
4579 pnation->server.traits[tr].fixed = diff / 2 + pnation->server.traits[tr].min;
4582 if (pnation->server.traits[tr].max < pnation->server.traits[tr].min) {
4583 ruleset_error(LOG_ERROR, "%s values for trait %s not sane.",
4584 nation_rule_name(pnation), trait_name(tr));
4585 ok = FALSE;
4586 break;
4590 if (!ok) {
4591 break;
4594 pnation->is_playable =
4595 secfile_lookup_bool_default(file, TRUE, "%s.is_playable", sec_name);
4597 /* Check barbarian type. Default is "None" meaning not a barbarian */
4598 barb_type = secfile_lookup_str_default(file, "None",
4599 "%s.barbarian_type", sec_name);
4600 pnation->barb_type = barbarian_type_by_name(barb_type, fc_strcasecmp);
4601 if (!barbarian_type_is_valid(pnation->barb_type)) {
4602 ruleset_error(LOG_ERROR,
4603 "Nation %s, barbarian_type is invalid (\"%s\")",
4604 nation_rule_name(pnation), barb_type);
4605 ok = FALSE;
4606 break;
4609 if (pnation->barb_type != NOT_A_BARBARIAN
4610 && pnation->is_playable) {
4611 /* We can't allow players to use barbarian nations, barbarians
4612 * may run out of nations */
4613 ruleset_error(LOG_ERROR,
4614 "Nation %s marked both barbarian and playable.",
4615 nation_rule_name(pnation));
4616 ok = FALSE;
4617 break;
4620 /* Flags */
4621 sz_strlcpy(pnation->flag_graphic_str,
4622 secfile_lookup_str_default(file, "-", "%s.flag", sec_name));
4623 sz_strlcpy(pnation->flag_graphic_alt,
4624 secfile_lookup_str_default(file, "-",
4625 "%s.flag_alt", sec_name));
4627 /* Ruler titles */
4628 for (j = 0;; j++) {
4629 const char *male, *female;
4631 name = secfile_lookup_str_default(file, NULL,
4632 "%s.ruler_titles%d.government",
4633 sec_name, j);
4634 if (NULL == name) {
4635 /* End of the list of ruler titles. */
4636 break;
4639 /* NB: even if the government doesn't exist, we load the entries for
4640 * the ruler titles to avoid warnings about unused entries. */
4641 male = secfile_lookup_str(file, "%s.ruler_titles%d.male_title",
4642 sec_name, j);
4643 female = secfile_lookup_str(file, "%s.ruler_titles%d.female_title",
4644 sec_name, j);
4645 gov = government_by_rule_name(name);
4647 /* Nationset may have been devised with a specific set of govs in
4648 * mind which don't quite match this ruleset, in which case we
4649 * (a) quietly ignore any govs mentioned that don't happen to be in
4650 * the current ruleset, (b) enforce that govs mentioned by nations
4651 * must be on the list */
4652 if (gov != NULL && game.server.ruledit.allowed_govs != NULL) {
4653 if (!is_on_allowed_list(name,
4654 game.server.ruledit.allowed_govs,
4655 game.server.ruledit.ag_count)) {
4656 /* Gov exists, but not intended for these nations */
4657 gov = NULL;
4658 ruleset_error(LOG_ERROR,
4659 "Nation %s: government \"%s\" not in allowed_govs.",
4660 nation_rule_name(pnation), name);
4661 ok = FALSE;
4662 break;
4664 } else if (!gov) {
4665 /* Gov doesn't exist; only complain if it's not on any list */
4666 if (game.server.ruledit.allowed_govs == NULL
4667 || !is_on_allowed_list(name,
4668 game.server.ruledit.allowed_govs,
4669 game.server.ruledit.ag_count)) {
4670 ruleset_error(LOG_ERROR, "Nation %s: government \"%s\" not found.",
4671 nation_rule_name(pnation), name);
4672 ok = FALSE;
4673 break;
4676 if (NULL != male && NULL != female) {
4677 if (gov) {
4678 (void) government_ruler_title_new(gov, pnation, male, female);
4680 } else {
4681 ruleset_error(LOG_ERROR, "%s", secfile_error());
4682 ok = FALSE;
4683 break;
4686 if (!ok) {
4687 break;
4690 /* City styles */
4691 name = secfile_lookup_str(file, "%s.style", sec_name);
4692 if (!name) {
4693 ruleset_error(LOG_ERROR, "%s", secfile_error());
4694 ok = FALSE;
4695 break;
4697 pnation->style = style_by_rule_name(name);
4698 if (pnation->style == NULL) {
4699 if (game.server.ruledit.allowed_styles == NULL
4700 || !is_on_allowed_list(name,
4701 game.server.ruledit.allowed_styles,
4702 game.server.ruledit.as_count)) {
4703 ruleset_error(LOG_ERROR, "Nation %s: Illegal style \"%s\"",
4704 nation_rule_name(pnation), name);
4705 ok = FALSE;
4706 break;
4707 } else {
4708 log_verbose("Nation %s: style \"%s\" not supported in this "
4709 "ruleset; using default.",
4710 nation_rule_name(pnation), name);
4711 pnation->style = style_by_number(0);
4715 /* Civilwar nations */
4716 vec = secfile_lookup_str_vec(file, &dim,
4717 "%s.civilwar_nations", sec_name);
4718 for (j = 0; j < dim; j++) {
4719 pconflict = nation_by_rule_name(vec[j]);
4721 /* No test for duplicate nations is performed. If there is a duplicate
4722 * entry it will just cause that nation to have an increased
4723 * probability of being chosen. */
4724 if (pconflict == pnation) {
4725 ruleset_error(LOG_ERROR, "Nation %s is its own civil war nation",
4726 nation_rule_name(pnation));
4727 ok = FALSE;
4728 break;
4729 } else if (NULL != pconflict) {
4730 nation_list_append(pnation->server.civilwar_nations, pconflict);
4731 nation_list_append(pconflict->server.parent_nations, pnation);
4732 } else {
4733 /* For nation authors, this would probably be considered an error.
4734 * But it can happen normally. The civ1 compatability ruleset only
4735 * uses the nations that were in civ1, so not all of the links will
4736 * exist. */
4737 log_verbose("Nation %s: civil war nation \"%s\" is unknown.",
4738 nation_rule_name(pnation), vec[j]);
4741 if (NULL != vec) {
4742 free(vec);
4744 if (!ok) {
4745 break;
4748 /* Load nation specific initial items */
4749 if (!lookup_tech_list(file, sec_name, "init_techs",
4750 pnation->init_techs, filename)) {
4751 ok = FALSE;
4752 break;
4754 if (!lookup_building_list(file, sec_name, "init_buildings",
4755 pnation->init_buildings, filename)) {
4756 ok = FALSE;
4757 break;
4759 if (!lookup_unit_list(file, sec_name, "init_units",
4760 pnation->init_units, filename)) {
4761 ok = FALSE;
4762 break;
4764 fc_strlcat(tmp, sec_name, 200);
4765 fc_strlcat(tmp, ".init_government", 200);
4766 if (secfile_entry_by_path(file, tmp)) {
4767 pnation->init_government = lookup_government(file, tmp, filename,
4768 NULL);
4769 /* If specified, init_government has to be in this specific ruleset,
4770 * not just allowed_govs */
4771 if (pnation->init_government == NULL) {
4772 ok = FALSE;
4773 break;
4775 /* ...but if a list of govs has been specified, enforce that this
4776 * nation's init_government is on the list. */
4777 if (game.server.ruledit.allowed_govs != NULL
4778 && !is_on_allowed_list(government_rule_name(pnation->init_government),
4779 game.server.ruledit.allowed_govs,
4780 game.server.ruledit.ag_count)) {
4781 ruleset_error(LOG_ERROR,
4782 "Nation %s: init_government \"%s\" not allowed.",
4783 nation_rule_name(pnation),
4784 government_rule_name(pnation->init_government));
4785 ok = FALSE;
4786 break;
4790 /* Read default city names. */
4791 if (!load_city_name_list(file, pnation, sec_name, "cities",
4792 game.server.ruledit.allowed_terrains,
4793 game.server.ruledit.at_count)) {
4794 ok = FALSE;
4795 break;
4798 legend = secfile_lookup_str_default(file, "", "%s.legend", sec_name);
4799 pnation->legend = fc_strdup(legend);
4800 if (check_strlen(pnation->legend, MAX_LEN_MSG, NULL)) {
4801 ruleset_error(LOG_ERROR,
4802 "Nation %s: legend \"%s\" is too long.",
4803 nation_rule_name(pnation),
4804 pnation->legend);
4805 ok = FALSE;
4806 break;
4809 pnation->player = NULL;
4810 } nations_iterate_end;
4811 section_list_destroy(sec);
4812 sec = NULL;
4815 /* Clean up on aborted load */
4816 if (sec) {
4817 fc_assert(!ok);
4818 section_list_destroy(sec);
4821 if (ok) {
4822 secfile_check_unused(file);
4825 if (ok) {
4826 /* Update cached number of playable nations in the current set */
4827 count_playable_nations();
4829 /* Sanity checks on all sets */
4830 nation_sets_iterate(pset) {
4831 int num_playable = 0, barb_land_count = 0, barb_sea_count = 0, barb_both_count = 0;
4833 nations_iterate(pnation) {
4834 if (nation_is_in_set(pnation, pset)) {
4835 switch (nation_barbarian_type(pnation)) {
4836 case NOT_A_BARBARIAN:
4837 if (is_nation_playable(pnation)) {
4838 num_playable++;
4840 break;
4841 case LAND_BARBARIAN:
4842 barb_land_count++;
4843 break;
4844 case SEA_BARBARIAN:
4845 barb_sea_count++;
4846 break;
4847 case ANIMAL_BARBARIAN:
4848 /* Animals are optional */
4849 break;
4850 case LAND_AND_SEA_BARBARIAN:
4851 barb_both_count++;
4852 break;
4853 default:
4854 fc_assert_ret_val(FALSE, FALSE);
4857 } nations_iterate_end;
4858 if (num_playable < 1) {
4859 ruleset_error(LOG_ERROR,
4860 "Nation set \"%s\" has no playable nations. "
4861 "At least one required!", nation_set_rule_name(pset));
4862 ok = FALSE;
4863 break;
4865 if (barb_land_count == 0 && barb_both_count == 0) {
4866 ruleset_error(LOG_ERROR,
4867 "No land barbarian nation defined in set \"%s\". "
4868 "At least one required!", nation_set_rule_name(pset));
4869 ok = FALSE;
4870 break;
4872 if (barb_sea_count == 0 && barb_both_count == 0) {
4873 ruleset_error(LOG_ERROR,
4874 "No sea barbarian nation defined in set \"%s\". "
4875 "At least one required!", nation_set_rule_name(pset));
4876 ok = FALSE;
4877 break;
4879 } nation_sets_iterate_end;
4882 return ok;
4885 /**************************************************************************
4886 Load names of nation styles so other rulesets can refer to styles with
4887 their name.
4888 **************************************************************************/
4889 static bool load_style_names(struct section_file *file,
4890 struct rscompat_info *compat)
4892 bool ok = TRUE;
4893 struct section_list *sec;
4894 const char *filename = secfile_name(file);
4896 compat->ver_styles = rscompat_check_capabilities(file, filename, compat);
4897 if (compat->ver_styles <= 0) {
4898 return FALSE;
4901 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
4902 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
4904 sec = secfile_sections_by_name_prefix(file, STYLE_SECTION_PREFIX);
4905 if (NULL == sec) {
4906 ruleset_error(LOG_ERROR, "No available nation styles in this ruleset!");
4907 ok = FALSE;
4908 } else {
4909 game.control.num_styles = section_list_size(sec);
4911 styles_alloc(game.control.num_styles);
4913 styles_iterate(ps) {
4914 const int i = style_index(ps);
4915 const char *sec_name = section_name(section_list_get(sec, i));
4917 ruleset_load_names(&ps->name, NULL, file, sec_name);
4918 } styles_iterate_end;
4921 section_list_destroy(sec);
4923 if (ok) {
4924 /* The citystyle sections: */
4925 int i = 0;
4927 sec = secfile_sections_by_name_prefix(file, CITYSTYLE_SECTION_PREFIX);
4928 if (NULL != sec) {
4929 city_styles_alloc(section_list_size(sec));
4930 section_list_iterate(sec, style) {
4931 if (!ruleset_load_names(&city_styles[i].name, NULL, file, section_name(style))) {
4932 ok = FALSE;
4933 break;
4935 i++;
4936 } section_list_iterate_end;
4938 section_list_destroy(sec);
4939 } else {
4940 city_styles_alloc(0);
4944 return ok;
4947 /**************************************************************************
4948 Load styles.ruleset file
4949 **************************************************************************/
4950 static bool load_ruleset_styles(struct section_file *file,
4951 struct rscompat_info *compat)
4953 struct section_list *sec;
4954 int i;
4955 bool ok = TRUE;
4957 /* City Styles ... */
4959 sec = secfile_sections_by_name_prefix(file, CITYSTYLE_SECTION_PREFIX);
4961 /* Get rest: */
4962 for (i = 0; i < game.control.styles_count; i++) {
4963 struct requirement_vector *reqs;
4964 const char *sec_name = section_name(section_list_get(sec, i));
4966 sz_strlcpy(city_styles[i].graphic,
4967 secfile_lookup_str(file, "%s.graphic", sec_name));
4968 sz_strlcpy(city_styles[i].graphic_alt,
4969 secfile_lookup_str(file, "%s.graphic_alt", sec_name));
4970 sz_strlcpy(city_styles[i].citizens_graphic,
4971 secfile_lookup_str_default(file, "-",
4972 "%s.citizens_graphic", sec_name));
4973 sz_strlcpy(city_styles[i].citizens_graphic_alt,
4974 secfile_lookup_str_default(file, "generic",
4975 "%s.citizens_graphic_alt", sec_name));
4977 reqs = lookup_req_list(file, compat, sec_name, "reqs", city_style_rule_name(i));
4978 if (reqs == NULL) {
4979 ok = FALSE;
4980 break;
4982 requirement_vector_copy(&city_styles[i].reqs, reqs);
4985 section_list_destroy(sec);
4987 if (ok) {
4988 sec = secfile_sections_by_name_prefix(file, MUSICSTYLE_SECTION_PREFIX);
4990 if (sec != NULL) {
4991 int musi;
4993 game.control.num_music_styles = section_list_size(sec);
4994 music_styles_alloc(game.control.num_music_styles);
4995 musi = 0;
4997 section_list_iterate(sec, psection) {
4998 struct requirement_vector *reqs;
4999 struct music_style *pmus = music_style_by_number(musi);
5000 const char *sec_name = section_name(psection);
5002 sz_strlcpy(pmus->music_peaceful,
5003 secfile_lookup_str_default(file, "-",
5004 "%s.music_peaceful", sec_name));
5005 sz_strlcpy(pmus->music_combat,
5006 secfile_lookup_str_default(file, "-",
5007 "%s.music_combat", sec_name));
5009 reqs = lookup_req_list(file, compat, sec_name, "reqs", "Music Style");
5010 if (reqs == NULL) {
5011 ok = FALSE;
5012 break;
5014 requirement_vector_copy(&pmus->reqs, reqs);
5016 musi++;
5017 } section_list_iterate_end;
5020 section_list_destroy(sec);
5023 return ok;
5026 /**************************************************************************
5027 Load a list of unit type flags that must be absent from the actor unit
5028 if an action auto performer should be triggered into an action auto
5029 performer.
5030 **************************************************************************/
5031 static bool load_action_auto_uflag_block(struct section_file *file,
5032 struct action_auto_perf *auto_perf,
5033 const char *uflags_path,
5034 const char *filename)
5036 /* Add each listed protected unit type flag as a !present
5037 * requirement. */
5038 if (secfile_entry_lookup(file, "%s", uflags_path)) {
5039 enum unit_type_flag_id *protecor_flag;
5040 size_t psize;
5041 int i;
5043 protecor_flag =
5044 secfile_lookup_enum_vec(file, &psize, unit_type_flag_id,
5045 "%s", uflags_path);
5047 if (!protecor_flag) {
5048 /* Entity exists but couldn't read it. */
5049 ruleset_error(LOG_ERROR,
5050 "\"%s\": %s: bad unit type flag list.",
5051 filename, uflags_path);
5053 return FALSE;
5056 for (i = 0; i < psize; i++) {
5057 requirement_vector_append(&auto_perf->reqs,
5058 req_from_values(VUT_UTFLAG,
5059 REQ_RANGE_LOCAL,
5060 FALSE, FALSE, TRUE,
5061 protecor_flag[i]));
5064 free(protecor_flag);
5067 return TRUE;
5070 /**************************************************************************
5071 Load the list of actions an action auto performer should try. The
5072 actions will be tried in the given order.
5073 **************************************************************************/
5074 static bool load_action_auto_actions(struct section_file *file,
5075 struct action_auto_perf *auto_perf,
5076 const char *actions_path,
5077 const char *filename)
5079 /* Read the alternative actions. */
5080 if (secfile_entry_lookup(file, "%s", actions_path)) {
5081 enum gen_action *unit_acts;
5082 size_t asize;
5083 int i;
5085 unit_acts = secfile_lookup_enum_vec(file, &asize, gen_action,
5086 "%s", actions_path);
5088 if (!unit_acts) {
5089 /* Entity exists but couldn't read it. */
5090 ruleset_error(LOG_ERROR,
5091 "\"%s\": %s: bad action list",
5092 filename, actions_path);
5094 return FALSE;
5097 for (i = 0; i < asize; i++) {
5098 auto_perf->alternatives[i] = unit_acts[i];
5101 free(unit_acts);
5104 return TRUE;
5107 /**************************************************************************
5108 Load missing unit upkeep ruleset settings as action auto performers.
5109 **************************************************************************/
5110 static bool load_muuk_as_action_auto(struct section_file *file,
5111 struct action_auto_perf *auto_perf,
5112 const char *item,
5113 const char *filename)
5115 char uflags_path[100];
5116 char action_path[100];
5118 fc_snprintf(uflags_path, sizeof(uflags_path),
5119 "missing_unit_upkeep.%s_protected", item);
5120 fc_snprintf(action_path, sizeof(action_path),
5121 "missing_unit_upkeep.%s_unit_act", item);
5123 return (load_action_auto_uflag_block(file, auto_perf, uflags_path,
5124 filename)
5125 && load_action_auto_actions(file, auto_perf, action_path,
5126 filename));
5129 /**************************************************************************
5130 Load cities.ruleset file
5131 **************************************************************************/
5132 static bool load_ruleset_cities(struct section_file *file,
5133 struct rscompat_info *compat)
5135 const char *filename = secfile_name(file);
5136 const char *item;
5137 struct section_list *sec;
5138 bool ok = TRUE;
5140 compat->ver_cities = rscompat_check_capabilities(file, filename, compat);
5141 if (compat->ver_cities <= 0) {
5142 return FALSE;
5145 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
5146 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
5148 /* Specialist options */
5149 sec = secfile_sections_by_name_prefix(file, SPECIALIST_SECTION_PREFIX);
5150 if (section_list_size(sec) >= SP_MAX) {
5151 ruleset_error(LOG_ERROR, "\"%s\": Too many specialists (%d, max %d).",
5152 filename, section_list_size(sec), SP_MAX);
5153 ok = FALSE;
5156 if (ok) {
5157 int i = 0;
5159 game.control.num_specialist_types = section_list_size(sec);
5161 section_list_iterate(sec, psection) {
5162 struct specialist *s = specialist_by_number(i);
5163 struct requirement_vector *reqs;
5164 const char *sec_name = section_name(psection);
5166 if (!ruleset_load_names(&s->name, NULL, file, sec_name)) {
5167 ok = FALSE;
5168 break;
5171 item = secfile_lookup_str_default(file, untranslated_name(&s->name),
5172 "%s.short_name", sec_name);
5173 name_set(&s->abbreviation, NULL, item);
5175 sz_strlcpy(s->graphic_alt,
5176 secfile_lookup_str_default(file, "-",
5177 "%s.graphic_alt", sec_name));
5179 reqs = lookup_req_list(file, compat, sec_name, "reqs", specialist_rule_name(s));
5180 if (reqs == NULL) {
5181 ok = FALSE;
5182 break;
5184 requirement_vector_copy(&s->reqs, reqs);
5186 s->helptext = lookup_strvec(file, sec_name, "helptext");
5188 if (requirement_vector_size(&s->reqs) == 0 && DEFAULT_SPECIALIST == -1) {
5189 DEFAULT_SPECIALIST = i;
5191 i++;
5192 } section_list_iterate_end;
5195 if (ok && DEFAULT_SPECIALIST == -1) {
5196 ruleset_error(LOG_ERROR,
5197 "\"%s\": must give a min_size of 0 for at least one "
5198 "specialist type.", filename);
5199 ok = FALSE;
5201 section_list_destroy(sec);
5202 sec = NULL;
5204 if (ok) {
5205 /* City Parameters */
5207 game.info.celebratesize =
5208 secfile_lookup_int_default(file, GAME_DEFAULT_CELEBRATESIZE,
5209 "parameters.celebrate_size_limit");
5210 game.info.add_to_size_limit =
5211 secfile_lookup_int_default(file, GAME_DEFAULT_ADDTOSIZE, "parameters.add_to_size_limit");
5212 game.info.angrycitizen =
5213 secfile_lookup_bool_default(file, GAME_DEFAULT_ANGRYCITIZEN,
5214 "parameters.angry_citizens");
5216 game.info.changable_tax =
5217 secfile_lookup_bool_default(file, GAME_DEFAULT_CHANGABLE_TAX, "parameters.changable_tax");
5218 game.info.forced_science =
5219 secfile_lookup_int_default(file, 0, "parameters.forced_science");
5220 game.info.forced_luxury =
5221 secfile_lookup_int_default(file, 100, "parameters.forced_luxury");
5222 game.info.forced_gold =
5223 secfile_lookup_int_default(file, 0, "parameters.forced_gold");
5224 if (game.info.forced_science + game.info.forced_luxury
5225 + game.info.forced_gold != 100) {
5226 ruleset_error(LOG_ERROR,
5227 "\"%s\": Forced taxes do not add up in ruleset!",
5228 filename);
5229 ok = FALSE;
5233 if (ok) {
5234 /* civ1 & 2 didn't reveal tiles */
5235 game.server.vision_reveal_tiles =
5236 secfile_lookup_bool_default(file, GAME_DEFAULT_VISION_REVEAL_TILES,
5237 "parameters.vision_reveal_tiles");
5239 game.info.pop_report_zeroes =
5240 secfile_lookup_int_default(file, 1, "parameters.pop_report_zeroes");
5242 /* Citizens configuration. */
5243 game.info.citizen_nationality =
5244 secfile_lookup_bool_default(file, GAME_DEFAULT_NATIONALITY,
5245 "citizen.nationality");
5246 game.info.citizen_convert_speed =
5247 secfile_lookup_int_default(file, GAME_DEFAULT_CONVERT_SPEED,
5248 "citizen.convert_speed");
5249 game.info.citizen_partisans_pct =
5250 secfile_lookup_int_default(file, 0, "citizen.partisans_pct");
5253 if (ok) {
5254 /* Missing unit upkeep. */
5255 struct action_auto_perf *auto_perf;
5257 /* Can't pay food upkeep! */
5258 auto_perf = action_auto_perf_slot_number(ACTION_AUTO_UPKEEP_FOOD);
5259 auto_perf->cause = AAPC_UNIT_UPKEEP;
5261 /* This is about food upkeep. */
5262 requirement_vector_append(&auto_perf->reqs,
5263 req_from_str("OutputType", "Local",
5264 FALSE, TRUE, TRUE,
5265 "Food"));
5267 /* Internally represented as an action auto performer rule. */
5268 if (!load_muuk_as_action_auto(file, auto_perf, "food", filename)) {
5269 ok = FALSE;
5272 game.info.muuk_food_wipe =
5273 secfile_lookup_bool_default(file, RS_DEFAULT_MUUK_FOOD_WIPE,
5274 "missing_unit_upkeep.food_wipe");
5276 /* Can't pay gold upkeep! */
5277 auto_perf = action_auto_perf_slot_number(ACTION_AUTO_UPKEEP_GOLD);
5278 auto_perf->cause = AAPC_UNIT_UPKEEP;
5280 /* This is about gold upkeep. */
5281 requirement_vector_append(&auto_perf->reqs,
5282 req_from_str("OutputType", "Local",
5283 FALSE, TRUE, TRUE,
5284 "Gold"));
5286 /* Internally represented as an action auto performer rule. */
5287 if (!load_muuk_as_action_auto(file, auto_perf, "gold", filename)) {
5288 ok = FALSE;
5291 game.info.muuk_gold_wipe =
5292 secfile_lookup_bool_default(file, RS_DEFAULT_MUUK_GOLD_WIPE,
5293 "missing_unit_upkeep.gold_wipe");
5295 /* Can't pay shield upkeep! */
5296 auto_perf = action_auto_perf_slot_number(ACTION_AUTO_UPKEEP_SHIELD);
5297 auto_perf->cause = AAPC_UNIT_UPKEEP;
5299 /* This is about shield upkeep. */
5300 requirement_vector_append(&auto_perf->reqs,
5301 req_from_str("OutputType", "Local",
5302 FALSE, TRUE, TRUE,
5303 "Shield"));
5305 /* Internally represented as an action auto performer rule. */
5306 if (!load_muuk_as_action_auto(file, auto_perf, "shield", filename)) {
5307 ok = FALSE;
5310 game.info.muuk_shield_wipe =
5311 secfile_lookup_bool_default(file, RS_DEFAULT_MUUK_SHIELD_WIPE,
5312 "missing_unit_upkeep.shield_wipe");
5315 if (ok) {
5316 secfile_check_unused(file);
5319 return ok;
5322 /**************************************************************************
5323 Load effects.ruleset file
5324 **************************************************************************/
5325 static bool load_ruleset_effects(struct section_file *file,
5326 struct rscompat_info *compat)
5328 struct section_list *sec;
5329 const char *type;
5330 const char *filename;
5331 bool ok = TRUE;
5332 bool effect_type_warned = FALSE;
5334 filename = secfile_name(file);
5336 compat->ver_effects = rscompat_check_capabilities(file, filename, compat);
5337 if (compat->ver_effects <= 0) {
5338 return FALSE;
5340 (void) secfile_entry_by_path(file, "datafile.description"); /* unused */
5341 (void) secfile_entry_by_path(file, "datafile.ruledit"); /* unused */
5343 /* Parse effects and add them to the effects ruleset cache. */
5344 sec = secfile_sections_by_name_prefix(file, EFFECT_SECTION_PREFIX);
5345 section_list_iterate(sec, psection) {
5346 enum effect_type eff;
5347 int value;
5348 struct multiplier *pmul;
5349 struct effect *peffect;
5350 const char *sec_name = section_name(psection);
5351 struct requirement_vector *reqs;
5353 type = secfile_lookup_str(file, "%s.type", sec_name);
5354 if (type == NULL && compat->compat_mode) {
5355 /* Backward compatibility. Field used to be named "name" */
5356 type = secfile_lookup_str(file, "%s.name", sec_name);
5357 if (type != NULL && !effect_type_warned) {
5358 log_deprecation(_("Effects should have \"type\", not the same field with old name \"name\"."));
5359 effect_type_warned = TRUE;
5362 if (type == NULL) {
5363 ruleset_error(LOG_ERROR, "\"%s\" [%s] missing effect type.", filename, sec_name);
5364 ok = FALSE;
5365 break;
5368 eff = effect_type_by_name(type, fc_strcasecmp);
5369 if (!effect_type_is_valid(eff)) {
5370 ruleset_error(LOG_ERROR, "\"%s\" [%s] lists unknown effect type \"%s\".",
5371 filename, sec_name, type);
5372 ok = FALSE;
5373 break;
5376 value = secfile_lookup_int_default(file, 1, "%s.value", sec_name);
5379 const char *multiplier_name
5380 = secfile_lookup_str(file, "%s.multiplier", sec_name);
5382 if (multiplier_name) {
5383 pmul = multiplier_by_rule_name(multiplier_name);
5384 if (!pmul) {
5385 ruleset_error(LOG_ERROR, "\"%s\" [%s] has unknown multiplier \"%s\".",
5386 filename, sec_name, multiplier_name);
5387 ok = FALSE;
5388 break;
5390 } else {
5391 pmul = NULL;
5395 peffect = effect_new(eff, value, pmul);
5397 reqs = lookup_req_list(file, compat, sec_name, "reqs", type);
5398 if (reqs == NULL) {
5399 ok = FALSE;
5400 break;
5403 requirement_vector_iterate(reqs, preq) {
5404 effect_req_append(peffect, *preq);
5405 } requirement_vector_iterate_end;
5407 if (compat->compat_mode) {
5408 reqs = lookup_req_list(file, compat, sec_name, "nreqs", type);
5409 if (reqs == NULL) {
5410 ok = FALSE;
5411 break;
5413 requirement_vector_iterate(reqs, preq) {
5414 preq->present = !preq->present;
5415 effect_req_append(peffect, *preq);
5416 } requirement_vector_iterate_end;
5418 } section_list_iterate_end;
5419 section_list_destroy(sec);
5421 if (ok) {
5422 secfile_check_unused(file);
5425 return ok;
5428 /**************************************************************************
5429 Print an error message if the value is out of range.
5430 **************************************************************************/
5431 static int secfile_lookup_int_default_min_max(struct section_file *file,
5432 int def, int min, int max,
5433 const char *path, ...)
5434 fc__attribute((__format__ (__printf__, 5, 6)));
5435 static int secfile_lookup_int_default_min_max(struct section_file *file,
5436 int def, int min, int max,
5437 const char *path, ...)
5439 char fullpath[256];
5440 int ival;
5441 va_list args;
5443 va_start(args, path);
5444 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
5445 va_end(args);
5447 if (!secfile_lookup_int(file, &ival, "%s", fullpath)) {
5448 ival = def;
5451 if (ival < min) {
5452 ruleset_error(LOG_ERROR,"\"%s\" should be in the interval [%d, %d] "
5453 "but is %d; using the minimal value.",
5454 fullpath, min, max, ival);
5455 ival = min;
5458 if (ival > max) {
5459 ruleset_error(LOG_ERROR,"\"%s\" should be in the interval [%d, %d] "
5460 "but is %d; using the maximal value.",
5461 fullpath, min, max, ival);
5462 ival = max;
5465 return ival;
5468 /**************************************************************************
5469 Load ruleset file.
5470 **************************************************************************/
5471 static bool load_ruleset_game(struct section_file *file, bool act,
5472 struct rscompat_info *compat)
5474 const char *sval, **svec;
5475 const char *filename;
5476 int *food_ini;
5477 int i;
5478 size_t teams;
5479 const char *pref_text;
5480 size_t gni_tmp;
5481 struct section_list *sec;
5482 size_t nval;
5483 const char *name;
5484 bool ok = TRUE;
5486 if (file == NULL) {
5487 return FALSE;
5489 filename = secfile_name(file);
5491 name = secfile_lookup_str_default(file, NULL, "ruledit.description_file");
5492 if (name != NULL) {
5493 game.server.ruledit.description_file = fc_strdup(name);
5496 /* section: tileset */
5497 pref_text = secfile_lookup_str_default(file, "", "tileset.prefered");
5498 if (pref_text[0] != '\0') {
5499 log_deprecation("Entry tileset.prefered in game.ruleset."
5500 " Use correct spelling tileset.preferred instead");
5502 pref_text = secfile_lookup_str_default(file, pref_text, "tileset.preferred");
5503 if (pref_text[0] != '\0') {
5504 /* There was tileset suggestion */
5505 sz_strlcpy(game.control.preferred_tileset, pref_text);
5506 } else {
5507 /* No tileset suggestions */
5508 game.control.preferred_tileset[0] = '\0';
5511 /* section: soundset */
5512 pref_text = secfile_lookup_str_default(file, "", "soundset.prefered");
5513 if (pref_text[0] != '\0') {
5514 log_deprecation("Entry soundset.prefered in game.ruleset."
5515 " Use correct spelling soundset.preferred instead");
5517 pref_text = secfile_lookup_str_default(file, pref_text, "soundset.preferred");
5518 if (pref_text[0] != '\0') {
5519 /* There was soundset suggestion */
5520 sz_strlcpy(game.control.preferred_soundset, pref_text);
5521 } else {
5522 /* No soundset suggestions */
5523 game.control.preferred_soundset[0] = '\0';
5526 /* section: musicset */
5527 pref_text = secfile_lookup_str_default(file, "", "musicset.prefered");
5528 if (pref_text[0] != '\0') {
5529 log_deprecation("Entry musicset.prefered in game.ruleset."
5530 " Use correct spelling musicset.preferred instead");
5532 pref_text = secfile_lookup_str_default(file, pref_text, "musicset.preferred");
5533 if (pref_text[0] != '\0') {
5534 /* There was musicset suggestion */
5535 sz_strlcpy(game.control.preferred_musicset, pref_text);
5536 } else {
5537 /* No musicset suggestions */
5538 game.control.preferred_musicset[0] = '\0';
5541 /* section: about */
5542 pref_text = secfile_lookup_str(file, "about.name");
5543 /* Ruleset/modpack name found */
5544 sz_strlcpy(game.control.name, pref_text);
5546 pref_text = secfile_lookup_str_default(file, "", "about.version");
5547 if (pref_text[0] != '\0') {
5548 /* Ruleset/modpack version found */
5549 sz_strlcpy(game.control.version, pref_text);
5550 } else {
5551 /* No version information */
5552 game.control.version[0] = '\0';
5555 pref_text = secfile_lookup_str_default(file, "", "about.summary");
5556 if (pref_text[0] != '\0') {
5557 int len;
5559 /* Ruleset/modpack summary found */
5560 len = strlen(pref_text);
5561 game.ruleset_summary = fc_malloc(len + 1);
5562 fc_strlcpy(game.ruleset_summary, pref_text, len + 1);
5563 } else {
5564 /* No summary */
5565 if (game.ruleset_summary != NULL) {
5566 free(game.ruleset_summary);
5567 game.ruleset_summary = NULL;
5571 pref_text = secfile_lookup_str_default(file, "", "about.description");
5572 if (pref_text[0] != '\0') {
5573 int len;
5575 /* Ruleset/modpack description found */
5576 len = strlen(pref_text);
5577 game.ruleset_description = fc_malloc(len + 1);
5578 fc_strlcpy(game.ruleset_description, pref_text, len + 1);
5579 game.control.desc_length = len;
5580 } else {
5581 /* No description */
5582 if (game.ruleset_description != NULL) {
5583 free(game.ruleset_description);
5584 game.ruleset_description = NULL;
5586 game.control.desc_length = 0;
5589 /* section: options */
5590 if (!lookup_tech_list(file, "options", "global_init_techs",
5591 game.rgame.global_init_techs, filename)) {
5592 ok = FALSE;
5595 if (ok) {
5596 if (!lookup_building_list(file, "options", "global_init_buildings",
5597 game.rgame.global_init_buildings, filename)) {
5598 ok = FALSE;
5602 if (ok) {
5603 const char **slist;
5604 int j;
5606 game.control.popup_tech_help = secfile_lookup_bool_default(file, FALSE,
5607 "options.popup_tech_help");
5609 /* section: civstyle */
5610 game.info.base_pollution
5611 = secfile_lookup_int_default(file, RS_DEFAULT_BASE_POLLUTION,
5612 "civstyle.base_pollution");
5614 game.info.gameloss_style = GAMELOSS_STYLE_CLASSICAL;
5616 slist = secfile_lookup_str_vec(file, &nval, "civstyle.gameloss_style");
5617 for (j = 0; j < nval; j++) {
5618 enum gameloss_style style;
5620 sval = slist[j];
5621 if (strcmp(sval, "") == 0) {
5622 continue;
5624 style = gameloss_style_by_name(sval, fc_strcasecmp);
5625 if (!gameloss_style_is_valid(style)) {
5626 ruleset_error(LOG_ERROR, "\"%s\": bad value \"%s\" for gameloss_style.",
5627 filename, sval);
5628 ok = FALSE;
5629 break;
5630 } else {
5631 game.info.gameloss_style |= style;
5634 free(slist);
5637 if (ok) {
5638 game.info.happy_cost
5639 = secfile_lookup_int_def_min_max(file,
5640 RS_DEFAULT_HAPPY_COST,
5641 RS_MIN_HAPPY_COST,
5642 RS_MAX_HAPPY_COST,
5643 "civstyle.happy_cost");
5644 game.info.food_cost
5645 = secfile_lookup_int_default_min_max(file,
5646 RS_DEFAULT_FOOD_COST,
5647 RS_MIN_FOOD_COST,
5648 RS_MAX_FOOD_COST,
5649 "civstyle.food_cost");
5650 game.info.civil_war_enabled
5651 = secfile_lookup_bool_default(file, TRUE, "civstyle.civil_war_enabled");
5653 game.info.paradrop_to_transport
5654 = secfile_lookup_bool_default(file, FALSE,
5655 "civstyle.paradrop_to_transport");
5657 /* TODO: move to global_unit_options */
5658 game.info.base_bribe_cost
5659 = secfile_lookup_int_default_min_max(file,
5660 RS_DEFAULT_BASE_BRIBE_COST,
5661 RS_MIN_BASE_BRIBE_COST,
5662 RS_MAX_BASE_BRIBE_COST,
5663 "civstyle.base_bribe_cost");
5664 /* TODO: move to global_unit_options */
5665 game.server.ransom_gold
5666 = secfile_lookup_int_default_min_max(file,
5667 RS_DEFAULT_RANSOM_GOLD,
5668 RS_MIN_RANSOM_GOLD,
5669 RS_MAX_RANSOM_GOLD,
5670 "civstyle.ransom_gold");
5671 /* TODO: move to global_unit_options */
5672 game.info.pillage_select
5673 = secfile_lookup_bool_default(file, RS_DEFAULT_PILLAGE_SELECT,
5674 "civstyle.pillage_select");
5676 game.info.tech_steal_allow_holes
5677 = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_STEAL_HOLES,
5678 "civstyle.tech_steal_allow_holes");
5679 game.info.tech_trade_allow_holes
5680 = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_TRADE_HOLES,
5681 "civstyle.tech_trade_allow_holes");
5682 game.info.tech_trade_loss_allow_holes
5683 = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_TRADE_LOSS_HOLES,
5684 "civstyle.tech_trade_loss_allow_holes");
5685 game.info.tech_parasite_allow_holes
5686 = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_PARASITE_HOLES,
5687 "civstyle.tech_parasite_allow_holes");
5688 game.info.tech_loss_allow_holes
5689 = secfile_lookup_bool_default(file, RS_DEFAULT_TECH_LOSS_HOLES,
5690 "civstyle.tech_loss_allow_holes");
5692 /* TODO: move to global_unit_options */
5693 game.server.upgrade_veteran_loss
5694 = secfile_lookup_int_default_min_max(file,
5695 RS_DEFAULT_UPGRADE_VETERAN_LOSS,
5696 RS_MIN_UPGRADE_VETERAN_LOSS,
5697 RS_MAX_UPGRADE_VETERAN_LOSS,
5698 "civstyle.upgrade_veteran_loss");
5699 /* TODO: move to global_unit_options */
5700 game.server.autoupgrade_veteran_loss
5701 = secfile_lookup_int_default_min_max(file,
5702 RS_DEFAULT_UPGRADE_VETERAN_LOSS,
5703 RS_MIN_UPGRADE_VETERAN_LOSS,
5704 RS_MAX_UPGRADE_VETERAN_LOSS,
5705 "civstyle.autoupgrade_veteran_loss");
5707 game.info.base_tech_cost
5708 = secfile_lookup_int_default_min_max(file,
5709 RS_DEFAULT_BASE_TECH_COST,
5710 RS_MIN_BASE_TECH_COST,
5711 RS_MAX_BASE_TECH_COST,
5712 "research.base_tech_cost");
5714 food_ini = secfile_lookup_int_vec(file, &gni_tmp,
5715 "civstyle.granary_food_ini");
5716 game.info.granary_num_inis = (int) gni_tmp;
5718 if (game.info.granary_num_inis > MAX_GRANARY_INIS) {
5719 ruleset_error(LOG_ERROR,
5720 "Too many granary_food_ini entries (%d, max %d)",
5721 game.info.granary_num_inis, MAX_GRANARY_INIS);
5722 ok = FALSE;
5723 } else if (game.info.granary_num_inis == 0) {
5724 log_error("No values for granary_food_ini. Using default "
5725 "value %d.", RS_DEFAULT_GRANARY_FOOD_INI);
5726 game.info.granary_num_inis = 1;
5727 game.info.granary_food_ini[0] = RS_DEFAULT_GRANARY_FOOD_INI;
5728 } else {
5729 int gi;
5731 /* check for <= 0 entries */
5732 for (gi = 0; gi < game.info.granary_num_inis; gi++) {
5733 if (food_ini[gi] <= 0) {
5734 if (gi == 0) {
5735 food_ini[gi] = RS_DEFAULT_GRANARY_FOOD_INI;
5736 } else {
5737 food_ini[gi] = food_ini[gi - 1];
5739 log_error("Bad value for granary_food_ini[%i]. Using %i.",
5740 gi, food_ini[gi]);
5742 game.info.granary_food_ini[gi] = food_ini[gi];
5745 free(food_ini);
5748 if (ok) {
5749 game.info.granary_food_inc
5750 = secfile_lookup_int_default_min_max(file,
5751 RS_DEFAULT_GRANARY_FOOD_INC,
5752 RS_MIN_GRANARY_FOOD_INC,
5753 RS_MAX_GRANARY_FOOD_INC,
5754 "civstyle.granary_food_inc");
5756 output_type_iterate(o) {
5757 game.info.min_city_center_output[o]
5758 = secfile_lookup_int_default_min_max(file,
5759 RS_DEFAULT_CITY_CENTER_OUTPUT,
5760 RS_MIN_CITY_CENTER_OUTPUT,
5761 RS_MAX_CITY_CENTER_OUTPUT,
5762 "civstyle.min_city_center_%s",
5763 get_output_identifier(o));
5764 } output_type_iterate_end;
5767 if (ok) {
5768 const char *tus_text;
5770 game.server.init_vis_radius_sq
5771 = secfile_lookup_int_default_min_max(file,
5772 RS_DEFAULT_VIS_RADIUS_SQ,
5773 RS_MIN_VIS_RADIUS_SQ,
5774 RS_MAX_VIS_RADIUS_SQ,
5775 "civstyle.init_vis_radius_sq");
5777 game.info.init_city_radius_sq
5778 = secfile_lookup_int_default_min_max(file,
5779 RS_DEFAULT_CITY_RADIUS_SQ,
5780 RS_MIN_CITY_RADIUS_SQ,
5781 RS_MAX_CITY_RADIUS_SQ,
5782 "civstyle.init_city_radius_sq");
5784 tus_text = secfile_lookup_str_default(file, RS_DEFAULT_GOLD_UPKEEP_STYLE,
5785 "civstyle.gold_upkeep_style");
5786 game.info.gold_upkeep_style = gold_upkeep_style_by_name(tus_text,
5787 fc_strcasecmp);
5788 if (!gold_upkeep_style_is_valid(game.info.gold_upkeep_style)) {
5789 ruleset_error(LOG_ERROR, "Unknown gold upkeep style \"%s\"",
5790 tus_text);
5791 ok = FALSE;
5794 /* section: illness */
5795 game.info.illness_on
5796 = secfile_lookup_bool_default(file, RS_DEFAULT_ILLNESS_ON,
5797 "illness.illness_on");
5798 game.info.illness_base_factor
5799 = secfile_lookup_int_default_min_max(file,
5800 RS_DEFAULT_ILLNESS_BASE_FACTOR,
5801 RS_MIN_ILLNESS_BASE_FACTOR,
5802 RS_MAX_ILLNESS_BASE_FACTOR,
5803 "illness.illness_base_factor");
5804 game.info.illness_min_size
5805 = secfile_lookup_int_default_min_max(file,
5806 RS_DEFAULT_ILLNESS_MIN_SIZE,
5807 RS_MIN_ILLNESS_MIN_SIZE,
5808 RS_MAX_ILLNESS_MIN_SIZE,
5809 "illness.illness_min_size");
5810 game.info.illness_trade_infection
5811 = secfile_lookup_int_default_min_max(file,
5812 RS_DEFAULT_ILLNESS_TRADE_INFECTION_PCT,
5813 RS_MIN_ILLNESS_TRADE_INFECTION_PCT,
5814 RS_MAX_ILLNESS_TRADE_INFECTION_PCT,
5815 "illness.illness_trade_infection");
5816 game.info.illness_pollution_factor
5817 = secfile_lookup_int_default_min_max(file,
5818 RS_DEFAULT_ILLNESS_POLLUTION_PCT,
5819 RS_MIN_ILLNESS_POLLUTION_PCT,
5820 RS_MAX_ILLNESS_POLLUTION_PCT,
5821 "illness.illness_pollution_factor");
5823 /* section: incite_cost */
5824 game.server.base_incite_cost
5825 = secfile_lookup_int_default_min_max(file,
5826 RS_DEFAULT_INCITE_BASE_COST,
5827 RS_MIN_INCITE_BASE_COST,
5828 RS_MAX_INCITE_BASE_COST,
5829 "incite_cost.base_incite_cost");
5830 game.server.incite_improvement_factor
5831 = secfile_lookup_int_default_min_max(file,
5832 RS_DEFAULT_INCITE_IMPROVEMENT_FCT,
5833 RS_MIN_INCITE_IMPROVEMENT_FCT,
5834 RS_MAX_INCITE_IMPROVEMENT_FCT,
5835 "incite_cost.improvement_factor");
5836 game.server.incite_unit_factor
5837 = secfile_lookup_int_default_min_max(file,
5838 RS_DEFAULT_INCITE_UNIT_FCT,
5839 RS_MIN_INCITE_UNIT_FCT,
5840 RS_MAX_INCITE_UNIT_FCT,
5841 "incite_cost.unit_factor");
5842 game.server.incite_total_factor
5843 = secfile_lookup_int_default_min_max(file,
5844 RS_DEFAULT_INCITE_TOTAL_FCT,
5845 RS_MIN_INCITE_TOTAL_FCT,
5846 RS_MAX_INCITE_TOTAL_FCT,
5847 "incite_cost.total_factor");
5849 /* section: global_unit_options */
5850 game.info.slow_invasions
5851 = secfile_lookup_bool_default(file, RS_DEFAULT_SLOW_INVASIONS,
5852 "global_unit_options.slow_invasions");
5854 if (ok) {
5855 /* Auto attack. */
5856 struct action_auto_perf *auto_perf;
5858 /* A unit moved next to this unit and the autoattack server setting
5859 * is enabled. */
5860 auto_perf = action_auto_perf_slot_number(ACTION_AUTO_MOVED_ADJ);
5861 auto_perf->cause = AAPC_UNIT_MOVED_ADJ;
5863 /* Auto attack happens during war. */
5864 requirement_vector_append(&auto_perf->reqs,
5865 req_from_values(VUT_DIPLREL,
5866 REQ_RANGE_LOCAL,
5867 FALSE, TRUE, TRUE, DS_WAR));
5869 /* Needs a movement point to auto attack. */
5870 requirement_vector_append(&auto_perf->reqs,
5871 req_from_values(VUT_MINMOVES,
5872 REQ_RANGE_LOCAL,
5873 FALSE, TRUE, TRUE, 1));
5875 /* Internally represented as an action auto performer rule. */
5876 if (!load_action_auto_uflag_block(file, auto_perf,
5877 "auto_attack.will_never",
5878 filename)) {
5879 ok = FALSE;
5882 /* TODO: It would be great if unit_survive_autoattack() could be made
5883 * flexible enough to also handle diplomatic actions etc. */
5884 auto_perf->alternatives[0] = ACTION_CAPTURE_UNITS;
5885 auto_perf->alternatives[1] = ACTION_BOMBARD;
5886 auto_perf->alternatives[2] = ACTION_ATTACK;
5889 /* section: actions */
5890 if (ok) {
5891 const char *text;
5892 int force_capture_units, force_bombard, force_explode_nuclear;
5894 if (secfile_lookup_bool_default(file, RS_DEFAULT_FORCE_TRADE_ROUTE,
5895 "actions.force_trade_route")) {
5896 /* Forbid entering the marketplace when a trade route can be
5897 * established. */
5898 BV_SET(action_by_number(ACTION_MARKETPLACE)->blocked_by,
5899 ACTION_TRADE_ROUTE);
5902 /* Forbid bombarding, exploading nuclear or attacking when it is
5903 * legal to capture units. */
5904 force_capture_units
5905 = secfile_lookup_bool_default(file, RS_DEFAULT_FORCE_CAPTURE_UNITS,
5906 "actions.force_capture_units");
5908 if (force_capture_units) {
5909 BV_SET(action_by_number(ACTION_BOMBARD)->blocked_by,
5910 ACTION_CAPTURE_UNITS);
5911 BV_SET(action_by_number(ACTION_NUKE)->blocked_by,
5912 ACTION_CAPTURE_UNITS);
5913 BV_SET(action_by_number(ACTION_ATTACK)->blocked_by,
5914 ACTION_CAPTURE_UNITS);
5915 BV_SET(action_by_number(ACTION_CONQUER_CITY)->blocked_by,
5916 ACTION_CAPTURE_UNITS);
5919 /* Forbid exploding nuclear or attacking when it is legal to
5920 * bombard. */
5921 force_bombard
5922 = secfile_lookup_bool_default(file, RS_DEFAULT_FORCE_BOMBARD,
5923 "actions.force_bombard");
5925 if (force_bombard) {
5926 BV_SET(action_by_number(ACTION_NUKE)->blocked_by,
5927 ACTION_BOMBARD);
5928 BV_SET(action_by_number(ACTION_ATTACK)->blocked_by,
5929 ACTION_BOMBARD);
5930 BV_SET(action_by_number(ACTION_CONQUER_CITY)->blocked_by,
5931 ACTION_BOMBARD);
5934 /* Forbid attacking when it is legal to do explode nuclear. */
5935 force_explode_nuclear
5936 = secfile_lookup_bool_default(file,
5937 RS_DEFAULT_FORCE_EXPLODE_NUCLEAR,
5938 "actions.force_explode_nuclear");
5940 if (force_explode_nuclear) {
5941 BV_SET(action_by_number(ACTION_ATTACK)->blocked_by,
5942 ACTION_NUKE);
5943 BV_SET(action_by_number(ACTION_CONQUER_CITY)->blocked_by,
5944 ACTION_NUKE);
5947 /* If the poison city action should empty the granary. */
5948 /* TODO: empty granary and reduce population should become separate
5949 * action effect flags when actions are generalized. */
5950 game.info.poison_empties_food_stock
5951 = secfile_lookup_bool_default(file,
5952 RS_DEFAULT_POISON_EMPTIES_FOOD_STOCK,
5953 "actions.poison_empties_food_stock");
5955 /* Allow setting max distance for bombardment before generalized
5956 * actions. */
5958 struct entry *pentry;
5959 int max_range;
5961 pentry = secfile_entry_lookup(file, "actions.bombard_max_range");
5963 if (!pentry) {
5964 max_range = RS_DEFAULT_BOMBARD_MAX_RANGE;
5965 } else {
5966 switch (entry_type(pentry)) {
5967 case ENTRY_INT:
5968 if (entry_int_get(pentry, &max_range)) {
5969 break;
5971 /* Fall through to error handling. */
5972 case ENTRY_STR:
5974 const char *custom;
5976 if (entry_str_get(pentry, &custom)
5977 && !fc_strcasecmp(custom, RS_ACTION_NO_MAX_DISTANCE)) {
5978 max_range = ACTION_DISTANCE_UNLIMITED;
5979 break;
5982 /* Fall through to error handling. */
5983 default:
5984 ruleset_error(LOG_ERROR, "Bad actions.bombard_max_range");
5985 ok = FALSE;
5986 max_range = RS_DEFAULT_BOMBARD_MAX_RANGE;
5987 break;
5991 action_by_number(ACTION_BOMBARD)->max_distance = max_range;
5994 text = secfile_lookup_str_default(file,
5995 /* TRANS: _Poison City (3% chance of success). */
5996 N_("%sPoison City%s"),
5997 "actions.ui_name_poison_city");
5998 sz_strlcpy(action_by_number(ACTION_SPY_POISON)->ui_name,
5999 text);
6001 text = secfile_lookup_str_default(file,
6002 /* TRANS: S_abotage Enemy Unit (3% chance of success). */
6003 N_("S%sabotage Enemy Unit%s"),
6004 "actions.ui_name_sabotage_unit");
6005 sz_strlcpy(action_by_number(ACTION_SPY_SABOTAGE_UNIT)->ui_name,
6006 text);
6008 text = secfile_lookup_str_default(file,
6009 /* TRANS: Bribe Enemy _Unit (3% chance of success). */
6010 N_("Bribe Enemy %sUnit%s"),
6011 "actions.ui_name_bribe_unit");
6012 sz_strlcpy(action_by_number(ACTION_SPY_BRIBE_UNIT)->ui_name,
6013 text);
6015 text = secfile_lookup_str_default(file,
6016 /* TRANS: _Sabotage City (3% chance of success). */
6017 N_("%sSabotage City%s"),
6018 "actions.ui_name_sabotage_city");
6019 sz_strlcpy(action_by_number(ACTION_SPY_SABOTAGE_CITY)->ui_name,
6020 text);
6022 text = secfile_lookup_str_default(file,
6023 /* TRANS: Industria_l Sabotage (3% chance of success). */
6024 N_("Industria%sl Sabotage%s"),
6025 "actions.ui_name_targeted_sabotage_city");
6026 sz_strlcpy(
6027 action_by_number(ACTION_SPY_TARGETED_SABOTAGE_CITY)->ui_name,
6028 text);
6030 text = secfile_lookup_str_default(file,
6031 /* TRANS: Incite a Re_volt (3% chance of success). */
6032 N_("Incite a Re%svolt%s"),
6033 "actions.ui_name_incite_city");
6034 sz_strlcpy(action_by_number(ACTION_SPY_INCITE_CITY)->ui_name,
6035 text);
6037 text = secfile_lookup_str_default(file,
6038 /* TRANS: Establish _Embassy (100% chance of success). */
6039 N_("Establish %sEmbassy%s"),
6040 "actions.ui_name_establish_embassy");
6041 sz_strlcpy(action_by_number(ACTION_ESTABLISH_EMBASSY)->ui_name,
6042 text);
6044 text = secfile_lookup_str_default(file,
6045 /* TRANS: Establish _Embassy (and stay) (100% chance of success). */
6046 N_("Establish %sEmbassy (and stay)%s"),
6047 "actions.ui_name_establish_embassy_stay");
6048 sz_strlcpy(action_by_number(ACTION_ESTABLISH_EMBASSY_STAY)->ui_name,
6049 text);
6051 text = secfile_lookup_str_default(file,
6052 /* TRANS: Steal _Technology (3% chance of success). */
6053 N_("Steal %sTechnology%s"),
6054 "actions.ui_name_steal_tech");
6055 sz_strlcpy(action_by_number(ACTION_SPY_STEAL_TECH)->ui_name,
6056 text);
6058 text = secfile_lookup_str_default(file,
6059 /* TRANS: In_dustrial Espionage (3% chance of success). */
6060 N_("In%sdustrial Espionage%s"),
6061 "actions.ui_name_targeted_steal_tech");
6062 sz_strlcpy(action_by_number(ACTION_SPY_TARGETED_STEAL_TECH)->ui_name,
6063 text);
6065 text = secfile_lookup_str_default(file,
6066 /* TRANS: _Investigate City (100% chance of success). */
6067 N_("%sInvestigate City%s"),
6068 "actions.ui_name_investigate_city");
6069 sz_strlcpy(action_by_number(ACTION_SPY_INVESTIGATE_CITY)->ui_name,
6070 text);
6072 text = secfile_lookup_str_default(file,
6073 /* TRANS: _Investigate City (spends the unit) (100% chance of
6074 * success). */
6075 N_("%sInvestigate City (spends the unit)%s"),
6076 "actions.ui_name_investigate_city_spend_unit");
6077 sz_strlcpy(action_by_number(ACTION_INV_CITY_SPEND)->ui_name,
6078 text);
6080 text = secfile_lookup_str_default(file,
6081 /* TRANS: Steal _Gold (100% chance of success). */
6082 N_("Steal %sGold%s"),
6083 "actions.ui_name_steal_gold");
6084 sz_strlcpy(action_by_number(ACTION_SPY_STEAL_GOLD)->ui_name,
6085 text);
6087 text = secfile_lookup_str_default(file,
6088 /* TRANS: Steal _Maps (100% chance of success). */
6089 N_("Steal %sMaps%s"),
6090 "actions.ui_name_steal_maps");
6091 sz_strlcpy(action_by_number(ACTION_STEAL_MAPS)->ui_name,
6092 text);
6094 text = secfile_lookup_str_default(file,
6095 /* TRANS: Establish Trade _Route (100% chance of success). */
6096 N_("Establish Trade %sRoute%s"),
6097 "actions.ui_name_establish_trade_route");
6098 sz_strlcpy(action_by_number(ACTION_TRADE_ROUTE)->ui_name,
6099 text);
6101 text = secfile_lookup_str_default(file,
6102 /* TRANS: Enter _Marketplace (100% chance of success). */
6103 N_("Enter %sMarketplace%s"),
6104 "actions.ui_name_enter_marketplace");
6105 sz_strlcpy(action_by_number(ACTION_MARKETPLACE)->ui_name,
6106 text);
6108 text = secfile_lookup_str_default(file,
6109 /* TRANS: Help _build Wonder (100% chance of success). */
6110 N_("Help %sbuild Wonder%s"),
6111 "actions.ui_name_help_wonder");
6112 sz_strlcpy(action_by_number(ACTION_HELP_WONDER)->ui_name,
6113 text);
6115 text = secfile_lookup_str_default(file,
6116 /* TRANS: _Capture Units (100% chance of success). */
6117 N_("%sCapture Units%s"),
6118 "actions.ui_name_capture_units");
6119 sz_strlcpy(action_by_number(ACTION_CAPTURE_UNITS)->ui_name,
6120 text);
6122 text = secfile_lookup_str_default(file,
6123 /* TRANS: _Expel Unit (100% chance of success). */
6124 N_("%sExpel Unit%s"),
6125 "actions.ui_name_expel_unit");
6126 sz_strlcpy(action_by_number(ACTION_EXPEL_UNIT)->ui_name,
6127 text);
6129 text = secfile_lookup_str_default(file,
6130 /* TRANS: _Found City (100% chance of success). */
6131 N_("%sFound City%s"),
6132 "actions.ui_name_found_city");
6133 sz_strlcpy(action_by_number(ACTION_FOUND_CITY)->ui_name,
6134 text);
6136 text = secfile_lookup_str_default(file,
6137 /* TRANS: _Join City (100% chance of success). */
6138 N_("%sJoin City%s"),
6139 "actions.ui_name_join_city");
6140 sz_strlcpy(action_by_number(ACTION_JOIN_CITY)->ui_name,
6141 text);
6143 text = secfile_lookup_str_default(file,
6144 /* TRANS: B_ombard (100% chance of success). */
6145 N_("B%sombard%s"),
6146 "actions.ui_name_bombard");
6147 sz_strlcpy(action_by_number(ACTION_BOMBARD)->ui_name,
6148 text);
6150 text = secfile_lookup_str_default(file,
6151 /* TRANS: Suitcase _Nuke (100% chance of success). */
6152 N_("Suitcase %sNuke%s"),
6153 "actions.ui_name_suitcase_nuke");
6154 sz_strlcpy(action_by_number(ACTION_SPY_NUKE)->ui_name,
6155 text);
6157 text = secfile_lookup_str_default(file,
6158 /* TRANS: Explode _Nuclear (100% chance of success). */
6159 N_("Explode %sNuclear%s"),
6160 "actions.ui_name_explode_nuclear");
6161 sz_strlcpy(action_by_number(ACTION_NUKE)->ui_name,
6162 text);
6164 text = secfile_lookup_str_default(file,
6165 /* TRANS: Destroy _City (100% chance of success). */
6166 N_("Destroy %sCity%s"),
6167 "actions.ui_name_destroy_city");
6168 sz_strlcpy(action_by_number(ACTION_DESTROY_CITY)->ui_name,
6169 text);
6171 text = secfile_lookup_str_default(file,
6172 /* TRANS: Rec_ycle Unit (100% chance of success). */
6173 N_("Rec%sycle Unit%s"),
6174 "actions.ui_name_recycle_unit");
6175 sz_strlcpy(action_by_number(ACTION_RECYCLE_UNIT)->ui_name,
6176 text);
6178 text = secfile_lookup_str_default(file,
6179 /* TRANS: _You're Fired (100% chance of success). */
6180 N_("%sYou're Fired%s"),
6181 "actions.ui_name_disband_unit");
6182 sz_strlcpy(action_by_number(ACTION_DISBAND_UNIT)->ui_name,
6183 text);
6185 text = secfile_lookup_str_default(file,
6186 /* TRANS: Set _Home City (100% chance of success). */
6187 N_("Set %sHome City%s"),
6188 "actions.ui_name_home_city");
6189 sz_strlcpy(action_by_number(ACTION_HOME_CITY)->ui_name,
6190 text);
6192 text = secfile_lookup_str_default(file,
6193 /* TRANS: _Upgrade Unit (100% chance of success). */
6194 N_("%sUpgrade Unit%s"),
6195 "actions.ui_upgrade_unit");
6196 sz_strlcpy(action_by_number(ACTION_UPGRADE_UNIT)->ui_name,
6197 text);
6199 text = secfile_lookup_str_default(file,
6200 /* TRANS: Drop _Paratrooper (100% chance of success). */
6201 N_("Drop %sParatrooper%s"),
6202 "actions.ui_paradrop_unit");
6203 sz_strlcpy(action_by_number(ACTION_PARADROP)->ui_name,
6204 text);
6206 text = secfile_lookup_str_default(file,
6207 /* TRANS: _Airlift to City (100% chance of success). */
6208 N_("%sAirlift to City%s"),
6209 "actions.ui_airlift_unit");
6210 sz_strlcpy(action_by_number(ACTION_AIRLIFT)->ui_name,
6211 text);
6213 text = secfile_lookup_str_default(file,
6214 /* TRANS: _Attack (100% chance of success). */
6215 N_("%sAttack%s"),
6216 "actions.ui_name_attack");
6217 sz_strlcpy(action_by_number(ACTION_ATTACK)->ui_name,
6218 text);
6220 text = secfile_lookup_str_default(file,
6221 /* TRANS: _Conquer City (100% chance of success). */
6222 N_("%sConquer City%s"),
6223 "actions.ui_name_conquer_city");
6224 sz_strlcpy(action_by_number(ACTION_CONQUER_CITY)->ui_name,
6225 text);
6227 text = secfile_lookup_str_default(file,
6228 /* TRANS: Heal _Unit (3% chance of success). */
6229 N_("Heal %sUnit%s"),
6230 "actions.ui_name_heal_unit");
6231 sz_strlcpy(action_by_number(ACTION_HEAL_UNIT)->ui_name,
6232 text);
6234 /* The quiet (don't auto generate help for) property of all actions
6235 * live in a single enum vector. This avoids generic action
6236 * expectations. */
6237 if (secfile_entry_by_path(file, "actions.quiet_actions")) {
6238 enum gen_action *quiet_actions;
6239 size_t asize;
6240 int j;
6242 quiet_actions =
6243 secfile_lookup_enum_vec(file, &asize, gen_action,
6244 "actions.quiet_actions");
6246 if (!quiet_actions) {
6247 /* Entity exists but couldn't read it. */
6248 ruleset_error(LOG_ERROR,
6249 "\"%s\": actions.quiet_actions: bad action list",
6250 filename);
6252 ok = FALSE;
6255 for (j = 0; j < asize; j++) {
6256 /* Don't auto generate help text for this action. */
6257 action_by_number(quiet_actions[j])->quiet = TRUE;
6260 free(quiet_actions);
6264 if (ok) {
6265 sec = secfile_sections_by_name_prefix(file,
6266 ACTION_ENABLER_SECTION_PREFIX);
6268 if (sec) {
6269 section_list_iterate(sec, psection) {
6270 struct action_enabler *enabler;
6271 const char *sec_name = section_name(psection);
6272 struct action *paction;
6273 struct requirement_vector *actor_reqs;
6274 struct requirement_vector *target_reqs;
6275 const char *action_text;
6277 enabler = action_enabler_new();
6279 action_text = secfile_lookup_str(file, "%s.action", sec_name);
6281 if (action_text == NULL) {
6282 ruleset_error(LOG_ERROR, "\"%s\" [%s] missing action to enable.",
6283 filename, sec_name);
6284 ok = FALSE;
6285 break;
6288 paction = action_by_rule_name(action_text);
6289 if (!paction) {
6290 ruleset_error(LOG_ERROR, "\"%s\" [%s] lists unknown action type \"%s\".",
6291 filename, sec_name, action_text);
6292 ok = FALSE;
6293 break;
6296 enabler->action = paction->id;
6298 actor_reqs = lookup_req_list(file, compat, sec_name, "actor_reqs", action_text);
6299 if (actor_reqs == NULL) {
6300 ok = FALSE;
6301 break;
6304 requirement_vector_copy(&enabler->actor_reqs, actor_reqs);
6306 target_reqs = lookup_req_list(file, compat, sec_name, "target_reqs", action_text);
6307 if (target_reqs == NULL) {
6308 ok = FALSE;
6309 break;
6312 requirement_vector_copy(&enabler->target_reqs, target_reqs);
6314 action_enabler_add(enabler);
6315 } section_list_iterate_end;
6316 section_list_destroy(sec);
6321 if (ok) {
6322 const char *tus_text;
6324 /* section: combat_rules */
6325 game.info.tired_attack
6326 = secfile_lookup_bool_default(file, RS_DEFAULT_TIRED_ATTACK,
6327 "combat_rules.tired_attack");
6329 /* section: borders */
6330 game.info.border_city_radius_sq
6331 = secfile_lookup_int_default_min_max(file,
6332 RS_DEFAULT_BORDER_RADIUS_SQ_CITY,
6333 RS_MIN_BORDER_RADIUS_SQ_CITY,
6334 RS_MAX_BORDER_RADIUS_SQ_CITY,
6335 "borders.radius_sq_city");
6336 game.info.border_size_effect
6337 = secfile_lookup_int_default_min_max(file,
6338 RS_DEFAULT_BORDER_SIZE_EFFECT,
6339 RS_MIN_BORDER_SIZE_EFFECT,
6340 RS_MAX_BORDER_SIZE_EFFECT,
6341 "borders.size_effect");
6343 game.info.border_city_permanent_radius_sq
6344 = secfile_lookup_int_default_min_max(file,
6345 RS_DEFAULT_BORDER_RADIUS_SQ_CITY_PERMANENT,
6346 RS_MIN_BORDER_RADIUS_SQ_CITY_PERMANENT,
6347 RS_MAX_BORDER_RADIUS_SQ_CITY_PERMANENT,
6348 "borders.radius_sq_city_permanent");
6350 /* section: research */
6351 tus_text = secfile_lookup_str_default(file, RS_DEFAULT_TECH_COST_STYLE,
6352 "research.tech_cost_style");
6353 game.info.tech_cost_style = tech_cost_style_by_name(tus_text,
6354 fc_strcasecmp);
6355 if (!tech_cost_style_is_valid(game.info.tech_cost_style)) {
6356 ruleset_error(LOG_ERROR, "Unknown tech cost style \"%s\"",
6357 tus_text);
6358 ok = FALSE;
6361 tus_text = secfile_lookup_str_default(file, RS_DEFAULT_TECH_LEAKAGE,
6362 "research.tech_leakage");
6363 game.info.tech_leakage = tech_leakage_style_by_name(tus_text,
6364 fc_strcasecmp);
6365 if (!tech_leakage_style_is_valid(game.info.tech_leakage)) {
6366 ruleset_error(LOG_ERROR, "Unknown tech leakage \"%s\"",
6367 tus_text);
6368 ok = FALSE;
6370 if (game.info.tech_cost_style == TECH_COST_CIV1CIV2
6371 && game.info.tech_leakage != TECH_LEAKAGE_NONE) {
6372 log_error("Only tech_leakage \"%s\" supported with "
6373 "tech_cost_style \"%s\". ",
6374 tech_leakage_style_name(TECH_LEAKAGE_NONE),
6375 tech_cost_style_name(TECH_COST_CIV1CIV2));
6376 log_error("Switching to tech_leakage \"%s\".",
6377 tech_leakage_style_name(TECH_LEAKAGE_NONE));
6378 game.info.tech_leakage = TECH_LEAKAGE_NONE;
6380 game.info.base_tech_cost
6381 = secfile_lookup_int_default_min_max(file,
6382 RS_DEFAULT_BASE_TECH_COST,
6383 RS_MIN_BASE_TECH_COST,
6384 RS_MAX_BASE_TECH_COST,
6385 "research.base_tech_cost");
6387 tus_text = secfile_lookup_str_default(file, RS_DEFAULT_TECH_UPKEEP_STYLE,
6388 "research.tech_upkeep_style");
6390 game.info.tech_upkeep_style = tech_upkeep_style_by_name(tus_text, fc_strcasecmp);
6392 if (!tech_upkeep_style_is_valid(game.info.tech_upkeep_style)) {
6393 ruleset_error(LOG_ERROR, "Unknown tech upkeep style \"%s\"",
6394 tus_text);
6395 ok = FALSE;
6399 if (ok) {
6400 game.info.tech_upkeep_divider
6401 = secfile_lookup_int_default_min_max(file,
6402 RS_DEFAULT_TECH_UPKEEP_DIVIDER,
6403 RS_MIN_TECH_UPKEEP_DIVIDER,
6404 RS_MAX_TECH_UPKEEP_DIVIDER,
6405 "research.tech_upkeep_divider");
6407 sval = secfile_lookup_str_default(file, NULL, "research.free_tech_method");
6408 if (sval == NULL) {
6409 ruleset_error(LOG_ERROR, "No free_tech_method given");
6410 ok = FALSE;
6411 } else {
6412 game.info.free_tech_method = free_tech_method_by_name(sval, fc_strcasecmp);
6413 if (!free_tech_method_is_valid(game.info.free_tech_method)) {
6414 ruleset_error(LOG_ERROR, "Bad value %s for free_tech_method.", sval);
6415 ok = FALSE;
6420 if (ok) {
6421 int cf;
6423 /* section: culture */
6424 game.info.culture_vic_points
6425 = secfile_lookup_int_default(file, RS_DEFAULT_CULTURE_VIC_POINTS,
6426 "culture.victory_min_points");
6427 game.info.culture_vic_lead
6428 = secfile_lookup_int_default(file, RS_DEFAULT_CULTURE_VIC_LEAD,
6429 "culture.victory_lead_pct");
6430 game.info.culture_migration_pml
6431 = secfile_lookup_int_default(file, RS_DEFAULT_CULTURE_MIGRATION_PML,
6432 "culture.migration_pml");
6434 /* section: calendar */
6435 game.calendar.calendar_skip_0
6436 = secfile_lookup_bool_default(file, RS_DEFAULT_CALENDAR_SKIP_0,
6437 "calendar.skip_year_0");
6438 game.server.start_year
6439 = secfile_lookup_int_default(file, GAME_START_YEAR,
6440 "calendar.start_year");
6441 game.calendar.calendar_fragments
6442 = secfile_lookup_int_default(file, 0, "calendar.fragments");
6444 if (game.calendar.calendar_fragments > MAX_CALENDAR_FRAGMENTS) {
6445 ruleset_error(LOG_ERROR, "Too many calendar fragments. Max is %d",
6446 MAX_CALENDAR_FRAGMENTS);
6447 ok = FALSE;
6448 game.calendar.calendar_fragments = 0;
6450 sz_strlcpy(game.calendar.positive_year_label,
6451 secfile_lookup_str_default(file,
6452 RS_DEFAULT_POS_YEAR_LABEL,
6453 "calendar.positive_label"));
6454 sz_strlcpy(game.calendar.negative_year_label,
6455 secfile_lookup_str_default(file,
6456 RS_DEFAULT_NEG_YEAR_LABEL,
6457 "calendar.negative_label"));
6459 for (cf = 0; cf < game.calendar.calendar_fragments; cf++) {
6460 const char *fname;
6462 fname = secfile_lookup_str_default(file, NULL, "calendar.fragment_name%d", cf);
6463 if (fname != NULL) {
6464 strncpy(game.calendar.calendar_fragment_name[cf], fname,
6465 sizeof(game.calendar.calendar_fragment_name[cf]));
6470 if (ok) {
6471 /* section playercolors */
6472 struct rgbcolor *prgbcolor = NULL;
6473 bool color_read = TRUE;
6475 /* Check if the player list is defined and empty. */
6476 if (playercolor_count() != 0) {
6477 ok = FALSE;
6478 } else {
6479 i = 0;
6481 while (color_read) {
6482 prgbcolor = NULL;
6484 color_read = rgbcolor_load(file, &prgbcolor, "playercolors.colorlist%d", i);
6485 if (color_read) {
6486 playercolor_add(prgbcolor);
6489 i++;
6492 if (playercolor_count() == 0) {
6493 ruleset_error(LOG_ERROR, "No player colors defined!");
6494 ok = FALSE;
6497 if (ok) {
6498 fc_assert(game.plr_bg_color == NULL);
6499 if (!rgbcolor_load(file, &game.plr_bg_color, "playercolors.background")) {
6500 ruleset_error(LOG_ERROR, "No background player color defined! (%s)",
6501 secfile_error());
6502 ok = FALSE;
6508 if (ok) {
6509 /* section: teams */
6510 svec = secfile_lookup_str_vec(file, &teams, "teams.names");
6511 if (team_slot_count() < teams) {
6512 teams = team_slot_count();
6514 game.server.ruledit.named_teams = teams;
6515 for (i = 0; i < teams; i++) {
6516 team_slot_set_defined_name(team_slot_by_number(i), svec[i]);
6518 free(svec);
6520 sec = secfile_sections_by_name_prefix(file, DISASTER_SECTION_PREFIX);
6521 nval = (NULL != sec ? section_list_size(sec) : 0);
6522 if (nval > MAX_DISASTER_TYPES) {
6523 int num = nval; /* No "size_t" to printf */
6525 ruleset_error(LOG_ERROR, "\"%s\": Too many disaster types (%d, max %d)",
6526 filename, num, MAX_DISASTER_TYPES);
6527 section_list_destroy(sec);
6528 ok = FALSE;
6529 } else {
6530 game.control.num_disaster_types = nval;
6534 if (ok) {
6535 disaster_type_iterate(pdis) {
6536 int id = disaster_index(pdis);
6537 int j;
6538 size_t eff_count;
6539 struct requirement_vector *reqs;
6540 const char *sec_name = section_name(section_list_get(sec, id));
6542 if (!ruleset_load_names(&pdis->name, NULL, file, sec_name)) {
6543 ruleset_error(LOG_ERROR, "\"%s\": Cannot load disaster names",
6544 filename);
6545 ok = FALSE;
6546 break;
6549 reqs = lookup_req_list(file, compat, sec_name, "reqs", disaster_rule_name(pdis));
6550 if (reqs == NULL) {
6551 ok = FALSE;
6552 break;
6554 requirement_vector_copy(&pdis->reqs, reqs);
6556 pdis->frequency = secfile_lookup_int_default(file, GAME_DEFAULT_DISASTER_FREQ,
6557 "%s.frequency", sec_name);
6559 svec = secfile_lookup_str_vec(file, &eff_count, "%s.effects", sec_name);
6561 BV_CLR_ALL(pdis->effects);
6562 for (j = 0; j < eff_count; j++) {
6563 const char *dsval = svec[j];
6564 enum disaster_effect_id effect;
6566 effect = disaster_effect_id_by_name(dsval, fc_strcasecmp);
6568 if (!disaster_effect_id_is_valid(effect)) {
6569 ruleset_error(LOG_ERROR,
6570 "\"%s\" disaster \"%s\": unknown effect \"%s\".",
6571 filename,
6572 disaster_rule_name(pdis),
6573 dsval);
6574 ok = FALSE;
6575 break;
6576 } else {
6577 BV_SET(pdis->effects, effect);
6581 free(svec);
6583 if (!ok) {
6584 break;
6586 } disaster_type_iterate_end;
6587 section_list_destroy(sec);
6590 if (ok) {
6591 sec = secfile_sections_by_name_prefix(file, ACHIEVEMENT_SECTION_PREFIX);
6593 achievements_iterate(pach) {
6594 int id = achievement_index(pach);
6595 const char *sec_name = section_name(section_list_get(sec, id));
6596 const char *typename;
6597 const char *msg;
6599 typename = secfile_lookup_str_default(file, NULL, "%s.type", sec_name);
6601 pach->type = achievement_type_by_name(typename, fc_strcasecmp);
6602 if (!achievement_type_is_valid(pach->type)) {
6603 ruleset_error(LOG_ERROR, "Achievement has unknown type \"%s\".",
6604 typename != NULL ? typename : "(NULL)");
6605 ok = FALSE;
6608 if (ok) {
6609 pach->unique = secfile_lookup_bool_default(file, GAME_DEFAULT_ACH_UNIQUE,
6610 "%s.unique", sec_name);
6612 pach->value = secfile_lookup_int_default(file, GAME_DEFAULT_ACH_VALUE,
6613 "%s.value", sec_name);
6614 pach->culture = secfile_lookup_int_default(file, 0,
6615 "%s.culture", sec_name);
6617 msg = secfile_lookup_str_default(file, NULL, "%s.first_msg", sec_name);
6618 if (msg == NULL) {
6619 ruleset_error(LOG_ERROR, "Achievement %s has no first msg!", sec_name);
6620 ok = FALSE;
6621 } else {
6622 pach->first_msg = fc_strdup(msg);
6626 if (ok) {
6627 msg = secfile_lookup_str_default(file, NULL, "%s.cons_msg", sec_name);
6628 if (msg == NULL) {
6629 if (!pach->unique) {
6630 ruleset_error(LOG_ERROR, "Achievement %s has no msg for consecutive gainers!", sec_name);
6631 ok = FALSE;
6633 } else {
6634 pach->cons_msg = fc_strdup(msg);
6638 if (!ok) {
6639 break;
6641 } achievements_iterate_end;
6644 if (ok) {
6645 for (i = 0; (name = secfile_lookup_str_default(file, NULL,
6646 "trade.settings%d.type",
6647 i)); i++) {
6648 enum trade_route_type type = trade_route_type_by_name(name);
6650 if (type == TRT_LAST) {
6651 ruleset_error(LOG_ERROR,
6652 "\"%s\" unknown trade route type \"%s\".",
6653 filename, name);
6654 ok = FALSE;
6655 } else {
6656 struct trade_route_settings *set = trade_route_settings_by_type(type);
6657 const char *cancelling;
6658 const char *bonus;
6660 set->trade_pct = secfile_lookup_int_default(file, 100,
6661 "trade.settings%d.pct", i);
6662 cancelling = secfile_lookup_str_default(file, "Active",
6663 "trade.settings%d.cancelling", i);
6664 set->cancelling = traderoute_cancelling_type_by_name(cancelling);
6665 if (set->cancelling == TRI_LAST) {
6666 ruleset_error(LOG_ERROR,
6667 "\"%s\" unknown traderoute cancelling type \"%s\".",
6668 filename, cancelling);
6669 ok = FALSE;
6672 bonus = secfile_lookup_str_default(file, "None", "trade.settings%d.bonus", i);
6674 set->bonus_type = traderoute_bonus_type_by_name(bonus, fc_strcasecmp);
6676 if (!traderoute_bonus_type_is_valid(set->bonus_type)) {
6677 ruleset_error(LOG_ERROR,
6678 "\"%s\" unknown traderoute bonus type \"%s\".",
6679 filename, bonus);
6680 ok = FALSE;
6686 if (ok) {
6687 const char *str = secfile_lookup_str_default(file, "Leaving", "trade.goods_selection");
6689 game.info.goods_selection = goods_selection_method_by_name(str, fc_strcasecmp);
6691 if (!goods_selection_method_is_valid(game.info.goods_selection)) {
6692 ruleset_error(LOG_ERROR,
6693 "\"%s\" goods selection method \"%s\" unknown.",
6694 filename, str);
6695 ok = FALSE;
6699 if (ok) {
6700 sec = secfile_sections_by_name_prefix(file, GOODS_SECTION_PREFIX);
6702 goods_type_iterate(pgood) {
6703 int id = goods_index(pgood);
6704 const char *sec_name = section_name(section_list_get(sec, id));
6705 struct requirement_vector *reqs;
6706 const char **slist;
6707 int j;
6709 reqs = lookup_req_list(file, compat, sec_name, "reqs", goods_rule_name(pgood));
6710 if (reqs == NULL) {
6711 ok = FALSE;
6712 break;
6714 requirement_vector_copy(&pgood->reqs, reqs);
6716 pgood->from_pct = secfile_lookup_int_default(file, 100,
6717 "%s.from_pct", sec_name);
6718 pgood->to_pct = secfile_lookup_int_default(file, 100,
6719 "%s.to_pct", sec_name);
6721 slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name);
6722 BV_CLR_ALL(pgood->flags);
6723 for (j = 0; j < nval; j++) {
6724 enum goods_flag_id flag;
6726 sval = slist[j];
6727 flag = goods_flag_id_by_name(sval, fc_strcasecmp);
6728 if (!goods_flag_id_is_valid(flag)) {
6729 ruleset_error(LOG_ERROR, "\"%s\" good \"%s\": unknown flag \"%s\".",
6730 filename,
6731 goods_rule_name(pgood),
6732 sval);
6733 ok = FALSE;
6734 break;
6735 } else {
6736 BV_SET(pgood->flags, flag);
6739 free(slist);
6741 pgood->helptext = lookup_strvec(file, sec_name, "helptext");
6742 } goods_type_iterate_end;
6745 /* secfile_check_unused() is not here, but only after also settings section
6746 * has been loaded. */
6748 return ok;
6751 /**************************************************************************
6752 Send the units ruleset information (all individual unit classes) to the
6753 specified connections.
6754 **************************************************************************/
6755 static void send_ruleset_unit_classes(struct conn_list *dest)
6757 struct packet_ruleset_unit_class packet;
6758 struct packet_ruleset_unit_class_flag fpacket;
6759 int i;
6761 for (i = 0; i < MAX_NUM_USER_UCLASS_FLAGS; i++) {
6762 const char *flagname;
6763 const char *helptxt;
6765 fpacket.id = i + UCF_USER_FLAG_1;
6767 flagname = unit_class_flag_id_name(i + UCF_USER_FLAG_1);
6768 if (flagname == NULL) {
6769 fpacket.name[0] = '\0';
6770 } else {
6771 sz_strlcpy(fpacket.name, flagname);
6774 helptxt = unit_class_flag_helptxt(i + UCF_USER_FLAG_1);
6775 if (helptxt == NULL) {
6776 fpacket.helptxt[0] = '\0';
6777 } else {
6778 sz_strlcpy(fpacket.helptxt, helptxt);
6781 lsend_packet_ruleset_unit_class_flag(dest, &fpacket);
6784 unit_class_iterate(c) {
6785 packet.id = uclass_number(c);
6786 sz_strlcpy(packet.name, untranslated_name(&c->name));
6787 sz_strlcpy(packet.rule_name, rule_name_get(&c->name));
6788 packet.min_speed = c->min_speed;
6789 packet.hp_loss_pct = c->hp_loss_pct;
6790 packet.hut_behavior = c->hut_behavior;
6791 packet.non_native_def_pct = c->non_native_def_pct;
6792 packet.flags = c->flags;
6794 PACKET_STRVEC_COMPUTE(packet.helptext, c->helptext);
6796 lsend_packet_ruleset_unit_class(dest, &packet);
6797 } unit_class_iterate_end;
6800 /**************************************************************************
6801 Send the units ruleset information (all individual units) to the
6802 specified connections.
6803 **************************************************************************/
6804 static void send_ruleset_units(struct conn_list *dest)
6806 struct packet_ruleset_unit packet;
6807 struct packet_ruleset_unit_flag fpacket;
6808 int i;
6810 for (i = 0; i < MAX_NUM_USER_UNIT_FLAGS; i++) {
6811 const char *flagname;
6812 const char *helptxt;
6814 fpacket.id = i + UTYF_USER_FLAG_1;
6816 flagname = unit_type_flag_id_name(i + UTYF_USER_FLAG_1);
6817 if (flagname == NULL) {
6818 fpacket.name[0] = '\0';
6819 } else {
6820 sz_strlcpy(fpacket.name, flagname);
6823 helptxt = unit_type_flag_helptxt(i + UTYF_USER_FLAG_1);
6824 if (helptxt == NULL) {
6825 fpacket.helptxt[0] = '\0';
6826 } else {
6827 sz_strlcpy(fpacket.helptxt, helptxt);
6830 lsend_packet_ruleset_unit_flag(dest, &fpacket);
6833 unit_type_iterate(u) {
6834 packet.id = utype_number(u);
6835 sz_strlcpy(packet.name, untranslated_name(&u->name));
6836 sz_strlcpy(packet.rule_name, rule_name_get(&u->name));
6837 sz_strlcpy(packet.sound_move, u->sound_move);
6838 sz_strlcpy(packet.sound_move_alt, u->sound_move_alt);
6839 sz_strlcpy(packet.sound_fight, u->sound_fight);
6840 sz_strlcpy(packet.sound_fight_alt, u->sound_fight_alt);
6841 sz_strlcpy(packet.graphic_str, u->graphic_str);
6842 sz_strlcpy(packet.graphic_alt, u->graphic_alt);
6843 packet.unit_class_id = uclass_number(utype_class(u));
6844 packet.build_cost = u->build_cost;
6845 packet.pop_cost = u->pop_cost;
6846 packet.attack_strength = u->attack_strength;
6847 packet.defense_strength = u->defense_strength;
6848 packet.move_rate = u->move_rate;
6849 packet.tech_requirement = u->require_advance
6850 ? advance_number(u->require_advance)
6851 : advance_count();
6852 packet.impr_requirement = u->need_improvement
6853 ? improvement_number(u->need_improvement)
6854 : improvement_count();
6855 packet.gov_requirement = u->need_government
6856 ? government_number(u->need_government)
6857 : government_count();
6858 packet.vision_radius_sq = u->vision_radius_sq;
6859 packet.transport_capacity = u->transport_capacity;
6860 packet.hp = u->hp;
6861 packet.firepower = u->firepower;
6862 packet.obsoleted_by = u->obsoleted_by
6863 ? utype_number(u->obsoleted_by)
6864 : utype_count();
6865 packet.converted_to = u->converted_to
6866 ? utype_number(u->converted_to)
6867 : utype_count();
6868 packet.convert_time = u->convert_time;
6869 packet.fuel = u->fuel;
6870 packet.flags = u->flags;
6871 packet.roles = u->roles;
6872 packet.happy_cost = u->happy_cost;
6873 output_type_iterate(o) {
6874 packet.upkeep[o] = u->upkeep[o];
6875 } output_type_iterate_end;
6876 packet.paratroopers_range = u->paratroopers_range;
6877 packet.paratroopers_mr_req = u->paratroopers_mr_req;
6878 packet.paratroopers_mr_sub = u->paratroopers_mr_sub;
6879 packet.bombard_rate = u->bombard_rate;
6880 packet.city_size = u->city_size;
6881 packet.city_slots = u->city_slots;
6882 packet.cargo = u->cargo;
6883 packet.targets = u->targets;
6884 packet.embarks = u->embarks;
6885 packet.disembarks = u->disembarks;
6887 if (u->veteran == NULL) {
6888 /* Use the default veteran system. */
6889 packet.veteran_levels = 0;
6890 } else {
6891 /* Per unit veteran system definition. */
6892 packet.veteran_levels = utype_veteran_levels(u);
6894 for (i = 0; i < packet.veteran_levels; i++) {
6895 const struct veteran_level *vlevel = utype_veteran_level(u, i);
6897 sz_strlcpy(packet.veteran_name[i], untranslated_name(&vlevel->name));
6898 packet.power_fact[i] = vlevel->power_fact;
6899 packet.move_bonus[i] = vlevel->move_bonus;
6902 PACKET_STRVEC_COMPUTE(packet.helptext, u->helptext);
6904 lsend_packet_ruleset_unit(dest, &packet);
6906 combat_bonus_list_iterate(u->bonuses, pbonus) {
6907 struct packet_ruleset_unit_bonus bonuspacket;
6909 bonuspacket.unit = packet.id;
6910 bonuspacket.flag = pbonus->flag;
6911 bonuspacket.type = pbonus->type;
6912 bonuspacket.value = pbonus->value;
6913 bonuspacket.quiet = pbonus->quiet;
6915 lsend_packet_ruleset_unit_bonus(dest, &bonuspacket);
6916 } combat_bonus_list_iterate_end;
6917 } unit_type_iterate_end;
6920 /**************************************************************************
6921 Send the specialists ruleset information (all individual specialist
6922 types) to the specified connections.
6923 **************************************************************************/
6924 static void send_ruleset_specialists(struct conn_list *dest)
6926 struct packet_ruleset_specialist packet;
6928 specialist_type_iterate(spec_id) {
6929 struct specialist *s = specialist_by_number(spec_id);
6930 int j;
6932 packet.id = spec_id;
6933 sz_strlcpy(packet.plural_name, untranslated_name(&s->name));
6934 sz_strlcpy(packet.rule_name, rule_name_get(&s->name));
6935 sz_strlcpy(packet.short_name, untranslated_name(&s->abbreviation));
6936 sz_strlcpy(packet.graphic_alt, s->graphic_alt);
6937 j = 0;
6938 requirement_vector_iterate(&s->reqs, preq) {
6939 packet.reqs[j++] = *preq;
6940 } requirement_vector_iterate_end;
6941 packet.reqs_count = j;
6943 PACKET_STRVEC_COMPUTE(packet.helptext, s->helptext);
6945 lsend_packet_ruleset_specialist(dest, &packet);
6946 } specialist_type_iterate_end;
6948 /**************************************************************************
6949 Send the techs class information to the specified connections.
6950 **************************************************************************/
6951 static void send_ruleset_tech_classes(struct conn_list *dest)
6953 struct packet_ruleset_tech_class packet;
6955 tech_class_iterate(ptclass) {
6956 packet.id = ptclass->idx;
6957 sz_strlcpy(packet.name, untranslated_name(&ptclass->name));
6958 sz_strlcpy(packet.rule_name, rule_name_get(&ptclass->name));
6959 packet.cost_pct = ptclass->cost_pct;
6961 lsend_packet_ruleset_tech_class(dest, &packet);
6962 } tech_class_iterate_end;
6965 /**************************************************************************
6966 Send the techs ruleset information (all individual advances) to the
6967 specified connections.
6968 **************************************************************************/
6969 static void send_ruleset_techs(struct conn_list *dest)
6971 struct packet_ruleset_tech packet;
6972 struct packet_ruleset_tech_flag fpacket;
6973 int i;
6975 for (i = 0; i < MAX_NUM_USER_TECH_FLAGS; i++) {
6976 const char *flagname;
6977 const char *helptxt;
6979 fpacket.id = i + TECH_USER_1;
6981 flagname = tech_flag_id_name_cb(i + TECH_USER_1);
6982 if (flagname == NULL) {
6983 fpacket.name[0] = '\0';
6984 } else {
6985 sz_strlcpy(fpacket.name, flagname);
6988 helptxt = tech_flag_helptxt(i + TECH_USER_1);
6989 if (helptxt == NULL) {
6990 fpacket.helptxt[0] = '\0';
6991 } else {
6992 sz_strlcpy(fpacket.helptxt, helptxt);
6995 lsend_packet_ruleset_tech_flag(dest, &fpacket);
6998 advance_iterate(A_FIRST, a) {
6999 packet.id = advance_number(a);
7000 packet.removed = !valid_advance(a);
7001 if (a->tclass == NULL) {
7002 packet.tclass = 0;
7003 } else {
7004 packet.tclass = a->tclass->idx;
7006 sz_strlcpy(packet.name, untranslated_name(&a->name));
7007 sz_strlcpy(packet.rule_name, rule_name_get(&a->name));
7008 sz_strlcpy(packet.graphic_str, a->graphic_str);
7009 sz_strlcpy(packet.graphic_alt, a->graphic_alt);
7011 /* Current size of the packet's research_reqs requirement vector. */
7012 i = 0;
7014 /* The requirements req1 and req2 are needed to research a tech. Send
7015 * them in the research_reqs requirement vector. Range is set to player
7016 * since pooled research is configurable. */
7018 if ((a->require[AR_ONE] != A_NEVER)
7019 && advance_number(a->require[AR_ONE]) > A_NONE) {
7020 packet.research_reqs[i++]
7021 = req_from_values(VUT_ADVANCE, REQ_RANGE_PLAYER,
7022 FALSE, TRUE, FALSE,
7023 advance_number(a->require[AR_ONE]));
7026 if ((a->require[AR_TWO] != A_NEVER)
7027 && advance_number(a->require[AR_TWO]) > A_NONE) {
7028 packet.research_reqs[i++]
7029 = req_from_values(VUT_ADVANCE, REQ_RANGE_PLAYER,
7030 FALSE, TRUE, FALSE,
7031 advance_number(a->require[AR_TWO]));;
7034 /* The requirements of the tech's research_reqs also goes in the
7035 * packet's research_reqs requirement vector. */
7036 requirement_vector_iterate(&a->research_reqs, req) {
7037 packet.research_reqs[i++] = *req;
7038 } requirement_vector_iterate_end;
7040 /* The packet's research_reqs should contain req1, req2 and the
7041 * requirements of the tech's research_reqs. */
7042 packet.research_reqs_count = i;
7044 packet.root_req = a->require[AR_ROOT]
7045 ? advance_number(a->require[AR_ROOT])
7046 : advance_count();
7048 packet.flags = a->flags;
7049 packet.cost = a->cost;
7050 packet.num_reqs = a->num_reqs;
7051 PACKET_STRVEC_COMPUTE(packet.helptext, a->helptext);
7053 lsend_packet_ruleset_tech(dest, &packet);
7054 } advance_iterate_end;
7057 /**************************************************************************
7058 Send the buildings ruleset information (all individual improvements and
7059 wonders) to the specified connections.
7060 **************************************************************************/
7061 static void send_ruleset_buildings(struct conn_list *dest)
7063 improvement_iterate(b) {
7064 struct packet_ruleset_building packet;
7065 int j;
7067 packet.id = improvement_number(b);
7068 packet.genus = b->genus;
7069 sz_strlcpy(packet.name, untranslated_name(&b->name));
7070 sz_strlcpy(packet.rule_name, rule_name_get(&b->name));
7071 sz_strlcpy(packet.graphic_str, b->graphic_str);
7072 sz_strlcpy(packet.graphic_alt, b->graphic_alt);
7073 j = 0;
7074 requirement_vector_iterate(&b->reqs, preq) {
7075 packet.reqs[j++] = *preq;
7076 } requirement_vector_iterate_end;
7077 packet.reqs_count = j;
7078 j = 0;
7079 requirement_vector_iterate(&b->obsolete_by, pobs) {
7080 packet.obs_reqs[j++] = *pobs;
7081 } requirement_vector_iterate_end;
7082 packet.obs_count = j;
7083 packet.build_cost = b->build_cost;
7084 packet.upkeep = b->upkeep;
7085 packet.sabotage = b->sabotage;
7086 packet.flags = b->flags;
7087 sz_strlcpy(packet.soundtag, b->soundtag);
7088 sz_strlcpy(packet.soundtag_alt, b->soundtag_alt);
7089 PACKET_STRVEC_COMPUTE(packet.helptext, b->helptext);
7091 lsend_packet_ruleset_building(dest, &packet);
7092 } improvement_iterate_end;
7095 /**************************************************************************
7096 Send the terrain ruleset information (terrain_control, and the individual
7097 terrain types) to the specified connections.
7098 **************************************************************************/
7099 static void send_ruleset_terrain(struct conn_list *dest)
7101 struct packet_ruleset_terrain packet;
7102 struct packet_ruleset_terrain_flag fpacket;
7103 int i;
7105 lsend_packet_ruleset_terrain_control(dest, &terrain_control);
7107 for (i = 0; i < MAX_NUM_USER_TER_FLAGS; i++) {
7108 const char *flagname;
7109 const char *helptxt;
7111 fpacket.id = i + TER_USER_1;
7113 flagname = terrain_flag_id_name_cb(i + TER_USER_1);
7114 if (flagname == NULL) {
7115 fpacket.name[0] = '\0';
7116 } else {
7117 sz_strlcpy(fpacket.name, flagname);
7120 helptxt = terrain_flag_helptxt(i + TER_USER_1);
7121 if (helptxt == NULL) {
7122 fpacket.helptxt[0] = '\0';
7123 } else {
7124 sz_strlcpy(fpacket.helptxt, helptxt);
7127 lsend_packet_ruleset_terrain_flag(dest, &fpacket);
7130 terrain_type_iterate(pterrain) {
7131 struct extra_type **r;
7133 packet.id = terrain_number(pterrain);
7134 packet.tclass = pterrain->tclass;
7135 packet.native_to = pterrain->native_to;
7137 sz_strlcpy(packet.name, untranslated_name(&pterrain->name));
7138 sz_strlcpy(packet.rule_name, rule_name_get(&pterrain->name));
7139 sz_strlcpy(packet.graphic_str, pterrain->graphic_str);
7140 sz_strlcpy(packet.graphic_alt, pterrain->graphic_alt);
7142 packet.movement_cost = pterrain->movement_cost;
7143 packet.defense_bonus = pterrain->defense_bonus;
7145 output_type_iterate(o) {
7146 packet.output[o] = pterrain->output[o];
7147 } output_type_iterate_end;
7149 packet.num_resources = 0;
7150 for (r = pterrain->resources; *r; r++) {
7151 packet.resources[packet.num_resources++] = extra_number(*r);
7154 output_type_iterate(o) {
7155 packet.road_output_incr_pct[o] = pterrain->road_output_incr_pct[o];
7156 } output_type_iterate_end;
7158 packet.base_time = pterrain->base_time;
7159 packet.road_time = pterrain->road_time;
7161 packet.irrigation_result = (pterrain->irrigation_result
7162 ? terrain_number(pterrain->irrigation_result)
7163 : terrain_count());
7164 packet.irrigation_food_incr = pterrain->irrigation_food_incr;
7165 packet.irrigation_time = pterrain->irrigation_time;
7167 packet.mining_result = (pterrain->mining_result
7168 ? terrain_number(pterrain->mining_result)
7169 : terrain_count());
7170 packet.mining_shield_incr = pterrain->mining_shield_incr;
7171 packet.mining_time = pterrain->mining_time;
7173 packet.animal = (pterrain->animal == NULL ? -1 : utype_number(pterrain->animal));
7174 packet.transform_result = (pterrain->transform_result
7175 ? terrain_number(pterrain->transform_result)
7176 : terrain_count());
7177 packet.pillage_time = pterrain->pillage_time;
7178 packet.transform_time = pterrain->transform_time;
7179 packet.clean_pollution_time = pterrain->clean_pollution_time;
7180 packet.clean_fallout_time = pterrain->clean_fallout_time;
7182 packet.flags = pterrain->flags;
7184 packet.color_red = pterrain->rgb->r;
7185 packet.color_green = pterrain->rgb->g;
7186 packet.color_blue = pterrain->rgb->b;
7188 PACKET_STRVEC_COMPUTE(packet.helptext, pterrain->helptext);
7190 lsend_packet_ruleset_terrain(dest, &packet);
7191 } terrain_type_iterate_end;
7194 /****************************************************************************
7195 Send the resource ruleset information to the specified connections.
7196 ****************************************************************************/
7197 static void send_ruleset_resources(struct conn_list *dest)
7199 struct packet_ruleset_resource packet;
7201 extra_type_by_cause_iterate(EC_RESOURCE, presource) {
7202 packet.id = extra_index(presource);
7204 output_type_iterate(o) {
7205 packet.output[o] = presource->data.resource->output[o];
7206 } output_type_iterate_end;
7208 lsend_packet_ruleset_resource(dest, &packet);
7209 } extra_type_by_cause_iterate_end;
7212 /**************************************************************************
7213 Send the extra ruleset information (all individual extra types) to the
7214 specified connections.
7215 **************************************************************************/
7216 static void send_ruleset_extras(struct conn_list *dest)
7218 struct packet_ruleset_extra packet;
7219 struct packet_ruleset_extra_flag fpacket;
7220 int i;
7222 for (i = 0; i < MAX_NUM_USER_EXTRA_FLAGS; i++) {
7223 const char *flagname;
7224 const char *helptxt;
7226 fpacket.id = i + EF_USER_FLAG_1;
7228 flagname = extra_flag_id_name(i + EF_USER_FLAG_1);
7229 if (flagname == NULL) {
7230 fpacket.name[0] = '\0';
7231 } else {
7232 sz_strlcpy(fpacket.name, flagname);
7235 helptxt = extra_flag_helptxt(i + EF_USER_FLAG_1);
7236 if (helptxt == NULL) {
7237 fpacket.helptxt[0] = '\0';
7238 } else {
7239 sz_strlcpy(fpacket.helptxt, helptxt);
7242 lsend_packet_ruleset_extra_flag(dest, &fpacket);
7245 extra_type_iterate(e) {
7246 int j;
7248 packet.id = extra_number(e);
7249 sz_strlcpy(packet.name, untranslated_name(&e->name));
7250 sz_strlcpy(packet.rule_name, rule_name_get(&e->name));
7252 packet.category = e->category;
7253 packet.causes = e->causes;
7254 packet.rmcauses = e->rmcauses;
7256 sz_strlcpy(packet.activity_gfx, e->activity_gfx);
7257 sz_strlcpy(packet.act_gfx_alt, e->act_gfx_alt);
7258 sz_strlcpy(packet.act_gfx_alt2, e->act_gfx_alt2);
7259 sz_strlcpy(packet.rmact_gfx, e->rmact_gfx);
7260 sz_strlcpy(packet.rmact_gfx_alt, e->rmact_gfx_alt);
7261 sz_strlcpy(packet.graphic_str, e->graphic_str);
7262 sz_strlcpy(packet.graphic_alt, e->graphic_alt);
7264 j = 0;
7265 requirement_vector_iterate(&e->reqs, preq) {
7266 packet.reqs[j++] = *preq;
7267 } requirement_vector_iterate_end;
7268 packet.reqs_count = j;
7270 j = 0;
7271 requirement_vector_iterate(&e->rmreqs, preq) {
7272 packet.rmreqs[j++] = *preq;
7273 } requirement_vector_iterate_end;
7274 packet.rmreqs_count = j;
7276 packet.appearance_chance = e->appearance_chance;
7277 j = 0;
7278 requirement_vector_iterate(&e->appearance_reqs, preq) {
7279 packet.appearance_reqs[j++] = *preq;
7280 } requirement_vector_iterate_end;
7281 packet.appearance_reqs_count = j;
7283 packet.disappearance_chance = e->disappearance_chance;
7284 j = 0;
7285 requirement_vector_iterate(&e->disappearance_reqs, preq) {
7286 packet.disappearance_reqs[j++] = *preq;
7287 } requirement_vector_iterate_end;
7288 packet.disappearance_reqs_count = j;
7290 packet.visibility_req = e->visibility_req;
7291 packet.buildable = e->buildable;
7292 packet.build_time = e->build_time;
7293 packet.build_time_factor = e->build_time_factor;
7294 packet.removal_time = e->removal_time;
7295 packet.removal_time_factor = e->removal_time_factor;
7296 packet.defense_bonus = e->defense_bonus;
7297 packet.eus = e->eus;
7299 packet.native_to = e->native_to;
7301 packet.flags = e->flags;
7302 packet.hidden_by = e->hidden_by;
7303 packet.conflicts = e->conflicts;
7305 PACKET_STRVEC_COMPUTE(packet.helptext, e->helptext);
7307 lsend_packet_ruleset_extra(dest, &packet);
7308 } extra_type_iterate_end;
7311 /**************************************************************************
7312 Send the base ruleset information (all individual base types) to the
7313 specified connections.
7314 **************************************************************************/
7315 static void send_ruleset_bases(struct conn_list *dest)
7317 extra_type_by_cause_iterate(EC_BASE, pextra) {
7318 struct base_type *b = extra_base_get(pextra);
7319 struct packet_ruleset_base packet;
7321 packet.id = base_number(b);
7323 packet.gui_type = b->gui_type;
7324 packet.border_sq = b->border_sq;
7325 packet.vision_main_sq = b->vision_main_sq;
7326 packet.vision_invis_sq = b->vision_invis_sq;
7328 packet.flags = b->flags;
7330 lsend_packet_ruleset_base(dest, &packet);
7331 } extra_type_by_cause_iterate_end;
7334 /**************************************************************************
7335 Send the road ruleset information (all individual road types) to the
7336 specified connections.
7337 **************************************************************************/
7338 static void send_ruleset_roads(struct conn_list *dest)
7340 struct packet_ruleset_road packet;
7342 extra_type_by_cause_iterate(EC_ROAD, pextra) {
7343 struct road_type *r = extra_road_get(pextra);
7344 int j;
7346 packet.id = road_number(r);
7348 j = 0;
7349 requirement_vector_iterate(&r->first_reqs, preq) {
7350 packet.first_reqs[j++] = *preq;
7351 } requirement_vector_iterate_end;
7352 packet.first_reqs_count = j;
7354 packet.move_cost = r->move_cost;
7355 packet.move_mode = r->move_mode;
7357 output_type_iterate(o) {
7358 packet.tile_incr_const[o] = r->tile_incr_const[o];
7359 packet.tile_incr[o] = r->tile_incr[o];
7360 packet.tile_bonus[o] = r->tile_bonus[o];
7361 } output_type_iterate_end;
7363 packet.compat = r->compat;
7365 packet.integrates = r->integrates;
7366 packet.flags = r->flags;
7368 lsend_packet_ruleset_road(dest, &packet);
7369 } extra_type_by_cause_iterate_end;
7372 /**************************************************************************
7373 Send the goods ruleset information (all individual goods types) to the
7374 specified connections.
7375 **************************************************************************/
7376 static void send_ruleset_goods(struct conn_list *dest)
7378 struct packet_ruleset_goods packet;
7380 goods_type_iterate(g) {
7381 int j;
7383 packet.id = goods_number(g);
7384 sz_strlcpy(packet.name, untranslated_name(&g->name));
7385 sz_strlcpy(packet.rule_name, rule_name_get(&g->name));
7387 j = 0;
7388 requirement_vector_iterate(&g->reqs, preq) {
7389 packet.reqs[j++] = *preq;
7390 } requirement_vector_iterate_end;
7391 packet.reqs_count = j;
7393 packet.from_pct = g->from_pct;
7394 packet.to_pct = g->to_pct;
7395 packet.flags = g->flags;
7397 PACKET_STRVEC_COMPUTE(packet.helptext, g->helptext);
7399 lsend_packet_ruleset_goods(dest, &packet);
7400 } goods_type_iterate_end;
7403 /**************************************************************************
7404 Send the disaster ruleset information (all individual disaster types) to the
7405 specified connections.
7406 **************************************************************************/
7407 static void send_ruleset_disasters(struct conn_list *dest)
7409 struct packet_ruleset_disaster packet;
7411 disaster_type_iterate(d) {
7412 int j;
7414 packet.id = disaster_number(d);
7416 sz_strlcpy(packet.name, untranslated_name(&d->name));
7417 sz_strlcpy(packet.rule_name, rule_name_get(&d->name));
7419 j = 0;
7420 requirement_vector_iterate(&d->reqs, preq) {
7421 packet.reqs[j++] = *preq;
7422 } requirement_vector_iterate_end;
7423 packet.reqs_count = j;
7425 packet.frequency = d->frequency;
7427 packet.effects = d->effects;
7429 lsend_packet_ruleset_disaster(dest, &packet);
7430 } disaster_type_iterate_end;
7433 /**************************************************************************
7434 Send the achievement ruleset information (all individual achievement types)
7435 to the specified connections.
7436 **************************************************************************/
7437 static void send_ruleset_achievements(struct conn_list *dest)
7439 struct packet_ruleset_achievement packet;
7441 achievements_iterate(a) {
7442 packet.id = achievement_number(a);
7444 sz_strlcpy(packet.name, untranslated_name(&a->name));
7445 sz_strlcpy(packet.rule_name, rule_name_get(&a->name));
7447 packet.type = a->type;
7448 packet.unique = a->unique;
7449 packet.value = a->value;
7451 lsend_packet_ruleset_achievement(dest, &packet);
7452 } achievements_iterate_end;
7455 /**************************************************************************
7456 Send action ruleset information to the specified connections.
7457 **************************************************************************/
7458 static void send_ruleset_actions(struct conn_list *dest)
7460 struct packet_ruleset_action packet;
7462 action_iterate(act) {
7463 packet.id = act;
7464 sz_strlcpy(packet.ui_name, action_by_number(act)->ui_name);
7465 packet.quiet = action_by_number(act)->quiet;
7467 packet.act_kind = action_by_number(act)->actor_kind;
7468 packet.tgt_kind = action_by_number(act)->target_kind;
7470 packet.min_distance = action_by_number(act)->min_distance;
7471 packet.max_distance = action_by_number(act)->max_distance;
7472 packet.blocked_by = action_by_number(act)->blocked_by;
7474 lsend_packet_ruleset_action(dest, &packet);
7475 } action_iterate_end;
7478 /**************************************************************************
7479 Send the action enabler ruleset information to the specified connections.
7480 **************************************************************************/
7481 static void send_ruleset_action_enablers(struct conn_list *dest)
7483 int counter;
7484 struct packet_ruleset_action_enabler packet;
7486 action_enablers_iterate(enabler) {
7487 packet.enabled_action = enabler->action;
7489 counter = 0;
7490 requirement_vector_iterate(&enabler->actor_reqs, req) {
7491 packet.actor_reqs[counter++] = *req;
7492 } requirement_vector_iterate_end;
7493 packet.actor_reqs_count = counter;
7495 counter = 0;
7496 requirement_vector_iterate(&enabler->target_reqs, req) {
7497 packet.target_reqs[counter++] = *req;
7498 } requirement_vector_iterate_end;
7499 packet.target_reqs_count = counter;
7501 lsend_packet_ruleset_action_enabler(dest, &packet);
7502 } action_enablers_iterate_end;
7505 /**************************************************************************
7506 Send action auto performer ruleset information to the specified
7507 connections.
7508 **************************************************************************/
7509 static void send_ruleset_action_auto_performers(struct conn_list *dest)
7511 int counter;
7512 int id;
7513 struct packet_ruleset_action_auto packet;
7515 id = 0;
7516 action_auto_perf_iterate(aperf) {
7517 packet.id = id++;
7519 packet.cause = aperf->cause;
7521 counter = 0;
7522 requirement_vector_iterate(&aperf->reqs, req) {
7523 packet.reqs[counter++] = *req;
7524 } requirement_vector_iterate_end;
7525 packet.reqs_count = counter;
7527 for (counter = 0;
7528 /* Can't list more actions than all actions. */
7529 counter < NUM_ACTIONS
7530 /* ACTION_NONE terminates the list. */
7531 && aperf->alternatives[counter] != ACTION_NONE;
7532 counter++) {
7533 packet.alternatives[counter] = aperf->alternatives[counter];
7535 packet.alternatives_count = counter;
7537 lsend_packet_ruleset_action_auto(dest, &packet);
7538 } action_auto_perf_iterate_end;
7541 /**************************************************************************
7542 Send the disaster ruleset information (all individual disaster types) to the
7543 specified connections.
7544 **************************************************************************/
7545 static void send_ruleset_trade_routes(struct conn_list *dest)
7547 struct packet_ruleset_trade packet;
7548 enum trade_route_type type;
7550 for (type = TRT_NATIONAL; type < TRT_LAST; type++) {
7551 struct trade_route_settings *set = trade_route_settings_by_type(type);
7553 packet.id = type;
7554 packet.trade_pct = set->trade_pct;
7555 packet.cancelling = set->cancelling;
7556 packet.bonus_type = set->bonus_type;
7558 lsend_packet_ruleset_trade(dest, &packet);
7562 /**************************************************************************
7563 Send the government ruleset information to the specified connections.
7564 One packet per government type, and for each type one per ruler title.
7565 **************************************************************************/
7566 static void send_ruleset_governments(struct conn_list *dest)
7568 struct packet_ruleset_government gov;
7569 struct packet_ruleset_government_ruler_title title;
7570 int j;
7572 governments_iterate(g) {
7573 /* send one packet_government */
7574 gov.id = government_number(g);
7576 j = 0;
7577 requirement_vector_iterate(&g->reqs, preq) {
7578 gov.reqs[j++] = *preq;
7579 } requirement_vector_iterate_end;
7580 gov.reqs_count = j;
7582 sz_strlcpy(gov.name, untranslated_name(&g->name));
7583 sz_strlcpy(gov.rule_name, rule_name_get(&g->name));
7584 sz_strlcpy(gov.graphic_str, g->graphic_str);
7585 sz_strlcpy(gov.graphic_alt, g->graphic_alt);
7586 PACKET_STRVEC_COMPUTE(gov.helptext, g->helptext);
7588 lsend_packet_ruleset_government(dest, &gov);
7590 /* Send one packet_government_ruler_title per ruler title. */
7591 ruler_titles_iterate(government_ruler_titles(g), pruler_title) {
7592 const struct nation_type *pnation = ruler_title_nation(pruler_title);
7594 title.gov = government_number(g);
7595 title.nation = pnation ? nation_number(pnation) : nation_count();
7596 sz_strlcpy(title.male_title,
7597 ruler_title_male_untranslated_name(pruler_title));
7598 sz_strlcpy(title.female_title,
7599 ruler_title_female_untranslated_name(pruler_title));
7600 lsend_packet_ruleset_government_ruler_title(dest, &title);
7601 } ruler_titles_iterate_end;
7602 } governments_iterate_end;
7605 /**************************************************************************
7606 Send the nations ruleset information (info on each nation) to the
7607 specified connections.
7608 **************************************************************************/
7609 static void send_ruleset_nations(struct conn_list *dest)
7611 struct packet_ruleset_nation_sets sets_packet;
7612 struct packet_ruleset_nation_groups groups_packet;
7613 struct packet_ruleset_nation packet;
7614 int i;
7616 sets_packet.nsets = nation_set_count();
7617 i = 0;
7618 nation_sets_iterate(pset) {
7619 sz_strlcpy(sets_packet.names[i], nation_set_untranslated_name(pset));
7620 sz_strlcpy(sets_packet.rule_names[i], nation_set_rule_name(pset));
7621 sz_strlcpy(sets_packet.descriptions[i], nation_set_description(pset));
7622 i++;
7623 } nation_sets_iterate_end;
7624 lsend_packet_ruleset_nation_sets(dest, &sets_packet);
7626 groups_packet.ngroups = nation_group_count();
7627 i = 0;
7628 nation_groups_iterate(pgroup) {
7629 sz_strlcpy(groups_packet.groups[i],
7630 nation_group_untranslated_name(pgroup));
7631 groups_packet.hidden[i] = pgroup->hidden;
7632 i++;
7633 } nation_groups_iterate_end;
7634 lsend_packet_ruleset_nation_groups(dest, &groups_packet);
7636 nations_iterate(n) {
7637 packet.id = nation_number(n);
7638 if (n->translation_domain == NULL) {
7639 packet.translation_domain[0] = '\0';
7640 } else {
7641 sz_strlcpy(packet.translation_domain, n->translation_domain);
7643 sz_strlcpy(packet.adjective, untranslated_name(&n->adjective));
7644 sz_strlcpy(packet.rule_name, rule_name_get(&n->adjective));
7645 sz_strlcpy(packet.noun_plural, untranslated_name(&n->noun_plural));
7646 sz_strlcpy(packet.graphic_str, n->flag_graphic_str);
7647 sz_strlcpy(packet.graphic_alt, n->flag_graphic_alt);
7649 i = 0;
7650 nation_leader_list_iterate(nation_leaders(n), pleader) {
7651 sz_strlcpy(packet.leader_name[i], nation_leader_name(pleader));
7652 packet.leader_is_male[i] = nation_leader_is_male(pleader);
7653 i++;
7654 } nation_leader_list_iterate_end;
7655 packet.leader_count = i;
7657 packet.style = style_number(n->style);
7658 packet.is_playable = n->is_playable;
7659 packet.barbarian_type = n->barb_type;
7661 sz_strlcpy(packet.legend, n->legend);
7663 i = 0;
7664 nation_set_list_iterate(n->sets, pset) {
7665 packet.sets[i++] = nation_set_number(pset);
7666 } nation_set_list_iterate_end;
7667 packet.nsets = i;
7669 i = 0;
7670 nation_group_list_iterate(n->groups, pgroup) {
7671 packet.groups[i++] = nation_group_number(pgroup);
7672 } nation_group_list_iterate_end;
7673 packet.ngroups = i;
7675 packet.init_government_id = n->init_government
7676 ? government_number(n->init_government) : government_count();
7677 fc_assert(ARRAY_SIZE(packet.init_techs) == ARRAY_SIZE(n->init_techs));
7678 for (i = 0; i < MAX_NUM_TECH_LIST; i++) {
7679 packet.init_techs[i] = n->init_techs[i];
7681 fc_assert(ARRAY_SIZE(packet.init_units) == ARRAY_SIZE(n->init_units));
7682 for (i = 0; i < MAX_NUM_UNIT_LIST; i++) {
7683 const struct unit_type *t = n->init_units[i];
7684 packet.init_units[i] = t ? utype_number(t) : U_LAST;
7686 fc_assert(ARRAY_SIZE(packet.init_buildings)
7687 == ARRAY_SIZE(n->init_buildings));
7688 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
7689 /* Impr_type_id to int */
7690 packet.init_buildings[i] = n->init_buildings[i];
7693 lsend_packet_ruleset_nation(dest, &packet);
7694 } nations_iterate_end;
7696 /* Send initial values of is_pickable */
7697 send_nation_availability(dest, FALSE);
7700 /**************************************************************************
7701 Send the nation style ruleset information (each style) to the specified
7702 connections.
7703 **************************************************************************/
7704 static void send_ruleset_styles(struct conn_list *dest)
7706 struct packet_ruleset_style packet;
7708 styles_iterate(s) {
7709 packet.id = style_index(s);
7710 sz_strlcpy(packet.name, untranslated_name(&s->name));
7711 sz_strlcpy(packet.rule_name, rule_name_get(&s->name));
7713 lsend_packet_ruleset_style(dest, &packet);
7714 } styles_iterate_end;
7717 /**************************************************************************
7718 Send the multiplier ruleset information to the specified
7719 connections.
7720 **************************************************************************/
7721 static void send_ruleset_multipliers(struct conn_list *dest)
7723 char helptext[MAX_LEN_PACKET];
7725 multipliers_iterate(pmul) {
7726 PACKET_STRVEC_COMPUTE(helptext, pmul->helptext);
7728 dlsend_packet_ruleset_multiplier(dest, multiplier_number(pmul),
7729 pmul->start, pmul->stop,
7730 pmul->step, pmul->def,
7731 pmul->offset, pmul->factor,
7732 untranslated_name(&pmul->name),
7733 rule_name_get(&pmul->name),
7734 helptext);
7735 } multipliers_iterate_end;
7738 /**************************************************************************
7739 Send the city-style ruleset information (each style) to the specified
7740 connections.
7741 **************************************************************************/
7742 static void send_ruleset_cities(struct conn_list *dest)
7744 struct packet_ruleset_city city_p;
7745 int k, j;
7747 for (k = 0; k < game.control.styles_count; k++) {
7748 city_p.style_id = k;
7750 j = 0;
7751 requirement_vector_iterate(&city_styles[k].reqs, preq) {
7752 city_p.reqs[j++] = *preq;
7753 } requirement_vector_iterate_end;
7754 city_p.reqs_count = j;
7756 sz_strlcpy(city_p.name, untranslated_name(&city_styles[k].name));
7757 sz_strlcpy(city_p.rule_name, rule_name_get(&city_styles[k].name));
7758 sz_strlcpy(city_p.graphic, city_styles[k].graphic);
7759 sz_strlcpy(city_p.graphic_alt, city_styles[k].graphic_alt);
7760 sz_strlcpy(city_p.citizens_graphic, city_styles[k].citizens_graphic);
7761 sz_strlcpy(city_p.citizens_graphic_alt,
7762 city_styles[k].citizens_graphic_alt);
7764 lsend_packet_ruleset_city(dest, &city_p);
7768 /**************************************************************************
7769 Send the music-style ruleset information (each style) to the specified
7770 connections.
7771 **************************************************************************/
7772 static void send_ruleset_musics(struct conn_list *dest)
7774 struct packet_ruleset_music packet;
7776 music_styles_iterate(pmus) {
7777 int j;
7779 packet.id = pmus->id;
7781 sz_strlcpy(packet.music_peaceful, pmus->music_peaceful);
7782 sz_strlcpy(packet.music_combat, pmus->music_combat);
7784 j = 0;
7785 requirement_vector_iterate(&(pmus->reqs), preq) {
7786 packet.reqs[j++] = *preq;
7787 } requirement_vector_iterate_end;
7788 packet.reqs_count = j;
7790 lsend_packet_ruleset_music(dest, &packet);
7791 } music_styles_iterate_end;
7794 /**************************************************************************
7795 Send information in packet_ruleset_game (miscellaneous rules) to the
7796 specified connections.
7797 **************************************************************************/
7798 static void send_ruleset_game(struct conn_list *dest)
7800 struct packet_ruleset_game misc_p;
7801 int i;
7803 fc_assert_ret(game.veteran != NULL);
7805 /* Per unit veteran system definition. */
7806 misc_p.veteran_levels = game.veteran->levels;
7808 for (i = 0; i < misc_p.veteran_levels; i++) {
7809 const struct veteran_level *vlevel = game.veteran->definitions + i;
7811 sz_strlcpy(misc_p.veteran_name[i], untranslated_name(&vlevel->name));
7812 misc_p.power_fact[i] = vlevel->power_fact;
7813 misc_p.move_bonus[i] = vlevel->move_bonus;
7816 fc_assert(sizeof(misc_p.global_init_techs)
7817 == sizeof(game.rgame.global_init_techs));
7818 fc_assert(ARRAY_SIZE(misc_p.global_init_techs)
7819 == ARRAY_SIZE(game.rgame.global_init_techs));
7820 memcpy(misc_p.global_init_techs, game.rgame.global_init_techs,
7821 sizeof(misc_p.global_init_techs));
7823 fc_assert(ARRAY_SIZE(misc_p.global_init_buildings)
7824 == ARRAY_SIZE(game.rgame.global_init_buildings));
7825 for (i = 0; i < MAX_NUM_BUILDING_LIST; i++) {
7826 /* Impr_type_id to int */
7827 misc_p.global_init_buildings[i] =
7828 game.rgame.global_init_buildings[i];
7831 misc_p.default_specialist = DEFAULT_SPECIALIST;
7833 fc_assert_ret(game.plr_bg_color != NULL);
7835 misc_p.background_red = game.plr_bg_color->r;
7836 misc_p.background_green = game.plr_bg_color->g;
7837 misc_p.background_blue = game.plr_bg_color->b;
7839 lsend_packet_ruleset_game(dest, &misc_p);
7842 /**************************************************************************
7843 Send all team names defined in the ruleset file(s) to the
7844 specified connections.
7845 **************************************************************************/
7846 static void send_ruleset_team_names(struct conn_list *dest)
7848 struct packet_team_name_info team_name_info_p;
7850 team_slots_iterate(tslot) {
7851 const char *name = team_slot_defined_name(tslot);
7853 if (NULL == name) {
7854 /* End of defined names. */
7855 break;
7858 team_name_info_p.team_id = team_slot_index(tslot);
7859 sz_strlcpy(team_name_info_p.team_name, name);
7861 lsend_packet_team_name_info(dest, &team_name_info_p);
7862 } team_slots_iterate_end;
7865 /**************************************************************************
7866 Make it clear to everyone that requested ruleset has not been loaded.
7867 **************************************************************************/
7868 static void notify_ruleset_fallback(const char *msg)
7870 notify_conn(NULL, NULL, E_LOG_FATAL, ftc_warning, "%s", msg);
7873 /**************************************************************************
7874 Loads the rulesets.
7875 **************************************************************************/
7876 bool load_rulesets(const char *restore, bool compat_mode,
7877 bool act, bool buffer_script)
7879 if (load_rulesetdir(game.server.rulesetdir, compat_mode, act, buffer_script)) {
7880 return TRUE;
7883 /* Fallback to previous one. */
7884 if (restore != NULL) {
7885 if (load_rulesetdir(restore, compat_mode, act, buffer_script)) {
7886 sz_strlcpy(game.server.rulesetdir, restore);
7888 notify_ruleset_fallback(_("Ruleset couldn't be loaded. Keeping previous one."));
7890 /* We're in sane state as restoring previous ruleset succeeded,
7891 * but return failure to indicate that this is not what caller
7892 * wanted. */
7893 return FALSE;
7897 /* Fallback to default one, but not if that's what we tried already */
7898 if (strcmp(GAME_DEFAULT_RULESETDIR, game.server.rulesetdir)
7899 && (restore == NULL || strcmp(GAME_DEFAULT_RULESETDIR, restore))) {
7900 if (load_rulesetdir(GAME_DEFAULT_RULESETDIR, FALSE, act, buffer_script)) {
7901 /* We're in sane state as fallback ruleset loading succeeded,
7902 * but return failure to indicate that this is not what caller
7903 * wanted. */
7904 sz_strlcpy(game.server.rulesetdir, GAME_DEFAULT_RULESETDIR);
7906 notify_ruleset_fallback(_("Ruleset couldn't be loaded. Switching to default one."));
7908 return FALSE;
7912 #ifdef FREECIV_WEB
7913 log_normal(_("Cannot load any ruleset. Freeciv-web ruleset is available from "
7914 "https://github.com/freeciv/freeciv-web"));
7915 #endif /* FREECIV_WEB */
7917 /* Cannot load even default ruleset, we're in completely unusable state */
7918 exit(EXIT_FAILURE);
7921 /**************************************************************************
7922 destroy secfile. Handle NULL parameter gracefully.
7923 **************************************************************************/
7924 static void nullcheck_secfile_destroy(struct section_file *file)
7926 if (file != NULL) {
7927 secfile_destroy(file);
7931 /**************************************************************************
7932 Completely deinitialize ruleset system. Server is not in usable
7933 state after this.
7934 **************************************************************************/
7935 void rulesets_deinit(void)
7937 script_server_free();
7938 requirement_vector_free(&reqs_list);
7941 /**************************************************************************
7942 Loads the rulesets from directory.
7943 This may be called more than once and it will free any stale data.
7944 **************************************************************************/
7945 static bool load_rulesetdir(const char *rsdir, bool compat_mode,
7946 bool act, bool buffer_script)
7948 struct section_file *techfile, *unitfile, *buildfile, *govfile, *terrfile;
7949 struct section_file *stylefile, *cityfile, *nationfile, *effectfile, *gamefile;
7950 bool ok = TRUE;
7951 struct rscompat_info compat_info;
7953 log_normal(_("Loading rulesets."));
7955 rscompat_init_info(&compat_info);
7956 compat_info.compat_mode = compat_mode;
7958 game_ruleset_free();
7959 /* Reset the list of available player colors. */
7960 playercolor_free();
7961 playercolor_init();
7962 game_ruleset_init();
7964 if (script_buffer != NULL) {
7965 FC_FREE(script_buffer);
7966 script_buffer = NULL;
7969 server.playable_nations = 0;
7971 techfile = openload_ruleset_file("techs", rsdir);
7972 buildfile = openload_ruleset_file("buildings", rsdir);
7973 govfile = openload_ruleset_file("governments", rsdir);
7974 unitfile = openload_ruleset_file("units", rsdir);
7975 terrfile = openload_ruleset_file("terrain", rsdir);
7976 stylefile = openload_ruleset_file("styles", rsdir);
7977 cityfile = openload_ruleset_file("cities", rsdir);
7978 nationfile = openload_ruleset_file("nations", rsdir);
7979 effectfile = openload_ruleset_file("effects", rsdir);
7980 gamefile = openload_ruleset_file("game", rsdir);
7982 if (techfile == NULL
7983 || buildfile == NULL
7984 || govfile == NULL
7985 || unitfile == NULL
7986 || terrfile == NULL
7987 || stylefile == NULL
7988 || cityfile == NULL
7989 || nationfile == NULL
7990 || effectfile == NULL
7991 || gamefile == NULL) {
7992 ok = FALSE;
7995 if (ok) {
7996 ok = load_game_names(gamefile, &compat_info)
7997 && load_tech_names(techfile, &compat_info)
7998 && load_building_names(buildfile, &compat_info)
7999 && load_government_names(govfile, &compat_info)
8000 && load_unit_names(unitfile, &compat_info)
8001 && load_terrain_names(terrfile, &compat_info)
8002 && load_style_names(stylefile, &compat_info)
8003 && load_nation_names(nationfile, &compat_info);
8006 if (ok) {
8007 ok = rscompat_names(&compat_info);
8010 if (ok) {
8011 ok = load_ruleset_techs(techfile, &compat_info);
8013 if (ok) {
8014 ok = load_ruleset_styles(stylefile, &compat_info);
8016 if (ok) {
8017 ok = load_ruleset_cities(cityfile, &compat_info);
8019 if (ok) {
8020 ok = load_ruleset_governments(govfile, &compat_info);
8022 if (ok) {
8023 /* terrain must precede nations and units */
8024 ok = load_ruleset_terrain(terrfile, &compat_info);
8026 if (ok) {
8027 ok = load_ruleset_units(unitfile, &compat_info);
8029 if (ok) {
8030 ok = load_ruleset_buildings(buildfile, &compat_info);
8032 if (ok) {
8033 ok = load_ruleset_nations(nationfile, &compat_info);
8035 if (ok) {
8036 ok = load_ruleset_effects(effectfile, &compat_info);
8038 if (ok) {
8039 ok = load_ruleset_game(gamefile, act, &compat_info);
8042 if (ok) {
8043 /* Init nations we just loaded. */
8044 update_nations_with_startpos();
8046 /* Needed by role_unit_precalcs(). */
8047 unit_type_action_cache_init();
8049 /* Prepare caches we want to sanity check. */
8050 role_unit_precalcs();
8051 road_integrators_cache_init();
8052 actions_rs_pre_san_gen();
8054 ok = autoadjust_ruleset_data()
8055 && sanity_check_ruleset_data(compat_info.compat_mode);
8058 if (ok) {
8059 /* Only load settings for a sane ruleset */
8060 ok = settings_ruleset(gamefile, "settings", act);
8062 if (ok) {
8063 secfile_check_unused(gamefile);
8067 nullcheck_secfile_destroy(techfile);
8068 nullcheck_secfile_destroy(stylefile);
8069 nullcheck_secfile_destroy(cityfile);
8070 nullcheck_secfile_destroy(govfile);
8071 nullcheck_secfile_destroy(terrfile);
8072 nullcheck_secfile_destroy(unitfile);
8073 nullcheck_secfile_destroy(buildfile);
8074 nullcheck_secfile_destroy(nationfile);
8075 nullcheck_secfile_destroy(effectfile);
8076 nullcheck_secfile_destroy(gamefile);
8078 if (extra_sections) {
8079 free(extra_sections);
8080 extra_sections = NULL;
8082 if (base_sections) {
8083 free(base_sections);
8084 base_sections = NULL;
8086 if (road_sections) {
8087 free(road_sections);
8088 road_sections = NULL;
8090 if (resource_sections) {
8091 free(resource_sections);
8092 resource_sections = NULL;
8094 if (terrain_sections) {
8095 free(terrain_sections);
8096 terrain_sections = NULL;
8099 if (ok) {
8100 rscompat_postprocess(&compat_info);
8103 if (ok) {
8105 char **buffer = buffer_script ? &script_buffer : NULL;
8107 script_server_free();
8109 script_server_init();
8111 ok = openload_script_file("script", rsdir, buffer);
8114 if (ok && !buffer_script) {
8115 ok = openload_script_file("default", rsdir, NULL);
8118 if (ok && act) {
8119 /* Populate remaining caches. */
8120 techs_precalc_data();
8121 improvement_feature_cache_init();
8122 unit_class_iterate(pclass) {
8123 set_unit_class_caches(pclass);
8124 } unit_class_iterate_end;
8125 unit_type_iterate(ptype) {
8126 ptype->unknown_move_cost = utype_unknown_move_cost(ptype);
8127 set_unit_type_caches(ptype);
8128 } unit_type_iterate_end;
8129 city_production_caravan_shields_init();
8131 /* Build advisors unit class cache corresponding to loaded rulesets */
8132 adv_units_ruleset_init();
8133 CALL_FUNC_EACH_AI(units_ruleset_init);
8135 /* We may need to adjust the number of AI players
8136 * if the number of available nations changed. */
8137 (void) aifill(game.info.aifill);
8140 return ok;
8143 /**************************************************************************
8144 Reload the game settings saved in the ruleset file.
8145 **************************************************************************/
8146 bool reload_rulesets_settings(void)
8148 struct section_file *file;
8149 bool ok = TRUE;
8151 file = openload_ruleset_file("game", game.server.rulesetdir);
8152 if (file == NULL) {
8153 ruleset_error(LOG_ERROR, "Could not load game.ruleset:\n%s",
8154 secfile_error());
8155 ok = FALSE;
8157 if (ok) {
8158 settings_ruleset(file, "settings", TRUE);
8159 secfile_destroy(file);
8162 return ok;
8165 /**************************************************************************
8166 Send all ruleset information to the specified connections.
8167 **************************************************************************/
8168 void send_rulesets(struct conn_list *dest)
8170 conn_list_compression_freeze(dest);
8172 /* ruleset_control also indicates to client that ruleset sending starts. */
8173 send_ruleset_control(dest);
8175 send_ruleset_game(dest);
8176 send_ruleset_disasters(dest);
8177 send_ruleset_achievements(dest);
8178 send_ruleset_trade_routes(dest);
8179 send_ruleset_team_names(dest);
8180 send_ruleset_actions(dest);
8181 send_ruleset_action_enablers(dest);
8182 send_ruleset_action_auto_performers(dest);
8183 send_ruleset_tech_classes(dest);
8184 send_ruleset_techs(dest);
8185 send_ruleset_governments(dest);
8186 send_ruleset_unit_classes(dest);
8187 send_ruleset_units(dest);
8188 send_ruleset_specialists(dest);
8189 send_ruleset_extras(dest);
8190 send_ruleset_bases(dest);
8191 send_ruleset_roads(dest);
8192 send_ruleset_resources(dest);
8193 send_ruleset_terrain(dest);
8194 send_ruleset_goods(dest);
8195 send_ruleset_buildings(dest);
8196 send_ruleset_nations(dest);
8197 send_ruleset_styles(dest);
8198 send_ruleset_cities(dest);
8199 send_ruleset_multipliers(dest);
8200 send_ruleset_musics(dest);
8201 send_ruleset_cache(dest);
8203 /* Indicate client that all rulesets have now been sent. */
8204 lsend_packet_rulesets_ready(dest);
8206 /* changed game settings will be send in
8207 * connecthand.c:establish_new_connection() */
8209 conn_list_compression_thaw(dest);